Makefile: Split definitions for SGI4,5,6.
[kai/samba.git] / source / smbd / quotas.c
1 #ifdef QUOTAS
2 /* 
3    Unix SMB/Netbios implementation.
4    Version 1.9.
5    support for quotas
6    Copyright (C) Andrew Tridgell 1992-1997
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23
24 /* 
25  * This is one of the most system dependent parts of Samba, and its
26  * done a litle differently. Each system has its own way of doing 
27  * things :-(
28  */
29
30 #include "includes.h"
31
32 extern int DEBUGLEVEL;
33
34 #ifdef LINUX
35
36 #include <sys/types.h>
37 #include <asm/types.h>
38 #include <sys/quota.h>
39
40 #include <mntent.h>
41 #include <linux/unistd.h>
42
43 _syscall4(int, quotactl, int, cmd, const char *, special, int, id, caddr_t, addr);
44
45 /****************************************************************************
46 try to get the disk space from disk quotas (LINUX version)
47 ****************************************************************************/
48
49 BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
50 {
51   uid_t euser_id;
52   int r;
53   struct dqblk D;
54   struct stat S;
55   FILE *fp;
56   struct mntent *mnt;
57   int devno;
58   int found;
59   
60   /* find the block device file */
61   
62   if ( stat(path, &S) == -1 ) {
63     return(False) ;
64   }
65
66   devno = S.st_dev ;
67   
68   fp = setmntent(MOUNTED,"r");
69   found = False ;
70   
71   while ((mnt = getmntent(fp))) {
72     if ( stat(mnt->mnt_dir,&S) == -1 )
73       continue ;
74     if (S.st_dev == devno) {
75       found = True ;
76       break ;
77     }
78   }
79   endmntent(fp) ;
80   
81   if (!found) {
82       return(False);
83     }
84
85   euser_id=geteuid();
86   seteuid(0);  
87   r=quotactl(QCMD(Q_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D);
88       seteuid(euser_id);
89
90   /* Use softlimit to determine disk space, except when it has been exceeded */
91   *bsize = 1024;
92   if (r)
93     {
94       if (errno == EDQUOT) 
95        {
96          *dfree =0;
97          *dsize =D.dqb_curblocks;
98          return (True);
99     }
100       else return(False);
101   }
102   /* Use softlimit to determine disk space, except when it has been exceeded */
103   if (
104       (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
105       (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
106       (D.dqb_isoftlimit && D.dqb_curinodes>=D.dqb_isoftlimit) ||
107       (D.dqb_ihardlimit && D.dqb_curinodes>=D.dqb_ihardlimit)
108      )
109     {
110       *dfree = 0;
111       *dsize = D.dqb_curblocks;
112     }
113   else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
114     {
115       return(False);
116     }
117   else {
118     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
119     *dsize = D.dqb_bsoftlimit;
120   }
121   return (True);
122 }
123
124 #elif defined(CRAY)
125
126 #include <sys/quota.h>
127 #include <mntent.h>
128
129 /****************************************************************************
130 try to get the disk space from disk quotas (CRAY VERSION)
131 ****************************************************************************/
132 BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
133 {
134   struct mntent *mnt;
135   FILE *fd;
136   struct stat sbuf;
137   dev_t devno ;
138   static dev_t devno_cached = 0 ;
139   static char name[MNTMAXSTR] ;
140   struct q_request request ;
141   struct qf_header header ;
142   static int quota_default = 0 ;
143   int found ;
144   
145   if ( stat(path,&sbuf) == -1 )
146     return(False) ;
147   
148   devno = sbuf.st_dev ;
149   
150   if ( devno != devno_cached ) {
151     
152     devno_cached = devno ;
153     
154     if ((fd = setmntent(KMTAB)) == NULL)
155       return(False) ;
156     
157     found = False ;
158     
159     while ((mnt = getmntent(fd)) != NULL) {
160       
161       if ( stat(mnt->mnt_dir,&sbuf) == -1 )
162         continue ;
163       
164       if (sbuf.st_dev == devno) {
165         
166         found = True ;
167         break ;
168         
169       }
170       
171     }
172     
173     strcpy(name,mnt->mnt_dir) ;
174     endmntent(fd) ;
175     
176     if ( ! found )
177       return(False) ;
178   }
179   
180   request.qf_magic = QF_MAGIC ;
181   request.qf_entry.id = geteuid() ;
182   
183   if (quotactl(name, Q_GETQUOTA, &request) == -1)
184     return(False) ;
185   
186   if ( ! request.user )
187     return(False) ;
188   
189   if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
190     
191     if ( ! quota_default ) {
192       
193       if ( quotactl(name, Q_GETHEADER, &header) == -1 )
194         return(False) ;
195       else
196         quota_default = header.user_h.def_fq ;
197     }
198     
199     *dfree = quota_default ;
200     
201   }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
202     
203     *dfree = 0 ;
204     
205   }else{
206     
207     *dfree = request.qf_entry.user_q.f_quota ;
208     
209   }
210   
211   *dsize = request.qf_entry.user_q.f_use ;
212   
213   if ( *dfree )
214     *dfree -= *dsize ;
215   
216   if ( *dfree < 0 )
217     *dfree = 0 ;
218   
219   *bsize = 4096 ;  /* Cray blocksize */
220   
221   return(True) ;
222   
223 }
224
225
226 #elif defined(SUNOS5) || defined(SUNOS4)
227
228 #include <fcntl.h>
229 #if defined(SUNOS5)
230 #include <sys/fs/ufs_quota.h>
231 #include <sys/mnttab.h>
232 #else /* defined(SUNOS4) */
233 #include <ufs/quota.h>
234 #include <mntent.h>
235 #endif
236
237 /****************************************************************************
238 try to get the disk space from disk quotas (solaris 2 version)
239 ****************************************************************************/
240 /* Quota code by Peter Urbanec (amiga@cse.unsw.edu.au) */
241 BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
242 {
243   uid_t user_id, euser_id;
244   int ret;
245   struct dqblk D;
246 #if defined(SUNOS5)
247   struct quotctl command;
248   int file;
249   struct mnttab mnt;
250   static char name[MNT_LINE_MAX] ;
251 #else
252   struct mntent *mnt;
253   static char name[MNTMAXSTR] ;
254 #endif
255   FILE *fd;
256   struct stat sbuf;
257   dev_t devno ;
258   static dev_t devno_cached = 0 ;
259   int found ;
260   
261   if ( stat(path,&sbuf) == -1 )
262     return(False) ;
263   
264   devno = sbuf.st_dev ;
265   DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%o\n", path,devno));
266   if ( devno != devno_cached ) {
267     devno_cached = devno ;
268 #if defined(SUNOS5)
269     if ((fd = fopen(MNTTAB, "r")) == NULL)
270       return(False) ;
271     
272     found = False ;
273     while (getmntent(fd, &mnt) == 0) {
274       if ( stat(mnt.mnt_mountp,&sbuf) == -1 )
275         continue ;
276       DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n", 
277                mnt.mnt_mountp,sbuf.st_dev));
278       if (sbuf.st_dev == devno) {
279         found = True ;
280         break ;
281       }
282     }
283     
284     strcpy(name,mnt.mnt_mountp) ;
285     strcat(name,"/quotas") ;
286     fclose(fd) ;
287 #else
288     if ((fd = setmntent(MOUNTED, "r")) == NULL)
289       return(False) ;
290     
291     found = False ;
292     while ((mnt = getmntent(fd)) != NULL) {
293       if ( stat(mnt->mnt_dir,&sbuf) == -1 )
294         continue ;
295       DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n", 
296                mnt->mnt_dir,sbuf.st_dev));
297       if (sbuf.st_dev == devno) {
298         found = True ;
299         break ;
300       }
301     }
302     
303     strcpy(name,mnt->mnt_fsname) ;
304     endmntent(fd) ;
305 #endif
306     
307     if ( ! found )
308       return(False) ;
309   }
310
311   euser_id = geteuid();
312   user_id = getuid();
313
314   setuid(0);  /* Solaris seems to want to give info only to super-user */
315   seteuid(0);
316
317 #if defined(SUNOS5)
318   DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
319   if((file=open(name, O_RDONLY))<0) {
320     setuid(user_id);  /* Restore the original UID status */
321     seteuid(euser_id);
322     return(False);
323   }
324   command.op = Q_GETQUOTA;
325   command.uid = euser_id;
326   command.addr = (caddr_t) &D;
327   ret = ioctl(file, Q_QUOTACTL, &command);
328   close(file);
329 #else
330   DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
331   ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
332 #endif
333
334   setuid(user_id); /* Restore the original uid status. */
335   seteuid(euser_id);
336
337   if (ret < 0) {
338     DEBUG(2,("disk_quotas ioctl (Solaris) failed\n"));
339     return(False);
340   }
341
342
343   /* Use softlimit to determine disk space. A user exceeding the quota is told
344    * that there's no space left. Writes might actually work for a bit if the
345    * hardlimit is set higher than softlimit. Effectively the disk becomes
346    * made of rubber latex and begins to expand to accommodate the user :-)
347    */
348
349   if (D.dqb_bsoftlimit==0)
350     return(False);
351   *bsize = 512;
352   *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
353   *dsize = D.dqb_bsoftlimit;
354   if(*dfree < 0)
355     {
356      *dfree = 0;
357      *dsize = D.dqb_curblocks;
358     }
359       
360 DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %d, dfree %d, dsize %d\n",
361          path,*bsize,*dfree,*dsize));
362
363       return(True);
364 }
365
366
367 #elif defined(OSF1)
368 #include <ufs/quota.h>
369
370 /****************************************************************************
371 try to get the disk space from disk quotas - OFS1 version
372 ****************************************************************************/
373 BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
374 {
375   uid_t user_id, euser_id;
376   int r, save_errno;
377   struct dqblk D;
378   struct stat S;
379
380   euser_id = geteuid();
381   user_id = getuid();
382
383   setreuid(euser_id, -1);
384   r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
385   if (r)
386      save_errno = errno;
387
388   if (setreuid(user_id, -1) == -1)
389     DEBUG(5,("Unable to reset uid to %d\n", user_id));
390
391   *bsize = DEV_BSIZE;
392
393   if (r)
394   {
395       if (save_errno == EDQUOT)   // disk quota exceeded
396       {
397          *dfree = 0;
398          *dsize = D.dqb_curblocks;
399          return (True);
400       }
401       else
402          return (False);  
403   }
404
405   /* Use softlimit to determine disk space, except when it has been exceeded */
406
407   if (D.dqb_bsoftlimit==0)
408     return(False);
409
410   if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
411     *dfree = 0;
412     *dsize = D.dqb_curblocks;
413   } else {
414     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
415     *dsize = D.dqb_bsoftlimit;
416   }
417   return (True);
418 }
419
420 #elif defined (SGI6)
421 /****************************************************************************
422 try to get the disk space from disk quotas (IRIX 6.2 version)
423 ****************************************************************************/
424
425 #include <sys/quota.h>
426 #include <mntent.h>
427
428 BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
429 {
430   uid_t euser_id;
431   int r;
432   struct dqblk D;
433   struct fs_disk_quota        F;
434   struct stat S;
435   FILE *fp;
436   struct mntent *mnt;
437   int devno;
438   int found;
439   
440   /* find the block device file */
441   
442   if ( stat(path, &S) == -1 ) {
443     return(False) ;
444   }
445
446   devno = S.st_dev ;
447   
448   fp = setmntent(MOUNTED,"r");
449   found = False ;
450   
451   while ((mnt = getmntent(fp))) {
452     if ( stat(mnt->mnt_dir,&S) == -1 )
453       continue ;
454     if (S.st_dev == devno) {
455       found = True ;
456       break ;
457     }
458   }
459   endmntent(fp) ;
460   
461   if (!found) {
462     return(False);
463   }
464
465   euser_id=geteuid();
466   seteuid(0);  
467
468   /* Use softlimit to determine disk space, except when it has been exceeded */
469
470   *bsize = 512;
471
472   if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
473   {
474     r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
475
476     if (r==-1)
477       return(False);
478         
479     /* Use softlimit to determine disk space, except when it has been exceeded */
480     if (
481         (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
482         (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
483         (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
484         (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
485        )
486     {
487       *dfree = 0;
488       *dsize = D.dqb_curblocks;
489     }
490     else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
491     {
492       return(False);
493     }
494     else 
495     {
496       *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
497       *dsize = D.dqb_bsoftlimit;
498     }
499
500   }
501   else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
502   {
503     r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
504
505     if (r==-1)
506       return(False);
507         
508     /* Use softlimit to determine disk space, except when it has been exceeded */
509     if (
510         (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
511         (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
512         (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
513         (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
514        )
515     {
516       /*
517        * Fixme!: these are __uint64_t, this may truncate values
518        */
519       *dfree = 0;
520       *dsize = (int) F.d_bcount;
521     }
522     else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
523     {
524       return(False);
525     }
526     else 
527     {
528       *dfree = (int)(F.d_blk_softlimit - F.d_bcount);
529       *dsize = (int)F.d_blk_softlimit;
530     }
531
532   }
533   else
534     return(False);
535
536   return (True);
537
538 }
539
540 #else
541
542 #ifdef        __FreeBSD__
543 #include <ufs/ufs/quota.h>
544 #include <machine/param.h>
545 #elif         AIX
546 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
547 #include <jfs/quota.h>
548 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
549 #define dqb_curfiles dqb_curinodes
550 #define dqb_fhardlimit dqb_ihardlimit
551 #define dqb_fsoftlimit dqb_isoftlimit
552 #else /* !__FreeBSD__ && !AIX */
553 #include <sys/quota.h>
554 #include <devnm.h>
555 #endif
556
557 /****************************************************************************
558 try to get the disk space from disk quotas - default version
559 ****************************************************************************/
560 BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
561 {
562   uid_t euser_id;
563   int r;
564   struct dqblk D;
565 #if !defined(__FreeBSD__) && !defined(AIX)
566   char dev_disk[256];
567   struct stat S;
568   /* find the block device file */
569   if ((stat(path, &S)<0) ||
570       (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
571 #endif
572
573   euser_id = geteuid();
574
575 #ifdef USE_SETRES
576   {
577     uid_t user_id;
578
579     /* for HPUX, real uid must be same as euid to execute quotactl for euid */
580     user_id = getuid();
581     setresuid(euser_id,-1,-1);
582     r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
583     if (setresuid(user_id,-1,-1))
584       DEBUG(5,("Unable to reset uid to %d\n", user_id));
585   }
586 #else /* USE_SETRES */
587 #if defined(__FreeBSD__)
588   {
589     /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
590     uid_t user_id;
591     gid_t egrp_id;
592  
593     /* Need to be root to get quotas in FreeBSD */
594     user_id = getuid();
595     egrp_id = getegid();
596     setuid(0);
597     seteuid(0);
598     r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
599
600     /* As FreeBSD has group quotas, if getting the user
601        quota fails, try getting the group instead. */
602     if (r)
603       r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
604     setuid(user_id);
605     seteuid(euser_id);
606   }
607 #elif defined(AIX)
608   /* AIX has both USER and GROUP quotas: 
609      Get the USER quota (ohnielse@fysik.dtu.dk) */
610   r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
611 #else /* !__FreeBSD__ && !AIX */
612   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
613 #endif /* !__FreeBSD__ && !AIX */
614 #endif /* USE_SETRES */
615
616   /* Use softlimit to determine disk space, except when it has been exceeded */
617 #if defined(__FreeBSD__)
618   *bsize = DEV_BSIZE;
619 #else /* !__FreeBSD__ */
620   *bsize = 1024;
621 #endif /*!__FreeBSD__ */
622
623   if (r)
624     {
625       if (errno == EDQUOT) 
626         {
627           *dfree =0;
628           *dsize =D.dqb_curblocks;
629           return (True);
630         }
631       else return(False);
632     }
633   if (D.dqb_bsoftlimit==0)
634     return(False);
635   /* Use softlimit to determine disk space, except when it has been exceeded */
636   if ((D.dqb_curblocks>D.dqb_bsoftlimit)
637 #if !defined(__FreeBSD__)
638 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
639 #endif
640     ) {
641       *dfree = 0;
642       *dsize = D.dqb_curblocks;
643     }
644   else {
645     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
646     *dsize = D.dqb_bsoftlimit;
647   }
648   return (True);
649 }
650
651 #endif
652
653 #else
654 /* this keeps fussy compilers happy */
655  void quotas_dummy(void) {}
656 #endif /* QUOTAS */
657