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