RIP BOOL. Convert BOOL -> bool. I found a few interesting
[nivanova/samba-autobuild/.git] / source3 / smbd / quotas.c
1 /* 
2    Unix SMB/CIFS implementation.
3    support for quotas
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20
21 /* 
22  * This is one of the most system dependent parts of Samba, and its
23  * done a litle differently. Each system has its own way of doing 
24  * things :-(
25  */
26
27 #include "includes.h"
28
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_QUOTA
31
32 #ifndef HAVE_SYS_QUOTAS
33
34 /* just a quick hack because sysquotas.h is included before linux/quota.h */
35 #ifdef QUOTABLOCK_SIZE
36 #undef QUOTABLOCK_SIZE
37 #endif
38
39 #ifdef WITH_QUOTAS
40
41 #if defined(VXFS_QUOTA)
42
43 /*
44  * In addition to their native filesystems, some systems have Veritas VxFS.
45  * Declare here, define at end: reduces likely "include" interaction problems.
46  *      David Lee <T.D.Lee@durham.ac.uk>
47  */
48 bool disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
49
50 #endif /* VXFS_QUOTA */
51
52 #ifdef LINUX
53
54 #include <sys/types.h>
55 #include <mntent.h>
56
57 /*
58  * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
59  * So we include all the files has *should* be in the system into a large,
60  * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA.
61  */
62
63 #include "samba_linux_quota.h"
64
65 typedef struct _LINUX_SMB_DISK_QUOTA {
66         SMB_BIG_UINT bsize;
67         SMB_BIG_UINT hardlimit; /* In bsize units. */
68         SMB_BIG_UINT softlimit; /* In bsize units. */
69         SMB_BIG_UINT curblocks; /* In bsize units. */
70         SMB_BIG_UINT ihardlimit; /* inode hard limit. */
71         SMB_BIG_UINT isoftlimit; /* inode soft limit. */
72         SMB_BIG_UINT curinodes; /* Current used inodes. */
73 } LINUX_SMB_DISK_QUOTA;
74
75
76 #ifdef HAVE_LINUX_DQBLK_XFS_H
77 #include <linux/dqblk_xfs.h>
78
79 /****************************************************************************
80  Abstract out the XFS Quota Manager quota get call.
81 ****************************************************************************/
82
83 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
84 {
85         struct fs_disk_quota D;
86         int ret;
87
88         ZERO_STRUCT(D);
89
90         ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
91
92         if (ret)
93                 ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
94
95         if (ret)
96                 return ret;
97
98         dp->bsize = (SMB_BIG_UINT)512;
99         dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit;
100         dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit;
101         dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit;
102         dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit;
103         dp->curinodes = (SMB_BIG_UINT)D.d_icount;
104         dp->curblocks = (SMB_BIG_UINT)D.d_bcount;
105
106         return ret;
107 }
108 #else
109 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
110 {
111         DEBUG(0,("XFS quota support not available\n"));
112         errno = ENOSYS;
113         return -1;
114 }
115 #endif
116
117
118 /****************************************************************************
119  Abstract out the old and new Linux quota get calls.
120 ****************************************************************************/
121
122 static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
123 {
124         struct v1_kern_dqblk D;
125         int ret;
126
127         ZERO_STRUCT(D);
128
129         ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
130
131         if (ret && errno != EDQUOT)
132                 ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
133
134         if (ret && errno != EDQUOT)
135                 return ret;
136
137         dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
138         dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
139         dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
140         dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
141         dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
142         dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
143         dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
144
145         return ret;
146 }
147
148 static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
149 {
150         struct v2_kern_dqblk D;
151         int ret;
152
153         ZERO_STRUCT(D);
154
155         ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
156
157         if (ret && errno != EDQUOT)
158                 ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
159
160         if (ret && errno != EDQUOT)
161                 return ret;
162
163         dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
164         dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
165         dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
166         dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
167         dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
168         dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
169         dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize;
170
171         return ret;
172 }
173
174 /****************************************************************************
175  Brand-new generic quota interface.
176 ****************************************************************************/
177
178 static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
179 {
180         struct if_dqblk D;
181         int ret;
182
183         ZERO_STRUCT(D);
184
185         ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
186
187         if (ret && errno != EDQUOT)
188                 ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
189
190         if (ret && errno != EDQUOT)
191                 return ret;
192
193         dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
194         dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
195         dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
196         dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
197         dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
198         dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
199         dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize;
200
201         return ret;
202 }
203
204 /****************************************************************************
205  Try to get the disk space from disk quotas (LINUX version).
206 ****************************************************************************/
207
208 bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
209 {
210         int r;
211         SMB_STRUCT_STAT S;
212         FILE *fp;
213         LINUX_SMB_DISK_QUOTA D;
214         struct mntent *mnt;
215         SMB_DEV_T devno;
216         int found;
217         uid_t euser_id;
218         gid_t egrp_id;
219
220         ZERO_STRUCT(D);
221
222         euser_id = geteuid();
223         egrp_id = getegid();
224
225         /* find the block device file */
226   
227         if ( sys_stat(path, &S) == -1 )
228                 return(False) ;
229
230         devno = S.st_dev ;
231   
232         if ((fp = setmntent(MOUNTED,"r")) == NULL)
233                 return(False) ;
234
235         found = False ;
236   
237         while ((mnt = getmntent(fp))) {
238                 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
239                         continue ;
240
241                 if (S.st_dev == devno) {
242                         found = True ;
243                         break;
244                 }
245         }
246
247         endmntent(fp) ;
248   
249         if (!found)
250                 return(False);
251
252         become_root();
253
254         if (strcmp(mnt->mnt_type, "xfs")==0) {
255                 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
256         } else {
257                 r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
258                 if (r == -1 && errno != EDQUOT) {
259                         r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
260                         if (r == -1 && errno != EDQUOT)
261                                 r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
262                 }
263         }
264
265         unbecome_root();
266
267         /* Use softlimit to determine disk space, except when it has been exceeded */
268         *bsize = D.bsize;
269         if (r == -1) {
270                 if (errno == EDQUOT) {
271                         *dfree =0;
272                         *dsize =D.curblocks;
273                         return (True);
274                 } else {
275                         return(False);
276                 }
277         }
278
279         /* Use softlimit to determine disk space, except when it has been exceeded */
280         if (
281                 (D.softlimit && D.curblocks >= D.softlimit) ||
282                 (D.hardlimit && D.curblocks >= D.hardlimit) ||
283                 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
284                 (D.ihardlimit && D.curinodes>=D.ihardlimit)
285         ) {
286                 *dfree = 0;
287                 *dsize = D.curblocks;
288         } else if (D.softlimit==0 && D.hardlimit==0) {
289                 return(False);
290         } else {
291                 if (D.softlimit == 0)
292                         D.softlimit = D.hardlimit;
293                 *dfree = D.softlimit - D.curblocks;
294                 *dsize = D.softlimit;
295         }
296
297         return (True);
298 }
299
300 #elif defined(CRAY)
301
302 #include <sys/quota.h>
303 #include <mntent.h>
304
305 /****************************************************************************
306 try to get the disk space from disk quotas (CRAY VERSION)
307 ****************************************************************************/
308
309 bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
310 {
311   struct mntent *mnt;
312   FILE *fd;
313   SMB_STRUCT_STAT sbuf;
314   SMB_DEV_T devno ;
315   static SMB_DEV_T devno_cached = 0 ;
316   static pstring name;
317   struct q_request request ;
318   struct qf_header header ;
319   static int quota_default = 0 ;
320   int found ;
321   
322   if ( sys_stat(path,&sbuf) == -1 )
323     return(False) ;
324   
325   devno = sbuf.st_dev ;
326   
327   if ( devno != devno_cached ) {
328     
329     devno_cached = devno ;
330     
331     if ((fd = setmntent(KMTAB)) == NULL)
332       return(False) ;
333     
334     found = False ;
335     
336     while ((mnt = getmntent(fd)) != NULL) {
337       
338       if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
339         continue ;
340       
341       if (sbuf.st_dev == devno) {
342         
343         found = True ;
344         break ;
345         
346       }
347       
348     }
349     
350     pstrcpy(name,mnt->mnt_dir) ;
351     endmntent(fd) ;
352     
353     if ( ! found )
354       return(False) ;
355   }
356   
357   request.qf_magic = QF_MAGIC ;
358   request.qf_entry.id = geteuid() ;
359   
360   if (quotactl(name, Q_GETQUOTA, &request) == -1)
361     return(False) ;
362   
363   if ( ! request.user )
364     return(False) ;
365   
366   if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
367     
368     if ( ! quota_default ) {
369       
370       if ( quotactl(name, Q_GETHEADER, &header) == -1 )
371         return(False) ;
372       else
373         quota_default = header.user_h.def_fq ;
374     }
375     
376     *dfree = quota_default ;
377     
378   }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
379     
380     *dfree = 0 ;
381     
382   }else{
383     
384     *dfree = request.qf_entry.user_q.f_quota ;
385     
386   }
387   
388   *dsize = request.qf_entry.user_q.f_use ;
389   
390   if ( *dfree < *dsize )
391     *dfree = 0 ;
392   else
393     *dfree -= *dsize ;
394   
395   *bsize = 4096 ;  /* Cray blocksize */
396   
397   return(True) ;
398   
399 }
400
401
402 #elif defined(SUNOS5) || defined(SUNOS4)
403
404 #include <fcntl.h>
405 #include <sys/param.h>
406 #if defined(SUNOS5)
407 #include <sys/fs/ufs_quota.h>
408 #include <sys/mnttab.h>
409 #include <sys/mntent.h>
410 #else /* defined(SUNOS4) */
411 #include <ufs/quota.h>
412 #include <mntent.h>
413 #endif
414
415 #if defined(SUNOS5)
416
417 /****************************************************************************
418  Allows querying of remote hosts for quotas on NFS mounted shares.
419  Supports normal NFS and AMD mounts.
420  Alan Romeril <a.romeril@ic.ac.uk> July 2K.
421 ****************************************************************************/
422
423 #include <rpc/rpc.h>
424 #include <rpc/types.h>
425 #include <rpcsvc/rquota.h>
426 #include <rpc/nettype.h>
427 #include <rpc/xdr.h>
428
429 static int quotastat;
430
431 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
432 {
433         if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
434                 return(0);
435         if (!xdr_int(xdrsp, &args->gqa_uid))
436                 return(0);
437         return (1);
438 }
439
440 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
441 {
442         if (!xdr_int(xdrsp, &quotastat)) {
443                 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
444                 return 0;
445         }
446         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
447                 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
448                 return 0;
449         }
450         if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
451                 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
452                 return 0;
453         }
454         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
455                 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
456                 return 0;
457         }
458         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
459                 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
460                 return 0;
461         }
462         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
463                 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
464                 return 0;
465         }
466         return (1);
467 }
468
469 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */ 
470 static bool nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
471 {
472         uid_t uid = euser_id;
473         struct dqblk D;
474         char *mnttype = nfspath;
475         CLIENT *clnt;
476         struct getquota_rslt gqr;
477         struct getquota_args args;
478         char *cutstr, *pathname, *host, *testpath;
479         int len;
480         static struct timeval timeout = {2,0};
481         enum clnt_stat clnt_stat;
482         bool ret = True;
483
484         *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
485
486         len=strcspn(mnttype, ":");
487         pathname=strstr(mnttype, ":");
488         cutstr = (char *) SMB_MALLOC(len+1);
489         if (!cutstr)
490                 return False;
491
492         memset(cutstr, '\0', len+1);
493         host = strncat(cutstr,mnttype, sizeof(char) * len );
494         DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
495         DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
496         testpath=strchr_m(mnttype, ':');
497         args.gqa_pathp = testpath+1;
498         args.gqa_uid = uid;
499
500         DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
501
502         if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
503                 ret = False;
504                 goto out;
505         }
506
507         clnt->cl_auth = authunix_create_default();
508         DEBUG(9,("nfs_quotas: auth_success\n"));
509
510         clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
511
512         if (clnt_stat != RPC_SUCCESS) {
513                 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
514                 ret = False;
515                 goto out;
516         }
517
518         /* 
519          * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
520          * no quota set, and 3 if no permission to get the quota.  If 0 or 3 return
521          * something sensible.
522          */   
523
524         switch ( quotastat ) {
525         case 0:
526                 DEBUG(9,("nfs_quotas: Remote Quotas Failed!  Error \"%i\" \n", quotastat ));
527                 ret = False;
528                 goto out;
529
530         case 1:
531                 DEBUG(9,("nfs_quotas: Good quota data\n"));
532                 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
533                 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
534                 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
535                 break;
536
537         case 2:
538         case 3:
539                 D.dqb_bsoftlimit = 1;
540                 D.dqb_curblocks = 1;
541                 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
542                 break;
543
544         default:
545                 DEBUG(9,("nfs_quotas: Remote Quotas Questionable!  Error \"%i\" \n", quotastat ));
546                 break;
547         }
548
549         DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
550                         quotastat,
551                         gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
552                         gqr.getquota_rslt_u.gqr_rquota.rq_active,
553                         gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
554                         gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
555                         gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
556
557         *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
558         *dsize = D.dqb_bsoftlimit;
559
560         if (D.dqb_curblocks == D.dqb_curblocks == 1)
561                 *bsize = 512;
562
563         if (D.dqb_curblocks > D.dqb_bsoftlimit) {
564                 *dfree = 0;
565                 *dsize = D.dqb_curblocks;
566         } else
567                 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
568
569   out:
570
571         if (clnt) {
572                 if (clnt->cl_auth)
573                         auth_destroy(clnt->cl_auth);
574                 clnt_destroy(clnt);
575         }
576
577         DEBUG(5,("nfs_quotas: For path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
578
579         SAFE_FREE(cutstr);
580         DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
581         return ret;
582 }
583 #endif
584
585 /****************************************************************************
586 try to get the disk space from disk quotas (SunOS & Solaris2 version)
587 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
588 ****************************************************************************/
589
590 bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
591 {
592         uid_t euser_id;
593         int ret;
594         struct dqblk D;
595 #if defined(SUNOS5)
596         struct quotctl command;
597         int file;
598         static struct mnttab mnt;
599         static pstring name;
600 #else /* SunOS4 */
601         struct mntent *mnt;
602         static pstring name;
603 #endif
604         FILE *fd;
605         SMB_STRUCT_STAT sbuf;
606         SMB_DEV_T devno ;
607         static SMB_DEV_T devno_cached = 0 ;
608         static int found ;
609
610         euser_id = geteuid();
611   
612         if ( sys_stat(path,&sbuf) == -1 )
613                 return(False) ;
614   
615         devno = sbuf.st_dev ;
616         DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
617                 path, (unsigned int)devno));
618         if ( devno != devno_cached ) {
619                 devno_cached = devno ;
620 #if defined(SUNOS5)
621                 if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
622                         return(False) ;
623     
624                 found = False ;
625
626                 while (getmntent(fd, &mnt) == 0) {
627                         if (sys_stat(mnt.mnt_mountp, &sbuf) == -1)
628                                 continue;
629
630                         DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
631                                 mnt.mnt_mountp, (unsigned int)devno));
632
633                         /* quotas are only on vxfs, UFS or NFS */
634                         if ( (sbuf.st_dev == devno) && (
635                                 strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
636                                 strcmp( mnt.mnt_fstype, "nfs" ) == 0    ||
637                                 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) { 
638                                         found = True ;
639                                         break;
640                         }
641                 }
642     
643                 pstrcpy(name,mnt.mnt_mountp) ;
644                 pstrcat(name,"/quotas") ;
645                 fclose(fd) ;
646 #else /* SunOS4 */
647                 if ((fd = setmntent(MOUNTED, "r")) == NULL)
648                         return(False) ;
649     
650                 found = False ;
651                 while ((mnt = getmntent(fd)) != NULL) {
652                         if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
653                                 continue ;
654                         DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev));
655                         if (sbuf.st_dev == devno) {
656                                 found = True ;
657                                 break;
658                         }
659                 }
660     
661                 pstrcpy(name,mnt->mnt_fsname) ;
662                 endmntent(fd) ;
663 #endif
664         }
665
666         if ( ! found )
667                 return(False) ;
668
669         become_root();
670
671 #if defined(SUNOS5)
672         if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) {
673                 bool retval;
674                 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt.mnt_special));
675                 retval = nfs_quotas(mnt.mnt_special, euser_id, bsize, dfree, dsize);
676                 unbecome_root();
677                 return retval;
678         }
679
680         DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
681         if((file=sys_open(name, O_RDONLY,0))<0) {
682                 unbecome_root();
683                 return(False);
684         }
685         command.op = Q_GETQUOTA;
686         command.uid = euser_id;
687         command.addr = (caddr_t) &D;
688         ret = ioctl(file, Q_QUOTACTL, &command);
689         close(file);
690 #else
691         DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
692         ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
693 #endif
694
695         unbecome_root();
696
697         if (ret < 0) {
698                 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
699
700 #if defined(SUNOS5) && defined(VXFS_QUOTA)
701                 /* If normal quotactl() fails, try vxfs private calls */
702                 set_effective_uid(euser_id);
703                 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
704                 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
705                         bool retval;
706                         retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
707                         return(retval);
708                 }
709 #else
710                 return(False);
711 #endif
712         }
713
714         /* If softlimit is zero, set it equal to hardlimit.
715          */
716   
717         if (D.dqb_bsoftlimit==0)
718                 D.dqb_bsoftlimit = D.dqb_bhardlimit;
719
720         /* Use softlimit to determine disk space. A user exceeding the quota is told
721          * that there's no space left. Writes might actually work for a bit if the
722          * hardlimit is set higher than softlimit. Effectively the disk becomes
723          * made of rubber latex and begins to expand to accommodate the user :-)
724          */
725
726         if (D.dqb_bsoftlimit==0)
727                 return(False);
728         *bsize = DEV_BSIZE;
729         *dsize = D.dqb_bsoftlimit;
730
731         if (D.dqb_curblocks > D.dqb_bsoftlimit) {
732                 *dfree = 0;
733                 *dsize = D.dqb_curblocks;
734         } else
735                 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
736       
737         DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",
738                 path,(double)*bsize,(double)*dfree,(double)*dsize));
739
740         return(True);
741 }
742
743
744 #elif defined(OSF1)
745 #include <ufs/quota.h>
746
747 /****************************************************************************
748 try to get the disk space from disk quotas - OSF1 version
749 ****************************************************************************/
750
751 bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
752 {
753   int r, save_errno;
754   struct dqblk D;
755   SMB_STRUCT_STAT S;
756   uid_t euser_id;
757
758   /*
759    * This code presumes that OSF1 will only
760    * give out quota info when the real uid 
761    * matches the effective uid. JRA.
762    */
763   euser_id = geteuid();
764   save_re_uid();
765   if (set_re_uid() != 0) return False;
766
767   r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
768   if (r) {
769      save_errno = errno;
770   }
771
772   restore_re_uid();
773
774   *bsize = DEV_BSIZE;
775
776   if (r)
777   {
778       if (save_errno == EDQUOT)   /* disk quota exceeded */
779       {
780          *dfree = 0;
781          *dsize = D.dqb_curblocks;
782          return (True);
783       }
784       else
785          return (False);  
786   }
787
788   /* If softlimit is zero, set it equal to hardlimit.
789    */
790
791   if (D.dqb_bsoftlimit==0)
792     D.dqb_bsoftlimit = D.dqb_bhardlimit;
793
794   /* Use softlimit to determine disk space, except when it has been exceeded */
795
796   if (D.dqb_bsoftlimit==0)
797     return(False);
798
799   if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
800     *dfree = 0;
801     *dsize = D.dqb_curblocks;
802   } else {
803     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
804     *dsize = D.dqb_bsoftlimit;
805   }
806   return (True);
807 }
808
809 #elif defined (IRIX6)
810 /****************************************************************************
811 try to get the disk space from disk quotas (IRIX 6.2 version)
812 ****************************************************************************/
813
814 #include <sys/quota.h>
815 #include <mntent.h>
816
817 bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
818 {
819   uid_t euser_id;
820   int r;
821   struct dqblk D;
822   struct fs_disk_quota        F;
823   SMB_STRUCT_STAT S;
824   FILE *fp;
825   struct mntent *mnt;
826   SMB_DEV_T devno;
827   int found;
828   
829   /* find the block device file */
830   
831   if ( sys_stat(path, &S) == -1 ) {
832     return(False) ;
833   }
834
835   devno = S.st_dev ;
836   
837   fp = setmntent(MOUNTED,"r");
838   found = False ;
839   
840   while ((mnt = getmntent(fp))) {
841     if ( sys_stat(mnt->mnt_dir,&S) == -1 )
842       continue ;
843     if (S.st_dev == devno) {
844       found = True ;
845       break ;
846     }
847   }
848   endmntent(fp) ;
849   
850   if (!found) {
851     return(False);
852   }
853
854   euser_id=geteuid();
855   become_root();
856
857   /* Use softlimit to determine disk space, except when it has been exceeded */
858
859   *bsize = 512;
860
861   if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
862   {
863     r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
864
865     unbecome_root();
866
867     if (r==-1)
868       return(False);
869         
870     /* Use softlimit to determine disk space, except when it has been exceeded */
871     if (
872         (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
873         (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
874         (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
875         (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
876        )
877     {
878       *dfree = 0;
879       *dsize = D.dqb_curblocks;
880     }
881     else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
882     {
883       return(False);
884     }
885     else 
886     {
887       *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
888       *dsize = D.dqb_bsoftlimit;
889     }
890
891   }
892   else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
893   {
894     r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
895
896     unbecome_root();
897
898     if (r==-1)
899     {
900       DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
901       return(False);
902     }
903         
904     /* No quota for this user. */
905     if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
906     {
907       return(False);
908     }
909
910     /* Use softlimit to determine disk space, except when it has been exceeded */
911     if (
912         (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
913         (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
914         (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
915         (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
916        )
917     {
918       *dfree = 0;
919       *dsize = F.d_bcount;
920     }
921     else 
922     {
923       *dfree = (F.d_blk_softlimit - F.d_bcount);
924       *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
925     }
926
927   }
928   else
929   {
930           unbecome_root();
931           return(False);
932   }
933
934   return (True);
935
936 }
937
938 #else
939
940 #if    defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
941 #include <ufs/ufs/quota.h>
942 #include <machine/param.h>
943 #elif         AIX
944 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
945 #include <jfs/quota.h>
946 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
947 #define dqb_curfiles dqb_curinodes
948 #define dqb_fhardlimit dqb_ihardlimit
949 #define dqb_fsoftlimit dqb_isoftlimit
950 #ifdef _AIXVERSION_530 
951 #include <sys/statfs.h>
952 #include <sys/vmount.h>
953 #endif /* AIX 5.3 */
954 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
955 #include <sys/quota.h>
956 #include <devnm.h>
957 #endif
958
959 #if defined(__FreeBSD__) || defined(__DragonFly__)
960
961 #include <rpc/rpc.h>
962 #include <rpc/types.h>
963 #include <rpcsvc/rquota.h>
964 #ifdef HAVE_RPC_NETTYPE_H
965 #include <rpc/nettype.h>
966 #endif
967 #include <rpc/xdr.h>
968
969 static int quotastat;
970
971 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
972 {
973         if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
974                 return(0);
975         if (!xdr_int(xdrsp, &args->gqa_uid))
976                 return(0);
977         return (1);
978 }
979
980 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
981 {
982         if (!xdr_int(xdrsp, &quotastat)) {
983                 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
984                 return 0;
985         }
986         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
987                 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
988                 return 0;
989         }
990         if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
991                 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
992                 return 0;
993         }
994         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
995                 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
996                 return 0;
997         }
998         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
999                 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
1000                 return 0;
1001         }
1002         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
1003                 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
1004                 return 0;
1005         }
1006         return (1);
1007 }
1008
1009 /* Works on FreeBSD, too. :-) */
1010 static bool nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1011 {
1012         uid_t uid = euser_id;
1013         struct dqblk D;
1014         char *mnttype = nfspath;
1015         CLIENT *clnt;
1016         struct getquota_rslt gqr;
1017         struct getquota_args args;
1018         char *cutstr, *pathname, *host, *testpath;
1019         int len;
1020         static struct timeval timeout = {2,0};
1021         enum clnt_stat clnt_stat;
1022         bool ret = True;
1023
1024         *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
1025
1026         len=strcspn(mnttype, ":");
1027         pathname=strstr(mnttype, ":");
1028         cutstr = (char *) SMB_MALLOC(len+1);
1029         if (!cutstr)
1030                 return False;
1031
1032         memset(cutstr, '\0', len+1);
1033         host = strncat(cutstr,mnttype, sizeof(char) * len );
1034         DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1035         DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1036         testpath=strchr_m(mnttype, ':');
1037         args.gqa_pathp = testpath+1;
1038         args.gqa_uid = uid;
1039
1040         DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1041
1042         if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1043                 ret = False;
1044                 goto out;
1045         }
1046
1047         clnt->cl_auth = authunix_create_default();
1048         DEBUG(9,("nfs_quotas: auth_success\n"));
1049
1050         clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, (const xdrproc_t) my_xdr_getquota_args, (caddr_t)&args, (const xdrproc_t) my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
1051
1052         if (clnt_stat != RPC_SUCCESS) {
1053                 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1054                 ret = False;
1055                 goto out;
1056         }
1057
1058         /* 
1059          * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1060          * no quota set, and 3 if no permission to get the quota.  If 0 or 3 return
1061          * something sensible.
1062          */   
1063
1064         switch ( quotastat ) {
1065         case 0:
1066                 DEBUG(9,("nfs_quotas: Remote Quotas Failed!  Error \"%i\" \n", quotastat ));
1067                 ret = False;
1068                 goto out;
1069
1070         case 1:
1071                 DEBUG(9,("nfs_quotas: Good quota data\n"));
1072                 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1073                 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1074                 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1075                 break;
1076
1077         case 2:
1078         case 3:
1079                 D.dqb_bsoftlimit = 1;
1080                 D.dqb_curblocks = 1;
1081                 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
1082                 break;
1083
1084         default:
1085                 DEBUG(9,("nfs_quotas: Remote Quotas Questionable!  Error \"%i\" \n", quotastat ));
1086                 break;
1087         }
1088
1089         DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
1090                         quotastat,
1091                         gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1092                         gqr.getquota_rslt_u.gqr_rquota.rq_active,
1093                         gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1094                         gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1095                         gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1096
1097         if (D.dqb_bsoftlimit == 0)
1098                 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1099         if (D.dqb_bsoftlimit == 0)
1100                 return False;
1101
1102         *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1103         *dsize = D.dqb_bsoftlimit;
1104
1105         if (D.dqb_curblocks == D.dqb_curblocks == 1)
1106                 *bsize = DEV_BSIZE;
1107
1108         if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1109                 *dfree = 0;
1110                 *dsize = D.dqb_curblocks;
1111         } else
1112                 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1113
1114   out:
1115
1116         if (clnt) {
1117                 if (clnt->cl_auth)
1118                         auth_destroy(clnt->cl_auth);
1119                 clnt_destroy(clnt);
1120         }
1121
1122         DEBUG(5,("nfs_quotas: For path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1123
1124         SAFE_FREE(cutstr);
1125         DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1126         return ret;
1127 }
1128
1129 #endif
1130
1131 /****************************************************************************
1132 try to get the disk space from disk quotas - default version
1133 ****************************************************************************/
1134
1135 bool disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1136 {
1137   int r;
1138   struct dqblk D;
1139   uid_t euser_id;
1140 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1141   char dev_disk[256];
1142   SMB_STRUCT_STAT S;
1143
1144   /* find the block device file */
1145
1146 #ifdef HPUX
1147   /* Need to set the cache flag to 1 for HPUX. Seems
1148    * to have a significant performance boost when
1149    * lstat calls on /dev access this function.
1150    */
1151   if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0))
1152 #else
1153   if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) 
1154         return (False);
1155 #endif /* ifdef HPUX */
1156
1157 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1158
1159   euser_id = geteuid();
1160
1161 #ifdef HPUX
1162   /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1163   save_re_uid();
1164   if (set_re_uid() != 0) return False;
1165   
1166   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1167
1168   restore_re_uid();
1169 #else 
1170 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1171   {
1172     /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1173     gid_t egrp_id;
1174 #if defined(__FreeBSD__) || defined(__DragonFly__)
1175     SMB_DEV_T devno;
1176     struct statfs *mnts;
1177     SMB_STRUCT_STAT st;
1178     int mntsize, i;
1179     
1180     if (sys_stat(path,&st) < 0)
1181         return False;
1182     devno = st.st_dev;
1183
1184     mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1185     if (mntsize <= 0)
1186         return False;
1187
1188     for (i = 0; i < mntsize; i++) {
1189         if (sys_stat(mnts[i].f_mntonname,&st) < 0)
1190             return False;
1191         if (st.st_dev == devno)
1192             break;
1193     }
1194     if (i == mntsize)
1195         return False;
1196 #endif
1197     
1198     become_root();
1199
1200 #if defined(__FreeBSD__) || defined(__DragonFly__)
1201     if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1202         bool retval;
1203         retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1204         unbecome_root();
1205         return retval;
1206     }
1207 #endif
1208
1209     egrp_id = getegid();
1210     r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1211
1212     /* As FreeBSD has group quotas, if getting the user
1213        quota fails, try getting the group instead. */
1214     if (r) {
1215             r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1216     }
1217
1218     unbecome_root();
1219   }
1220 #elif defined(AIX)
1221   /* AIX has both USER and GROUP quotas: 
1222      Get the USER quota (ohnielse@fysik.dtu.dk) */
1223 #ifdef _AIXVERSION_530
1224   {
1225     struct statfs statbuf;
1226     quota64_t user_quota;
1227     if (statfs(path,&statbuf) != 0)
1228       return False;
1229     if(statbuf.f_vfstype == MNT_J2)
1230     {
1231     /* For some reason we need to be root for jfs2 */
1232       become_root();
1233       r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
1234       unbecome_root();
1235     /* Copy results to old struct to let the following code work as before */
1236       D.dqb_curblocks  = user_quota.bused;
1237       D.dqb_bsoftlimit = user_quota.bsoft;
1238       D.dqb_bhardlimit = user_quota.bhard;
1239       D.dqb_curfiles   = user_quota.iused;
1240       D.dqb_fsoftlimit = user_quota.isoft;
1241       D.dqb_fhardlimit = user_quota.ihard;
1242     }
1243     else if(statbuf.f_vfstype == MNT_JFS)
1244     {
1245 #endif /* AIX 5.3 */
1246   save_re_uid();
1247   if (set_re_uid() != 0) 
1248     return False;
1249   r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1250   restore_re_uid();
1251 #ifdef _AIXVERSION_530
1252     }
1253     else
1254       r = 1; /* Fail for other FS-types */
1255   }
1256 #endif /* AIX 5.3 */
1257 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1258   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1259 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1260 #endif /* HPUX */
1261
1262   /* Use softlimit to determine disk space, except when it has been exceeded */
1263 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1264   *bsize = DEV_BSIZE;
1265 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1266   *bsize = 1024;
1267 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1268
1269   if (r)
1270     {
1271       if (errno == EDQUOT) 
1272         {
1273           *dfree =0;
1274           *dsize =D.dqb_curblocks;
1275           return (True);
1276         }
1277       else return(False);
1278     }
1279
1280   /* If softlimit is zero, set it equal to hardlimit.
1281    */
1282
1283   if (D.dqb_bsoftlimit==0)
1284     D.dqb_bsoftlimit = D.dqb_bhardlimit;
1285
1286   if (D.dqb_bsoftlimit==0)
1287     return(False);
1288   /* Use softlimit to determine disk space, except when it has been exceeded */
1289   if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1290 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1291 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1292 #endif
1293     ) {
1294       *dfree = 0;
1295       *dsize = D.dqb_curblocks;
1296     }
1297   else {
1298     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1299     *dsize = D.dqb_bsoftlimit;
1300   }
1301   return (True);
1302 }
1303
1304 #endif
1305
1306 #if defined(VXFS_QUOTA)
1307
1308 /****************************************************************************
1309 Try to get the disk space from Veritas disk quotas.
1310     David Lee <T.D.Lee@durham.ac.uk> August 1999.
1311
1312 Background assumptions:
1313     Potentially under many Operating Systems.  Initially Solaris 2.
1314
1315     My guess is that Veritas is largely, though not entirely,
1316     independent of OS.  So I have separated it out.
1317
1318     There may be some details.  For example, OS-specific "include" files.
1319
1320     It is understood that HPUX 10 somehow gets Veritas quotas without
1321     any special effort; if so, this routine need not be compiled in.
1322         Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1323
1324 Warning:
1325     It is understood that Veritas do not publicly support this ioctl interface.
1326     Rather their preference would be for the user (us) to call the native
1327     OS and then for the OS itself to call through to the VxFS filesystem.
1328     Presumably HPUX 10, see above, does this.
1329
1330 Hints for porting:
1331     Add your OS to "IFLIST" below.
1332     Get it to compile successfully:
1333         Almost certainly "include"s require attention: see SUNOS5.
1334     In the main code above, arrange for it to be called: see SUNOS5.
1335     Test!
1336     
1337 ****************************************************************************/
1338
1339 /* "IFLIST"
1340  * This "if" is a list of ports:
1341  *      if defined(OS1) || defined(OS2) || ...
1342  */
1343 #if defined(SUNOS5)
1344
1345 #if defined(SUNOS5)
1346 #include <sys/fs/vx_solaris.h>
1347 #endif
1348 #include <sys/fs/vx_machdep.h>
1349 #include <sys/fs/vx_layout.h>
1350 #include <sys/fs/vx_quota.h>
1351 #include <sys/fs/vx_aioctl.h>
1352 #include <sys/fs/vx_ioctl.h>
1353
1354 bool disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1355 {
1356   uid_t user_id, euser_id;
1357   int ret;
1358   struct vx_dqblk D;
1359   struct vx_quotctl quotabuf;
1360   struct vx_genioctl genbuf;
1361   pstring qfname;
1362   int file;
1363
1364   /*
1365    * "name" may or may not include a trailing "/quotas".
1366    * Arranging consistency of calling here in "quotas.c" may not be easy and
1367    * it might be easier to examine and adjust it here.
1368    * Fortunately, VxFS seems not to mind at present.
1369    */
1370   pstrcpy(qfname, name) ;
1371   /* pstrcat(qfname, "/quotas") ; */    /* possibly examine and adjust "name" */
1372
1373   euser_id = geteuid();
1374   set_effective_uid(0);
1375
1376   DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1377   if((file=sys_open(qfname, O_RDONLY,0))<0) {
1378     set_effective_uid(euser_id);
1379     return(False);
1380   }
1381   genbuf.ioc_cmd = VX_QUOTACTL;
1382   genbuf.ioc_up = (void *) &quotabuf;
1383
1384   quotabuf.cmd = VX_GETQUOTA;
1385   quotabuf.uid = euser_id;
1386   quotabuf.addr = (caddr_t) &D;
1387   ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1388   close(file);
1389
1390   set_effective_uid(euser_id);
1391
1392   if (ret < 0) {
1393     DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1394     return(False);
1395   }
1396
1397   /* If softlimit is zero, set it equal to hardlimit.
1398    */
1399
1400   if (D.dqb_bsoftlimit==0)
1401     D.dqb_bsoftlimit = D.dqb_bhardlimit;
1402
1403   /* Use softlimit to determine disk space. A user exceeding the quota is told
1404    * that there's no space left. Writes might actually work for a bit if the
1405    * hardlimit is set higher than softlimit. Effectively the disk becomes
1406    * made of rubber latex and begins to expand to accommodate the user :-)
1407    */
1408   DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1409          path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1410          D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1411
1412   if (D.dqb_bsoftlimit==0)
1413     return(False);
1414   *bsize = DEV_BSIZE;
1415   *dsize = D.dqb_bsoftlimit;
1416
1417   if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1418      *dfree = 0;
1419      *dsize = D.dqb_curblocks;
1420   } else
1421     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1422       
1423   DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",
1424          path,(double)*bsize,(double)*dfree,(double)*dsize));
1425
1426   return(True);
1427 }
1428
1429 #endif /* SUNOS5 || ... */
1430
1431 #endif /* VXFS_QUOTA */
1432
1433 #else /* WITH_QUOTAS */
1434
1435 bool disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1436 {
1437   (*bsize) = 512; /* This value should be ignored */
1438
1439   /* And just to be sure we set some values that hopefully */
1440   /* will be larger that any possible real-world value     */
1441   (*dfree) = (SMB_BIG_UINT)-1;
1442   (*dsize) = (SMB_BIG_UINT)-1;
1443
1444   /* As we have select not to use quotas, allways fail */
1445   return False;
1446 }
1447 #endif /* WITH_QUOTAS */
1448
1449 #else /* HAVE_SYS_QUOTAS */
1450 /* wrapper to the new sys_quota interface 
1451    this file should be removed later
1452    */
1453 bool disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1454 {
1455         int r;
1456         SMB_DISK_QUOTA D;
1457         unid_t id;
1458
1459         id.uid = geteuid();
1460
1461         ZERO_STRUCT(D);
1462         r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1463
1464         /* Use softlimit to determine disk space, except when it has been exceeded */
1465         *bsize = D.bsize;
1466         if (r == -1) {
1467                 if (errno == EDQUOT) {
1468                         *dfree =0;
1469                         *dsize =D.curblocks;
1470                         return (True);
1471                 } else {
1472                         goto try_group_quota;
1473                 }
1474         }
1475
1476         /* Use softlimit to determine disk space, except when it has been exceeded */
1477         if (
1478                 (D.softlimit && D.curblocks >= D.softlimit) ||
1479                 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1480                 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1481                 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1482         ) {
1483                 *dfree = 0;
1484                 *dsize = D.curblocks;
1485         } else if (D.softlimit==0 && D.hardlimit==0) {
1486                 goto try_group_quota;
1487         } else {
1488                 if (D.softlimit == 0)
1489                         D.softlimit = D.hardlimit;
1490                 *dfree = D.softlimit - D.curblocks;
1491                 *dsize = D.softlimit;
1492         }
1493
1494         return True;
1495         
1496 try_group_quota:
1497         id.gid = getegid();
1498
1499         ZERO_STRUCT(D);
1500         r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1501
1502         /* Use softlimit to determine disk space, except when it has been exceeded */
1503         *bsize = D.bsize;
1504         if (r == -1) {
1505                 if (errno == EDQUOT) {
1506                         *dfree =0;
1507                         *dsize =D.curblocks;
1508                         return (True);
1509                 } else {
1510                         return False;
1511                 }
1512         }
1513
1514         /* Use softlimit to determine disk space, except when it has been exceeded */
1515         if (
1516                 (D.softlimit && D.curblocks >= D.softlimit) ||
1517                 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1518                 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1519                 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1520         ) {
1521                 *dfree = 0;
1522                 *dsize = D.curblocks;
1523         } else if (D.softlimit==0 && D.hardlimit==0) {
1524                 return False;
1525         } else {
1526                 if (D.softlimit == 0)
1527                         D.softlimit = D.hardlimit;
1528                 *dfree = D.softlimit - D.curblocks;
1529                 *dsize = D.softlimit;
1530         }
1531
1532         return (True);
1533 }
1534 #endif /* HAVE_SYS_QUOTAS */