move to SAFE_FREE()
[ira/wip.git] / source3 / smbd / quotas.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    support for quotas
5    Copyright (C) Andrew Tridgell 1992-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22
23 /* 
24  * This is one of the most system dependent parts of Samba, and its
25  * done a litle differently. Each system has its own way of doing 
26  * things :-(
27  */
28
29 #include "includes.h"
30
31 extern int DEBUGLEVEL;
32
33 #if defined(VXFS_QUOTA)
34
35 /*
36  * In addition to their native filesystems, some systems have Veritas VxFS.
37  * Declare here, define at end: reduces likely "include" interaction problems.
38  *      David Lee <T.D.Lee@durham.ac.uk>
39  */
40 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
41
42 #endif /* VXFS_QUOTA */
43
44 #ifdef LINUX
45
46 #include <sys/types.h>
47 #include <asm/types.h>
48 #include <sys/quota.h>
49
50 #include <mntent.h>
51 #include <linux/unistd.h>
52
53 _syscall4(int, quotactl, int, cmd, const char *, special, int, id, caddr_t, addr);
54
55 /****************************************************************************
56 try to get the disk space from disk quotas (LINUX version)
57 ****************************************************************************/
58
59 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
60 {
61   int r;
62   struct dqblk D;
63   SMB_STRUCT_STAT S;
64   FILE *fp;
65   struct mntent *mnt;
66   SMB_DEV_T devno;
67   int found;
68   uid_t euser_id;
69
70   euser_id = geteuid();
71   
72   /* find the block device file */
73   
74   if ( sys_stat(path, &S) == -1 ) {
75     return(False) ;
76   }
77
78   devno = S.st_dev ;
79   
80   fp = setmntent(MOUNTED,"r");
81   found = False ;
82   
83   while ((mnt = getmntent(fp))) {
84     if ( sys_stat(mnt->mnt_dir,&S) == -1 )
85       continue ;
86     if (S.st_dev == devno) {
87       found = True ;
88       break ;
89     }
90   }
91   endmntent(fp) ;
92   
93   if (!found) {
94       return(False);
95     }
96
97   save_re_uid();
98   set_effective_uid(0);  
99   r=quotactl(QCMD(Q_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D);
100   restore_re_uid();
101
102   /* Use softlimit to determine disk space, except when it has been exceeded */
103   *bsize = 1024;
104   if (r)
105     {
106       if (errno == EDQUOT) 
107        {
108          *dfree =0;
109          *dsize =D.dqb_curblocks;
110          return (True);
111     }
112       else return(False);
113   }
114   /* Use softlimit to determine disk space, except when it has been exceeded */
115   if (
116       (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
117       (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
118       (D.dqb_isoftlimit && D.dqb_curinodes>=D.dqb_isoftlimit) ||
119       (D.dqb_ihardlimit && D.dqb_curinodes>=D.dqb_ihardlimit)
120      )
121     {
122       *dfree = 0;
123       *dsize = D.dqb_curblocks;
124     }
125   else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
126     {
127       return(False);
128     }
129   else {
130     if (D.dqb_bsoftlimit == 0)
131       D.dqb_bsoftlimit = D.dqb_bhardlimit;
132     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
133     *dsize = D.dqb_bsoftlimit;
134   }
135   return (True);
136 }
137
138 #elif defined(CRAY)
139
140 #include <sys/quota.h>
141 #include <mntent.h>
142
143 /****************************************************************************
144 try to get the disk space from disk quotas (CRAY VERSION)
145 ****************************************************************************/
146
147 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
148 {
149   struct mntent *mnt;
150   FILE *fd;
151   SMB_STRUCT_STAT sbuf;
152   SMB_DEV_T devno ;
153   static SMB_DEV_T devno_cached = 0 ;
154   static pstring name;
155   struct q_request request ;
156   struct qf_header header ;
157   static int quota_default = 0 ;
158   int found ;
159   
160   if ( sys_stat(path,&sbuf) == -1 )
161     return(False) ;
162   
163   devno = sbuf.st_dev ;
164   
165   if ( devno != devno_cached ) {
166     
167     devno_cached = devno ;
168     
169     if ((fd = setmntent(KMTAB)) == NULL)
170       return(False) ;
171     
172     found = False ;
173     
174     while ((mnt = getmntent(fd)) != NULL) {
175       
176       if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
177         continue ;
178       
179       if (sbuf.st_dev == devno) {
180         
181         found = True ;
182         break ;
183         
184       }
185       
186     }
187     
188     pstrcpy(name,mnt->mnt_dir) ;
189     endmntent(fd) ;
190     
191     if ( ! found )
192       return(False) ;
193   }
194   
195   request.qf_magic = QF_MAGIC ;
196   request.qf_entry.id = geteuid() ;
197   
198   if (quotactl(name, Q_GETQUOTA, &request) == -1)
199     return(False) ;
200   
201   if ( ! request.user )
202     return(False) ;
203   
204   if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
205     
206     if ( ! quota_default ) {
207       
208       if ( quotactl(name, Q_GETHEADER, &header) == -1 )
209         return(False) ;
210       else
211         quota_default = header.user_h.def_fq ;
212     }
213     
214     *dfree = quota_default ;
215     
216   }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
217     
218     *dfree = 0 ;
219     
220   }else{
221     
222     *dfree = request.qf_entry.user_q.f_quota ;
223     
224   }
225   
226   *dsize = request.qf_entry.user_q.f_use ;
227   
228   if ( *dfree < *dsize )
229     *dfree = 0 ;
230   else
231     *dfree -= *dsize ;
232   
233   *bsize = 4096 ;  /* Cray blocksize */
234   
235   return(True) ;
236   
237 }
238
239
240 #elif defined(SUNOS5) || defined(SUNOS4)
241
242 #include <fcntl.h>
243 #include <sys/param.h>
244 #if defined(SUNOS5)
245 #include <sys/fs/ufs_quota.h>
246 #include <sys/mnttab.h>
247 #include <sys/mntent.h>
248 #else /* defined(SUNOS4) */
249 #include <ufs/quota.h>
250 #include <mntent.h>
251 #endif
252
253 #if defined(SUNOS5)
254
255 /****************************************************************************
256  Allows querying of remote hosts for quotas on NFS mounted shares.
257  Supports normal NFS and AMD mounts.
258  Alan Romeril <a.romeril@ic.ac.uk> July 2K.
259 ****************************************************************************/
260
261 #include <rpc/rpc.h>
262 #include <rpc/types.h>
263 #include <rpcsvc/rquota.h>
264 #include <rpc/nettype.h>
265 #include <rpc/xdr.h>
266
267 static int quotastat;
268
269 static int xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
270 {
271         if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
272                 return(0);
273         if (!xdr_int(xdrsp, &args->gqa_uid))
274                 return(0);
275         return (1);
276 }
277
278 static int xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
279 {
280         if (!xdr_int(xdrsp, &quotastat)) {
281                 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
282                 return 0;
283         }
284         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
285                 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
286                 return 0;
287         }
288         if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
289                 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
290                 return 0;
291         }
292         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
293                 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
294                 return 0;
295         }
296         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
297                 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
298                 return 0;
299         }
300         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
301                 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
302                 return 0;
303         }
304         return (1);
305 }
306
307 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */ 
308 static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
309 {
310         uid_t uid = euser_id;
311         struct dqblk D;
312         char *mnttype = nfspath;
313         CLIENT *clnt;
314         struct getquota_rslt gqr;
315         struct getquota_args args;
316         char *cutstr, *pathname, *host, *testpath;
317         int len;
318         static struct timeval timeout = {2,0};
319         enum clnt_stat clnt_stat;
320         BOOL ret = True;
321
322         *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
323
324         len=strcspn(mnttype, ":");
325         pathname=strstr(mnttype, ":");
326         cutstr = (char *) malloc(sizeof(char) * len );
327         if (!cutstr)
328                 return False;
329
330         host = strncat(cutstr,mnttype, sizeof(char) * len );
331         DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
332         DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
333         testpath=strchr_m(mnttype, ':');
334         args.gqa_pathp = testpath+1;
335         args.gqa_uid = uid;
336
337         DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
338
339         if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
340                 ret = False;
341                 goto out;
342         }
343
344         clnt->cl_auth = authunix_create_default();
345         DEBUG(9,("nfs_quotas: auth_success\n"));
346
347         clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, xdr_getquota_args, (caddr_t)&args, xdr_getquota_rslt, (caddr_t)&gqr, timeout);
348
349         if (clnt_stat != RPC_SUCCESS) {
350                 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
351                 ret = False;
352                 goto out;
353         }
354
355         /* 
356          * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
357          * no quota set, and 3 if no permission to get the quota.  If 0 or 3 return
358          * something sensible.
359          */   
360
361         switch ( quotastat ) {
362         case 0:
363                 DEBUG(9,("nfs_quotas: Remote Quotas Failed!  Error \"%i\" \n", quotastat ));
364                 ret = False;
365                 goto out;
366
367         case 1:
368                 DEBUG(9,("nfs_quotas: Good quota data\n"));
369                 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
370                 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
371                 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
372                 break;
373
374         case 2:
375         case 3:
376                 D.dqb_bsoftlimit = 1;
377                 D.dqb_curblocks = 1;
378                 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
379                 break;
380
381         default:
382                 DEBUG(9,("nfs_quotas: Remote Quotas Questionable!  Error \"%i\" \n", quotastat ));
383                 break;
384         }
385
386         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",
387                         quotastat,
388                         gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
389                         gqr.getquota_rslt_u.gqr_rquota.rq_active,
390                         gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
391                         gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
392                         gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
393
394         *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
395         *dsize = D.dqb_bsoftlimit;
396
397         if (D.dqb_curblocks == D.dqb_curblocks == 1)
398                 *bsize = 512;
399
400         if (D.dqb_curblocks > D.dqb_bsoftlimit) {
401                 *dfree = 0;
402                 *dsize = D.dqb_curblocks;
403         } else
404                 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
405
406   out:
407
408         if (clnt) {
409                 if (clnt->cl_auth)
410                         auth_destroy(clnt->cl_auth);
411                 clnt_destroy(clnt);
412         }
413
414         DEBUG(5,("nfs_quotas: For path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
415
416         SAFE_FREE(cutstr);
417         DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
418         return ret;
419 }
420 #endif
421
422 /****************************************************************************
423 try to get the disk space from disk quotas (SunOS & Solaris2 version)
424 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
425 ****************************************************************************/
426
427 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
428 {
429         uid_t euser_id;
430         int ret;
431         struct dqblk D;
432 #if defined(SUNOS5)
433         struct quotctl command;
434         int file;
435         static struct mnttab mnt;
436         static pstring name;
437         pstring devopt;
438 #else /* SunOS4 */
439         struct mntent *mnt;
440         static pstring name;
441 #endif
442         FILE *fd;
443         SMB_STRUCT_STAT sbuf;
444         SMB_DEV_T devno ;
445         static SMB_DEV_T devno_cached = 0 ;
446         static int found ;
447
448         euser_id = geteuid();
449   
450         if ( sys_stat(path,&sbuf) == -1 )
451                 return(False) ;
452   
453         devno = sbuf.st_dev ;
454         DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,(unsigned int)devno));
455         if ( devno != devno_cached ) {
456                 devno_cached = devno ;
457 #if defined(SUNOS5)
458                 if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
459                         return(False) ;
460     
461                 found = False ;
462                 slprintf(devopt, sizeof(devopt) - 1, "dev=%x", (unsigned int)devno);
463                 while (getmntent(fd, &mnt) == 0) {
464                         if( !hasmntopt(&mnt, devopt) )
465                                 continue;
466
467                         DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt));
468
469                         /* quotas are only on vxfs, UFS or NFS */
470                         if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
471                                 strcmp( mnt.mnt_fstype, "nfs" ) == 0    ||
472                                 strcmp( mnt.mnt_fstype, "vxfs" ) == 0  ) { 
473                                         found = True ;
474                                         break;
475                         }
476                 }
477     
478                 pstrcpy(name,mnt.mnt_mountp) ;
479                 pstrcat(name,"/quotas") ;
480                 fclose(fd) ;
481 #else /* SunOS4 */
482                 if ((fd = setmntent(MOUNTED, "r")) == NULL)
483                         return(False) ;
484     
485                 found = False ;
486                 while ((mnt = getmntent(fd)) != NULL) {
487                         if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
488                                 continue ;
489                         DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev));
490                         if (sbuf.st_dev == devno) {
491                                 found = True ;
492                                 break;
493                         }
494                 }
495     
496                 pstrcpy(name,mnt->mnt_fsname) ;
497                 endmntent(fd) ;
498 #endif
499         }
500
501         if ( ! found )
502                 return(False) ;
503
504         save_re_uid();
505         set_effective_uid(0);
506
507 #if defined(SUNOS5)
508         if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) {
509                 BOOL retval;
510                 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt.mnt_special));
511                 retval = nfs_quotas(mnt.mnt_special, euser_id, bsize, dfree, dsize);
512                 restore_re_uid();
513                 return retval;
514         }
515
516         DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
517         if((file=sys_open(name, O_RDONLY,0))<0) {
518                 restore_re_uid();
519                 return(False);
520         }
521         command.op = Q_GETQUOTA;
522         command.uid = euser_id;
523         command.addr = (caddr_t) &D;
524         ret = ioctl(file, Q_QUOTACTL, &command);
525         close(file);
526 #else
527         DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
528         ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
529 #endif
530
531         restore_re_uid();
532
533         if (ret < 0) {
534                 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
535
536 #if defined(SUNOS5) && defined(VXFS_QUOTA)
537                 /* If normal quotactl() fails, try vxfs private calls */
538                 set_effective_uid(euser_id);
539                 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
540                 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
541                         BOOL retval;
542                         retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
543                         return(retval);
544                 }
545 #else
546                 return(False);
547 #endif
548         }
549
550         /* If softlimit is zero, set it equal to hardlimit.
551          */
552   
553         if (D.dqb_bsoftlimit==0)
554                 D.dqb_bsoftlimit = D.dqb_bhardlimit;
555
556         /* Use softlimit to determine disk space. A user exceeding the quota is told
557          * that there's no space left. Writes might actually work for a bit if the
558          * hardlimit is set higher than softlimit. Effectively the disk becomes
559          * made of rubber latex and begins to expand to accommodate the user :-)
560          */
561
562         if (D.dqb_bsoftlimit==0)
563                 return(False);
564         *bsize = DEV_BSIZE;
565         *dsize = D.dqb_bsoftlimit;
566
567         if (D.dqb_curblocks > D.dqb_bsoftlimit) {
568                 *dfree = 0;
569                 *dsize = D.dqb_curblocks;
570         } else
571                 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
572       
573         DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",
574                 path,(double)*bsize,(double)*dfree,(double)*dsize));
575
576         return(True);
577 }
578
579
580 #elif defined(OSF1)
581 #include <ufs/quota.h>
582
583 /****************************************************************************
584 try to get the disk space from disk quotas - OSF1 version
585 ****************************************************************************/
586
587 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
588 {
589   int r, save_errno;
590   struct dqblk D;
591   SMB_STRUCT_STAT S;
592   uid_t euser_id;
593
594   /*
595    * This code presumes that OSF1 will only
596    * give out quota info when the real uid 
597    * matches the effective uid. JRA.
598    */
599   euser_id = geteuid();
600   save_re_uid();
601   if (set_re_uid() != 0) return False;
602
603   r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
604   if (r) {
605      save_errno = errno;
606   }
607
608   restore_re_uid();
609
610   *bsize = DEV_BSIZE;
611
612   if (r)
613   {
614       if (save_errno == EDQUOT)   /* disk quota exceeded */
615       {
616          *dfree = 0;
617          *dsize = D.dqb_curblocks;
618          return (True);
619       }
620       else
621          return (False);  
622   }
623
624   /* If softlimit is zero, set it equal to hardlimit.
625    */
626
627   if (D.dqb_bsoftlimit==0)
628     D.dqb_bsoftlimit = D.dqb_bhardlimit;
629
630   /* Use softlimit to determine disk space, except when it has been exceeded */
631
632   if (D.dqb_bsoftlimit==0)
633     return(False);
634
635   if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
636     *dfree = 0;
637     *dsize = D.dqb_curblocks;
638   } else {
639     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
640     *dsize = D.dqb_bsoftlimit;
641   }
642   return (True);
643 }
644
645 #elif defined (IRIX6)
646 /****************************************************************************
647 try to get the disk space from disk quotas (IRIX 6.2 version)
648 ****************************************************************************/
649
650 #include <sys/quota.h>
651 #include <mntent.h>
652
653 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
654 {
655   uid_t euser_id;
656   int r;
657   struct dqblk D;
658   struct fs_disk_quota        F;
659   SMB_STRUCT_STAT S;
660   FILE *fp;
661   struct mntent *mnt;
662   SMB_DEV_T devno;
663   int found;
664   
665   /* find the block device file */
666   
667   if ( sys_stat(path, &S) == -1 ) {
668     return(False) ;
669   }
670
671   devno = S.st_dev ;
672   
673   fp = setmntent(MOUNTED,"r");
674   found = False ;
675   
676   while ((mnt = getmntent(fp))) {
677     if ( sys_stat(mnt->mnt_dir,&S) == -1 )
678       continue ;
679     if (S.st_dev == devno) {
680       found = True ;
681       break ;
682     }
683   }
684   endmntent(fp) ;
685   
686   if (!found) {
687     return(False);
688   }
689
690   euser_id=geteuid();
691   save_re_uid();
692   set_effective_uid(0);  
693
694   /* Use softlimit to determine disk space, except when it has been exceeded */
695
696   *bsize = 512;
697
698   if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
699   {
700     r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
701
702     restore_re_uid();
703
704     if (r==-1)
705       return(False);
706         
707     /* Use softlimit to determine disk space, except when it has been exceeded */
708     if (
709         (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
710         (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
711         (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
712         (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
713        )
714     {
715       *dfree = 0;
716       *dsize = D.dqb_curblocks;
717     }
718     else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
719     {
720       return(False);
721     }
722     else 
723     {
724       *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
725       *dsize = D.dqb_bsoftlimit;
726     }
727
728   }
729   else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
730   {
731     r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
732
733     restore_re_uid();
734
735     if (r==-1)
736       return(False);
737         
738     /* Use softlimit to determine disk space, except when it has been exceeded */
739     if (
740         (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
741         (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
742         (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
743         (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
744        )
745     {
746       *dfree = 0;
747       *dsize = F.d_bcount;
748     }
749     else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
750     {
751       return(False);
752     }
753     else 
754     {
755       *dfree = (F.d_blk_softlimit - F.d_bcount);
756       *dsize = F.d_blk_softlimit;
757     }
758
759   }
760   else
761   {
762           restore_re_uid();
763           return(False);
764   }
765
766   return (True);
767
768 }
769
770 #else
771
772 #if    defined(__FreeBSD__) || defined(__OpenBSD__)
773 #include <ufs/ufs/quota.h>
774 #include <machine/param.h>
775 #elif         AIX
776 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
777 #include <jfs/quota.h>
778 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
779 #define dqb_curfiles dqb_curinodes
780 #define dqb_fhardlimit dqb_ihardlimit
781 #define dqb_fsoftlimit dqb_isoftlimit
782 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
783 #include <sys/quota.h>
784 #include <devnm.h>
785 #endif
786
787 /****************************************************************************
788 try to get the disk space from disk quotas - default version
789 ****************************************************************************/
790
791 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
792 {
793   int r;
794   struct dqblk D;
795   uid_t euser_id;
796 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
797   char dev_disk[256];
798   SMB_STRUCT_STAT S;
799   /* find the block device file */
800   if ((sys_stat(path, &S)<0) ||
801       (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
802 #endif
803
804   euser_id = geteuid();
805
806 #ifdef HPUX
807   /* for HPUX, real uid must be same as euid to execute quotactl for euid */
808   save_re_uid();
809   if (set_re_uid() != 0) return False;
810   
811   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
812
813   restore_re_uid();
814 #else 
815 #if defined(__FreeBSD__) || defined(__OpenBSD__)
816   {
817     /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
818     gid_t egrp_id;
819  
820     save_re_uid();
821     set_effective_uid(0);
822
823     egrp_id = getegid();
824     r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
825
826     /* As FreeBSD has group quotas, if getting the user
827        quota fails, try getting the group instead. */
828     if (r) {
829             r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
830     }
831
832     restore_re_uid();
833   }
834 #elif defined(AIX)
835   /* AIX has both USER and GROUP quotas: 
836      Get the USER quota (ohnielse@fysik.dtu.dk) */
837   r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
838 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
839   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
840 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
841 #endif /* HPUX */
842
843   /* Use softlimit to determine disk space, except when it has been exceeded */
844 #if defined(__FreeBSD__) || defined(__OpenBSD__)
845   *bsize = DEV_BSIZE;
846 #else /* !__FreeBSD__ && !__OpenBSD__ */
847   *bsize = 1024;
848 #endif /*!__FreeBSD__ && !__OpenBSD__ */
849
850   if (r)
851     {
852       if (errno == EDQUOT) 
853         {
854           *dfree =0;
855           *dsize =D.dqb_curblocks;
856           return (True);
857         }
858       else return(False);
859     }
860
861   /* If softlimit is zero, set it equal to hardlimit.
862    */
863
864   if (D.dqb_bsoftlimit==0)
865     D.dqb_bsoftlimit = D.dqb_bhardlimit;
866
867   if (D.dqb_bsoftlimit==0)
868     return(False);
869   /* Use softlimit to determine disk space, except when it has been exceeded */
870   if ((D.dqb_curblocks>D.dqb_bsoftlimit)
871 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
872 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
873 #endif
874     ) {
875       *dfree = 0;
876       *dsize = D.dqb_curblocks;
877     }
878   else {
879     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
880     *dsize = D.dqb_bsoftlimit;
881   }
882   return (True);
883 }
884
885 #endif
886
887 #if defined(VXFS_QUOTA)
888
889 /****************************************************************************
890 Try to get the disk space from Veritas disk quotas.
891     David Lee <T.D.Lee@durham.ac.uk> August 1999.
892
893 Background assumptions:
894     Potentially under many Operating Systems.  Initially Solaris 2.
895
896     My guess is that Veritas is largely, though not entirely,
897     independent of OS.  So I have separated it out.
898
899     There may be some details.  For example, OS-specific "include" files.
900
901     It is understood that HPUX 10 somehow gets Veritas quotas without
902     any special effort; if so, this routine need not be compiled in.
903         Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
904
905 Warning:
906     It is understood that Veritas do not publicly support this ioctl interface.
907     Rather their preference would be for the user (us) to call the native
908     OS and then for the OS itself to call through to the VxFS filesystem.
909     Presumably HPUX 10, see above, does this.
910
911 Hints for porting:
912     Add your OS to "IFLIST" below.
913     Get it to compile successfully:
914         Almost certainly "include"s require attention: see SUNOS5.
915     In the main code above, arrange for it to be called: see SUNOS5.
916     Test!
917     
918 ****************************************************************************/
919
920 /* "IFLIST"
921  * This "if" is a list of ports:
922  *      if defined(OS1) || defined(OS2) || ...
923  */
924 #if defined(SUNOS5)
925
926 #if defined(SUNOS5)
927 #include <sys/fs/vx_solaris.h>
928 #endif
929 #include <sys/fs/vx_machdep.h>
930 #include <sys/fs/vx_layout.h>
931 #include <sys/fs/vx_quota.h>
932 #include <sys/fs/vx_aioctl.h>
933 #include <sys/fs/vx_ioctl.h>
934
935 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
936 {
937   uid_t user_id, euser_id;
938   int ret;
939   struct vx_dqblk D;
940   struct vx_quotctl quotabuf;
941   struct vx_genioctl genbuf;
942   pstring qfname;
943   int file;
944
945   /*
946    * "name" may or may not include a trailing "/quotas".
947    * Arranging consistency of calling here in "quotas.c" may not be easy and
948    * it might be easier to examine and adjust it here.
949    * Fortunately, VxFS seems not to mind at present.
950    */
951   pstrcpy(qfname, name) ;
952   /* pstrcat(qfname, "/quotas") ; */    /* possibly examine and adjust "name" */
953
954   euser_id = geteuid();
955   set_effective_uid(0);
956
957   DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
958   if((file=sys_open(qfname, O_RDONLY,0))<0) {
959     set_effective_uid(euser_id);
960     return(False);
961   }
962   genbuf.ioc_cmd = VX_QUOTACTL;
963   genbuf.ioc_up = (void *) &quotabuf;
964
965   quotabuf.cmd = VX_GETQUOTA;
966   quotabuf.uid = euser_id;
967   quotabuf.addr = (caddr_t) &D;
968   ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
969   close(file);
970
971   set_effective_uid(euser_id);
972
973   if (ret < 0) {
974     DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
975     return(False);
976   }
977
978   /* If softlimit is zero, set it equal to hardlimit.
979    */
980
981   if (D.dqb_bsoftlimit==0)
982     D.dqb_bsoftlimit = D.dqb_bhardlimit;
983
984   /* Use softlimit to determine disk space. A user exceeding the quota is told
985    * that there's no space left. Writes might actually work for a bit if the
986    * hardlimit is set higher than softlimit. Effectively the disk becomes
987    * made of rubber latex and begins to expand to accommodate the user :-)
988    */
989   DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
990          path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
991          D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
992
993   if (D.dqb_bsoftlimit==0)
994     return(False);
995   *bsize = DEV_BSIZE;
996   *dsize = D.dqb_bsoftlimit;
997
998   if (D.dqb_curblocks > D.dqb_bsoftlimit) {
999      *dfree = 0;
1000      *dsize = D.dqb_curblocks;
1001   } else
1002     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1003       
1004   DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",
1005          path,(double)*bsize,(double)*dfree,(double)*dsize));
1006
1007   return(True);
1008 }
1009
1010 #endif /* SUNOS5 || ... */
1011
1012 #endif /* VXFS_QUOTA */