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