Initial import
[samba] / 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         save_re_uid();
242         set_effective_uid(0);  
243
244         if (strcmp(mnt->mnt_type, "xfs")==0) {
245                 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
246         } else {
247                 r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
248                 if (r == -1 && errno != EDQUOT) {
249                         r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
250                         if (r == -1 && errno != EDQUOT)
251                                 r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
252                 }
253         }
254
255         restore_re_uid();
256
257         /* Use softlimit to determine disk space, except when it has been exceeded */
258         *bsize = D.bsize;
259         if (r == -1) {
260                 if (errno == EDQUOT) {
261                         *dfree =0;
262                         *dsize =D.curblocks;
263                         return (True);
264                 } else {
265                         return(False);
266                 }
267         }
268
269         /* Use softlimit to determine disk space, except when it has been exceeded */
270         if (
271                 (D.softlimit && D.curblocks >= D.softlimit) ||
272                 (D.hardlimit && D.curblocks >= D.hardlimit) ||
273                 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
274                 (D.ihardlimit && D.curinodes>=D.ihardlimit)
275         ) {
276                 *dfree = 0;
277                 *dsize = D.curblocks;
278         } else if (D.softlimit==0 && D.hardlimit==0) {
279                 return(False);
280         } else {
281                 if (D.softlimit == 0)
282                         D.softlimit = D.hardlimit;
283                 *dfree = D.softlimit - D.curblocks;
284                 *dsize = D.softlimit;
285         }
286
287         return (True);
288 }
289
290 #elif defined(CRAY)
291
292 #include <sys/quota.h>
293 #include <mntent.h>
294
295 /****************************************************************************
296 try to get the disk space from disk quotas (CRAY VERSION)
297 ****************************************************************************/
298
299 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
300 {
301   struct mntent *mnt;
302   FILE *fd;
303   SMB_STRUCT_STAT sbuf;
304   SMB_DEV_T devno ;
305   static SMB_DEV_T devno_cached = 0 ;
306   static pstring name;
307   struct q_request request ;
308   struct qf_header header ;
309   static int quota_default = 0 ;
310   int found ;
311   
312   if ( sys_stat(path,&sbuf) == -1 )
313     return(False) ;
314   
315   devno = sbuf.st_dev ;
316   
317   if ( devno != devno_cached ) {
318     
319     devno_cached = devno ;
320     
321     if ((fd = setmntent(KMTAB)) == NULL)
322       return(False) ;
323     
324     found = False ;
325     
326     while ((mnt = getmntent(fd)) != NULL) {
327       
328       if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
329         continue ;
330       
331       if (sbuf.st_dev == devno) {
332         
333         found = True ;
334         break ;
335         
336       }
337       
338     }
339     
340     pstrcpy(name,mnt->mnt_dir) ;
341     endmntent(fd) ;
342     
343     if ( ! found )
344       return(False) ;
345   }
346   
347   request.qf_magic = QF_MAGIC ;
348   request.qf_entry.id = geteuid() ;
349   
350   if (quotactl(name, Q_GETQUOTA, &request) == -1)
351     return(False) ;
352   
353   if ( ! request.user )
354     return(False) ;
355   
356   if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
357     
358     if ( ! quota_default ) {
359       
360       if ( quotactl(name, Q_GETHEADER, &header) == -1 )
361         return(False) ;
362       else
363         quota_default = header.user_h.def_fq ;
364     }
365     
366     *dfree = quota_default ;
367     
368   }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
369     
370     *dfree = 0 ;
371     
372   }else{
373     
374     *dfree = request.qf_entry.user_q.f_quota ;
375     
376   }
377   
378   *dsize = request.qf_entry.user_q.f_use ;
379   
380   if ( *dfree < *dsize )
381     *dfree = 0 ;
382   else
383     *dfree -= *dsize ;
384   
385   *bsize = 4096 ;  /* Cray blocksize */
386   
387   return(True) ;
388   
389 }
390
391
392 #elif defined(SUNOS5) || defined(SUNOS4)
393
394 #include <fcntl.h>
395 #include <sys/param.h>
396 #if defined(SUNOS5)
397 #include <sys/fs/ufs_quota.h>
398 #include <sys/mnttab.h>
399 #include <sys/mntent.h>
400 #else /* defined(SUNOS4) */
401 #include <ufs/quota.h>
402 #include <mntent.h>
403 #endif
404
405 #if defined(SUNOS5)
406
407 /****************************************************************************
408  Allows querying of remote hosts for quotas on NFS mounted shares.
409  Supports normal NFS and AMD mounts.
410  Alan Romeril <a.romeril@ic.ac.uk> July 2K.
411 ****************************************************************************/
412
413 #include <rpc/rpc.h>
414 #include <rpc/types.h>
415 #include <rpcsvc/rquota.h>
416 #include <rpc/nettype.h>
417 #include <rpc/xdr.h>
418
419 static int quotastat;
420
421 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
422 {
423         if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
424                 return(0);
425         if (!xdr_int(xdrsp, &args->gqa_uid))
426                 return(0);
427         return (1);
428 }
429
430 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
431 {
432         if (!xdr_int(xdrsp, &quotastat)) {
433                 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
434                 return 0;
435         }
436         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
437                 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
438                 return 0;
439         }
440         if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
441                 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
442                 return 0;
443         }
444         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
445                 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
446                 return 0;
447         }
448         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
449                 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
450                 return 0;
451         }
452         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
453                 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
454                 return 0;
455         }
456         return (1);
457 }
458
459 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */ 
460 static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
461 {
462         uid_t uid = euser_id;
463         struct dqblk D;
464         char *mnttype = nfspath;
465         CLIENT *clnt;
466         struct getquota_rslt gqr;
467         struct getquota_args args;
468         char *cutstr, *pathname, *host, *testpath;
469         int len;
470         static struct timeval timeout = {2,0};
471         enum clnt_stat clnt_stat;
472         BOOL ret = True;
473
474         *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
475
476         len=strcspn(mnttype, ":");
477         pathname=strstr(mnttype, ":");
478         cutstr = (char *) SMB_MALLOC(len+1);
479         if (!cutstr)
480                 return False;
481
482         memset(cutstr, '\0', len+1);
483         host = strncat(cutstr,mnttype, sizeof(char) * len );
484         DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
485         DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
486         testpath=strchr_m(mnttype, ':');
487         args.gqa_pathp = testpath+1;
488         args.gqa_uid = uid;
489
490         DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
491
492         if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
493                 ret = False;
494                 goto out;
495         }
496
497         clnt->cl_auth = authunix_create_default();
498         DEBUG(9,("nfs_quotas: auth_success\n"));
499
500         clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
501
502         if (clnt_stat != RPC_SUCCESS) {
503                 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
504                 ret = False;
505                 goto out;
506         }
507
508         /* 
509          * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
510          * no quota set, and 3 if no permission to get the quota.  If 0 or 3 return
511          * something sensible.
512          */   
513
514         switch ( quotastat ) {
515         case 0:
516                 DEBUG(9,("nfs_quotas: Remote Quotas Failed!  Error \"%i\" \n", quotastat ));
517                 ret = False;
518                 goto out;
519
520         case 1:
521                 DEBUG(9,("nfs_quotas: Good quota data\n"));
522                 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
523                 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
524                 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
525                 break;
526
527         case 2:
528         case 3:
529                 D.dqb_bsoftlimit = 1;
530                 D.dqb_curblocks = 1;
531                 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
532                 break;
533
534         default:
535                 DEBUG(9,("nfs_quotas: Remote Quotas Questionable!  Error \"%i\" \n", quotastat ));
536                 break;
537         }
538
539         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",
540                         quotastat,
541                         gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
542                         gqr.getquota_rslt_u.gqr_rquota.rq_active,
543                         gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
544                         gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
545                         gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
546
547         *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
548         *dsize = D.dqb_bsoftlimit;
549
550         if (D.dqb_curblocks == D.dqb_curblocks == 1)
551                 *bsize = 512;
552
553         if (D.dqb_curblocks > D.dqb_bsoftlimit) {
554                 *dfree = 0;
555                 *dsize = D.dqb_curblocks;
556         } else
557                 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
558
559   out:
560
561         if (clnt) {
562                 if (clnt->cl_auth)
563                         auth_destroy(clnt->cl_auth);
564                 clnt_destroy(clnt);
565         }
566
567         DEBUG(5,("nfs_quotas: For path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
568
569         SAFE_FREE(cutstr);
570         DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
571         return ret;
572 }
573 #endif
574
575 /****************************************************************************
576 try to get the disk space from disk quotas (SunOS & Solaris2 version)
577 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
578 ****************************************************************************/
579
580 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
581 {
582         uid_t euser_id;
583         int ret;
584         struct dqblk D;
585 #if defined(SUNOS5)
586         struct quotctl command;
587         int file;
588         static struct mnttab mnt;
589         static pstring name;
590         pstring devopt;
591 #else /* SunOS4 */
592         struct mntent *mnt;
593         static pstring name;
594 #endif
595         FILE *fd;
596         SMB_STRUCT_STAT sbuf;
597         SMB_DEV_T devno ;
598         static SMB_DEV_T devno_cached = 0 ;
599         static int found ;
600
601         euser_id = geteuid();
602   
603         if ( sys_stat(path,&sbuf) == -1 )
604                 return(False) ;
605   
606         devno = sbuf.st_dev ;
607         DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,(unsigned int)devno));
608         if ( devno != devno_cached ) {
609                 devno_cached = devno ;
610 #if defined(SUNOS5)
611                 if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
612                         return(False) ;
613     
614                 found = False ;
615                 slprintf(devopt, sizeof(devopt) - 1, "dev=%x", (unsigned int)devno);
616                 while (getmntent(fd, &mnt) == 0) {
617                         if( !hasmntopt(&mnt, devopt) )
618                                 continue;
619
620                         DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt));
621
622                         /* quotas are only on vxfs, UFS or NFS */
623                         if ( 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         save_re_uid();
658         set_effective_uid(0);
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                 restore_re_uid();
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                 restore_re_uid();
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         restore_re_uid();
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   save_re_uid();
845   set_effective_uid(0);  
846
847   /* Use softlimit to determine disk space, except when it has been exceeded */
848
849   *bsize = 512;
850
851   if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
852   {
853     r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
854
855     restore_re_uid();
856
857     if (r==-1)
858       return(False);
859         
860     /* Use softlimit to determine disk space, except when it has been exceeded */
861     if (
862         (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
863         (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
864         (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
865         (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
866        )
867     {
868       *dfree = 0;
869       *dsize = D.dqb_curblocks;
870     }
871     else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
872     {
873       return(False);
874     }
875     else 
876     {
877       *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
878       *dsize = D.dqb_bsoftlimit;
879     }
880
881   }
882   else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
883   {
884     r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
885
886     restore_re_uid();
887
888     if (r==-1)
889     {
890       DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
891       return(False);
892     }
893         
894     /* No quota for this user. */
895     if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
896     {
897       return(False);
898     }
899
900     /* Use softlimit to determine disk space, except when it has been exceeded */
901     if (
902         (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
903         (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
904         (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
905         (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
906        )
907     {
908       *dfree = 0;
909       *dsize = F.d_bcount;
910     }
911     else 
912     {
913       *dfree = (F.d_blk_softlimit - F.d_bcount);
914       *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
915     }
916
917   }
918   else
919   {
920           restore_re_uid();
921           return(False);
922   }
923
924   return (True);
925
926 }
927
928 #else
929
930 #if    defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
931 #include <ufs/ufs/quota.h>
932 #include <machine/param.h>
933 #elif         AIX
934 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
935 #include <jfs/quota.h>
936 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
937 #define dqb_curfiles dqb_curinodes
938 #define dqb_fhardlimit dqb_ihardlimit
939 #define dqb_fsoftlimit dqb_isoftlimit
940 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
941 #include <sys/quota.h>
942 #include <devnm.h>
943 #endif
944
945 #if defined(__FreeBSD__) || defined(__DragonFly__)
946
947 #include <rpc/rpc.h>
948 #include <rpc/types.h>
949 #include <rpcsvc/rquota.h>
950 #ifdef HAVE_RPC_NETTYPE_H
951 #include <rpc/nettype.h>
952 #endif
953 #include <rpc/xdr.h>
954
955 static int quotastat;
956
957 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
958 {
959         if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
960                 return(0);
961         if (!xdr_int(xdrsp, &args->gqa_uid))
962                 return(0);
963         return (1);
964 }
965
966 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
967 {
968         if (!xdr_int(xdrsp, &quotastat)) {
969                 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
970                 return 0;
971         }
972         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
973                 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
974                 return 0;
975         }
976         if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
977                 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
978                 return 0;
979         }
980         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
981                 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
982                 return 0;
983         }
984         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
985                 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
986                 return 0;
987         }
988         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
989                 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
990                 return 0;
991         }
992         return (1);
993 }
994
995 /* Works on FreeBSD, too. :-) */
996 static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
997 {
998         uid_t uid = euser_id;
999         struct dqblk D;
1000         char *mnttype = nfspath;
1001         CLIENT *clnt;
1002         struct getquota_rslt gqr;
1003         struct getquota_args args;
1004         char *cutstr, *pathname, *host, *testpath;
1005         int len;
1006         static struct timeval timeout = {2,0};
1007         enum clnt_stat clnt_stat;
1008         BOOL ret = True;
1009
1010         *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
1011
1012         len=strcspn(mnttype, ":");
1013         pathname=strstr(mnttype, ":");
1014         cutstr = (char *) SMB_MALLOC(len+1);
1015         if (!cutstr)
1016                 return False;
1017
1018         memset(cutstr, '\0', len+1);
1019         host = strncat(cutstr,mnttype, sizeof(char) * len );
1020         DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1021         DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1022         testpath=strchr_m(mnttype, ':');
1023         args.gqa_pathp = testpath+1;
1024         args.gqa_uid = uid;
1025
1026         DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1027
1028         if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1029                 ret = False;
1030                 goto out;
1031         }
1032
1033         clnt->cl_auth = authunix_create_default();
1034         DEBUG(9,("nfs_quotas: auth_success\n"));
1035
1036         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);
1037
1038         if (clnt_stat != RPC_SUCCESS) {
1039                 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1040                 ret = False;
1041                 goto out;
1042         }
1043
1044         /* 
1045          * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1046          * no quota set, and 3 if no permission to get the quota.  If 0 or 3 return
1047          * something sensible.
1048          */   
1049
1050         switch ( quotastat ) {
1051         case 0:
1052                 DEBUG(9,("nfs_quotas: Remote Quotas Failed!  Error \"%i\" \n", quotastat ));
1053                 ret = False;
1054                 goto out;
1055
1056         case 1:
1057                 DEBUG(9,("nfs_quotas: Good quota data\n"));
1058                 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1059                 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1060                 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1061                 break;
1062
1063         case 2:
1064         case 3:
1065                 D.dqb_bsoftlimit = 1;
1066                 D.dqb_curblocks = 1;
1067                 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
1068                 break;
1069
1070         default:
1071                 DEBUG(9,("nfs_quotas: Remote Quotas Questionable!  Error \"%i\" \n", quotastat ));
1072                 break;
1073         }
1074
1075         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",
1076                         quotastat,
1077                         gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1078                         gqr.getquota_rslt_u.gqr_rquota.rq_active,
1079                         gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1080                         gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1081                         gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1082
1083         if (D.dqb_bsoftlimit == 0)
1084                 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1085         if (D.dqb_bsoftlimit == 0)
1086                 return False;
1087
1088         *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1089         *dsize = D.dqb_bsoftlimit;
1090
1091         if (D.dqb_curblocks == D.dqb_curblocks == 1)
1092                 *bsize = DEV_BSIZE;
1093
1094         if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1095                 *dfree = 0;
1096                 *dsize = D.dqb_curblocks;
1097         } else
1098                 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1099
1100   out:
1101
1102         if (clnt) {
1103                 if (clnt->cl_auth)
1104                         auth_destroy(clnt->cl_auth);
1105                 clnt_destroy(clnt);
1106         }
1107
1108         DEBUG(5,("nfs_quotas: For path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1109
1110         SAFE_FREE(cutstr);
1111         DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1112         return ret;
1113 }
1114
1115 #endif
1116
1117 /****************************************************************************
1118 try to get the disk space from disk quotas - default version
1119 ****************************************************************************/
1120
1121 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1122 {
1123   int r;
1124   struct dqblk D;
1125   uid_t euser_id;
1126 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1127   char dev_disk[256];
1128   SMB_STRUCT_STAT S;
1129
1130   /* find the block device file */
1131
1132 #ifdef HPUX
1133   /* Need to set the cache flag to 1 for HPUX. Seems
1134    * to have a significant performance boost when
1135    * lstat calls on /dev access this function.
1136    */
1137   if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0))
1138 #else
1139   if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) 
1140         return (False);
1141 #endif /* ifdef HPUX */
1142
1143 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1144
1145   euser_id = geteuid();
1146
1147 #ifdef HPUX
1148   /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1149   save_re_uid();
1150   if (set_re_uid() != 0) return False;
1151   
1152   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1153
1154   restore_re_uid();
1155 #else 
1156 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1157   {
1158     /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1159     gid_t egrp_id;
1160 #if defined(__FreeBSD__) || defined(__DragonFly__)
1161     SMB_DEV_T devno;
1162     struct statfs *mnts;
1163     SMB_STRUCT_STAT st;
1164     int mntsize, i;
1165     
1166     if (sys_stat(path,&st) < 0)
1167         return False;
1168     devno = st.st_dev;
1169
1170     mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1171     if (mntsize <= 0)
1172         return False;
1173
1174     for (i = 0; i < mntsize; i++) {
1175         if (sys_stat(mnts[i].f_mntonname,&st) < 0)
1176             return False;
1177         if (st.st_dev == devno)
1178             break;
1179     }
1180     if (i == mntsize)
1181         return False;
1182 #endif
1183     
1184     save_re_uid();
1185     set_effective_uid(0);
1186
1187 #if defined(__FreeBSD__) || defined(__DragonFly__)
1188     if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1189         BOOL retval;
1190         retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1191         restore_re_uid();
1192         return retval;
1193     }
1194 #endif
1195
1196     egrp_id = getegid();
1197     r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1198
1199     /* As FreeBSD has group quotas, if getting the user
1200        quota fails, try getting the group instead. */
1201     if (r) {
1202             r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1203     }
1204
1205     restore_re_uid();
1206   }
1207 #elif defined(AIX)
1208   /* AIX has both USER and GROUP quotas: 
1209      Get the USER quota (ohnielse@fysik.dtu.dk) */
1210   save_re_uid();
1211   if (set_re_uid() != 0) 
1212     return False;
1213   r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1214   restore_re_uid();
1215 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1216   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1217 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1218 #endif /* HPUX */
1219
1220   /* Use softlimit to determine disk space, except when it has been exceeded */
1221 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1222   *bsize = DEV_BSIZE;
1223 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1224   *bsize = 1024;
1225 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1226
1227   if (r)
1228     {
1229       if (errno == EDQUOT) 
1230         {
1231           *dfree =0;
1232           *dsize =D.dqb_curblocks;
1233           return (True);
1234         }
1235       else return(False);
1236     }
1237
1238   /* If softlimit is zero, set it equal to hardlimit.
1239    */
1240
1241   if (D.dqb_bsoftlimit==0)
1242     D.dqb_bsoftlimit = D.dqb_bhardlimit;
1243
1244   if (D.dqb_bsoftlimit==0)
1245     return(False);
1246   /* Use softlimit to determine disk space, except when it has been exceeded */
1247   if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1248 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1249 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1250 #endif
1251     ) {
1252       *dfree = 0;
1253       *dsize = D.dqb_curblocks;
1254     }
1255   else {
1256     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1257     *dsize = D.dqb_bsoftlimit;
1258   }
1259   return (True);
1260 }
1261
1262 #endif
1263
1264 #if defined(VXFS_QUOTA)
1265
1266 /****************************************************************************
1267 Try to get the disk space from Veritas disk quotas.
1268     David Lee <T.D.Lee@durham.ac.uk> August 1999.
1269
1270 Background assumptions:
1271     Potentially under many Operating Systems.  Initially Solaris 2.
1272
1273     My guess is that Veritas is largely, though not entirely,
1274     independent of OS.  So I have separated it out.
1275
1276     There may be some details.  For example, OS-specific "include" files.
1277
1278     It is understood that HPUX 10 somehow gets Veritas quotas without
1279     any special effort; if so, this routine need not be compiled in.
1280         Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1281
1282 Warning:
1283     It is understood that Veritas do not publicly support this ioctl interface.
1284     Rather their preference would be for the user (us) to call the native
1285     OS and then for the OS itself to call through to the VxFS filesystem.
1286     Presumably HPUX 10, see above, does this.
1287
1288 Hints for porting:
1289     Add your OS to "IFLIST" below.
1290     Get it to compile successfully:
1291         Almost certainly "include"s require attention: see SUNOS5.
1292     In the main code above, arrange for it to be called: see SUNOS5.
1293     Test!
1294     
1295 ****************************************************************************/
1296
1297 /* "IFLIST"
1298  * This "if" is a list of ports:
1299  *      if defined(OS1) || defined(OS2) || ...
1300  */
1301 #if defined(SUNOS5)
1302
1303 #if defined(SUNOS5)
1304 #include <sys/fs/vx_solaris.h>
1305 #endif
1306 #include <sys/fs/vx_machdep.h>
1307 #include <sys/fs/vx_layout.h>
1308 #include <sys/fs/vx_quota.h>
1309 #include <sys/fs/vx_aioctl.h>
1310 #include <sys/fs/vx_ioctl.h>
1311
1312 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1313 {
1314   uid_t user_id, euser_id;
1315   int ret;
1316   struct vx_dqblk D;
1317   struct vx_quotctl quotabuf;
1318   struct vx_genioctl genbuf;
1319   pstring qfname;
1320   int file;
1321
1322   /*
1323    * "name" may or may not include a trailing "/quotas".
1324    * Arranging consistency of calling here in "quotas.c" may not be easy and
1325    * it might be easier to examine and adjust it here.
1326    * Fortunately, VxFS seems not to mind at present.
1327    */
1328   pstrcpy(qfname, name) ;
1329   /* pstrcat(qfname, "/quotas") ; */    /* possibly examine and adjust "name" */
1330
1331   euser_id = geteuid();
1332   set_effective_uid(0);
1333
1334   DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1335   if((file=sys_open(qfname, O_RDONLY,0))<0) {
1336     set_effective_uid(euser_id);
1337     return(False);
1338   }
1339   genbuf.ioc_cmd = VX_QUOTACTL;
1340   genbuf.ioc_up = (void *) &quotabuf;
1341
1342   quotabuf.cmd = VX_GETQUOTA;
1343   quotabuf.uid = euser_id;
1344   quotabuf.addr = (caddr_t) &D;
1345   ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1346   close(file);
1347
1348   set_effective_uid(euser_id);
1349
1350   if (ret < 0) {
1351     DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1352     return(False);
1353   }
1354
1355   /* If softlimit is zero, set it equal to hardlimit.
1356    */
1357
1358   if (D.dqb_bsoftlimit==0)
1359     D.dqb_bsoftlimit = D.dqb_bhardlimit;
1360
1361   /* Use softlimit to determine disk space. A user exceeding the quota is told
1362    * that there's no space left. Writes might actually work for a bit if the
1363    * hardlimit is set higher than softlimit. Effectively the disk becomes
1364    * made of rubber latex and begins to expand to accommodate the user :-)
1365    */
1366   DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1367          path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1368          D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1369
1370   if (D.dqb_bsoftlimit==0)
1371     return(False);
1372   *bsize = DEV_BSIZE;
1373   *dsize = D.dqb_bsoftlimit;
1374
1375   if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1376      *dfree = 0;
1377      *dsize = D.dqb_curblocks;
1378   } else
1379     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1380       
1381   DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",
1382          path,(double)*bsize,(double)*dfree,(double)*dsize));
1383
1384   return(True);
1385 }
1386
1387 #endif /* SUNOS5 || ... */
1388
1389 #endif /* VXFS_QUOTA */
1390
1391 #else /* WITH_QUOTAS */
1392
1393 BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1394 {
1395   (*bsize) = 512; /* This value should be ignored */
1396
1397   /* And just to be sure we set some values that hopefully */
1398   /* will be larger that any possible real-world value     */
1399   (*dfree) = (SMB_BIG_UINT)-1;
1400   (*dsize) = (SMB_BIG_UINT)-1;
1401
1402   /* As we have select not to use quotas, allways fail */
1403   return False;
1404 }
1405 #endif /* WITH_QUOTAS */
1406
1407 #else /* HAVE_SYS_QUOTAS */
1408 /* wrapper to the new sys_quota interface 
1409    this file should be removed later
1410    */
1411 BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1412 {
1413         int r;
1414         SMB_DISK_QUOTA D;
1415         unid_t id;
1416
1417         id.uid = geteuid();
1418
1419         ZERO_STRUCT(D);
1420         r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1421
1422         /* Use softlimit to determine disk space, except when it has been exceeded */
1423         *bsize = D.bsize;
1424         if (r == -1) {
1425                 if (errno == EDQUOT) {
1426                         *dfree =0;
1427                         *dsize =D.curblocks;
1428                         return (True);
1429                 } else {
1430                         goto try_group_quota;
1431                 }
1432         }
1433
1434         /* Use softlimit to determine disk space, except when it has been exceeded */
1435         if (
1436                 (D.softlimit && D.curblocks >= D.softlimit) ||
1437                 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1438                 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1439                 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1440         ) {
1441                 *dfree = 0;
1442                 *dsize = D.curblocks;
1443         } else if (D.softlimit==0 && D.hardlimit==0) {
1444                 goto try_group_quota;
1445         } else {
1446                 if (D.softlimit == 0)
1447                         D.softlimit = D.hardlimit;
1448                 *dfree = D.softlimit - D.curblocks;
1449                 *dsize = D.softlimit;
1450         }
1451
1452         return True;
1453         
1454 try_group_quota:
1455         id.gid = getegid();
1456
1457         ZERO_STRUCT(D);
1458         r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1459
1460         /* Use softlimit to determine disk space, except when it has been exceeded */
1461         *bsize = D.bsize;
1462         if (r == -1) {
1463                 if (errno == EDQUOT) {
1464                         *dfree =0;
1465                         *dsize =D.curblocks;
1466                         return (True);
1467                 } else {
1468                         return False;
1469                 }
1470         }
1471
1472         /* Use softlimit to determine disk space, except when it has been exceeded */
1473         if (
1474                 (D.softlimit && D.curblocks >= D.softlimit) ||
1475                 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1476                 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1477                 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1478         ) {
1479                 *dfree = 0;
1480                 *dsize = D.curblocks;
1481         } else if (D.softlimit==0 && D.hardlimit==0) {
1482                 return False;
1483         } else {
1484                 if (D.softlimit == 0)
1485                         D.softlimit = D.hardlimit;
1486                 *dfree = D.softlimit - D.curblocks;
1487                 *dsize = D.softlimit;
1488         }
1489
1490         return (True);
1491 }
1492 #endif /* HAVE_SYS_QUOTAS */