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