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