Ok - this is the 64 bit widening check in. It changes the configure
[jra/samba/.git] / source3 / 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-1998
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   SMB_STRUCT_STAT S;
55   FILE *fp;
56   struct mntent *mnt;
57   SMB_DEV_T devno;
58   int found;
59   
60   /* find the block device file */
61   
62   if ( sys_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 ( sys_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     if (D.dqb_bsoftlimit == 0)
119       D.dqb_bsoftlimit = D.dqb_bhardlimit;
120     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
121     *dsize = D.dqb_bsoftlimit;
122   }
123   return (True);
124 }
125
126 #elif defined(CRAY)
127
128 #include <sys/quota.h>
129 #include <mntent.h>
130
131 /****************************************************************************
132 try to get the disk space from disk quotas (CRAY VERSION)
133 ****************************************************************************/
134 BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
135 {
136   struct mntent *mnt;
137   FILE *fd;
138   SMB_STRUCT_STAT sbuf;
139   SMB_DEV_T devno ;
140   static SMB_DEV_T devno_cached = 0 ;
141   static pstring name;
142   struct q_request request ;
143   struct qf_header header ;
144   static int quota_default = 0 ;
145   int found ;
146   
147   if ( sys_stat(path,&sbuf) == -1 )
148     return(False) ;
149   
150   devno = sbuf.st_dev ;
151   
152   if ( devno != devno_cached ) {
153     
154     devno_cached = devno ;
155     
156     if ((fd = setmntent(KMTAB)) == NULL)
157       return(False) ;
158     
159     found = False ;
160     
161     while ((mnt = getmntent(fd)) != NULL) {
162       
163       if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
164         continue ;
165       
166       if (sbuf.st_dev == devno) {
167         
168         found = True ;
169         break ;
170         
171       }
172       
173     }
174     
175     pstrcpy(name,mnt->mnt_dir) ;
176     endmntent(fd) ;
177     
178     if ( ! found )
179       return(False) ;
180   }
181   
182   request.qf_magic = QF_MAGIC ;
183   request.qf_entry.id = geteuid() ;
184   
185   if (quotactl(name, Q_GETQUOTA, &request) == -1)
186     return(False) ;
187   
188   if ( ! request.user )
189     return(False) ;
190   
191   if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
192     
193     if ( ! quota_default ) {
194       
195       if ( quotactl(name, Q_GETHEADER, &header) == -1 )
196         return(False) ;
197       else
198         quota_default = header.user_h.def_fq ;
199     }
200     
201     *dfree = quota_default ;
202     
203   }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
204     
205     *dfree = 0 ;
206     
207   }else{
208     
209     *dfree = request.qf_entry.user_q.f_quota ;
210     
211   }
212   
213   *dsize = request.qf_entry.user_q.f_use ;
214   
215   if ( *dfree )
216     *dfree -= *dsize ;
217   
218   if ( *dfree < 0 )
219     *dfree = 0 ;
220   
221   *bsize = 4096 ;  /* Cray blocksize */
222   
223   return(True) ;
224   
225 }
226
227
228 #elif defined(SUNOS5) || defined(SUNOS4)
229
230 #include <fcntl.h>
231 #if defined(SUNOS5)
232 #include <sys/fs/ufs_quota.h>
233 #include <sys/mnttab.h>
234 #else /* defined(SUNOS4) */
235 #include <ufs/quota.h>
236 #include <mntent.h>
237 #endif
238
239 /****************************************************************************
240 try to get the disk space from disk quotas (solaris 2 version)
241 ****************************************************************************/
242 /* Quota code by Peter Urbanec (amiga@cse.unsw.edu.au) */
243 BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
244 {
245   uid_t user_id, euser_id;
246   int ret;
247   struct dqblk D;
248 #if defined(SUNOS5)
249   struct quotctl command;
250   int file;
251   struct mnttab mnt;
252   static pstring name;
253 #else
254   struct mntent *mnt;
255   static pstring name;
256 #endif
257   FILE *fd;
258   SMB_STRUCT_STAT sbuf;
259   SMB_DEV_T devno ;
260   static SMB_DEV_T devno_cached = 0 ;
261   int found ;
262   
263   if ( sys_stat(path,&sbuf) == -1 )
264     return(False) ;
265   
266   devno = sbuf.st_dev ;
267   DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%o\n", path,devno));
268   if ( devno != devno_cached ) {
269     devno_cached = devno ;
270 #if defined(SUNOS5)
271     if ((fd = fopen(MNTTAB, "r")) == NULL)
272       return(False) ;
273     
274     found = False ;
275     while (getmntent(fd, &mnt) == 0) {
276       if ( sys_stat(mnt.mnt_mountp,&sbuf) == -1 )
277         continue ;
278       DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n", 
279                mnt.mnt_mountp,sbuf.st_dev));
280       if (sbuf.st_dev == devno) {
281         found = True ;
282         break ;
283       }
284     }
285     
286     pstrcpy(name,mnt.mnt_mountp) ;
287     pstrcat(name,"/quotas") ;
288     fclose(fd) ;
289 #else
290     if ((fd = setmntent(MOUNTED, "r")) == NULL)
291       return(False) ;
292     
293     found = False ;
294     while ((mnt = getmntent(fd)) != NULL) {
295       if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
296         continue ;
297       DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n", 
298                mnt->mnt_dir,sbuf.st_dev));
299       if (sbuf.st_dev == devno) {
300         found = True ;
301         break ;
302       }
303     }
304     
305     pstrcpy(name,mnt->mnt_fsname) ;
306     endmntent(fd) ;
307 #endif
308     
309     if ( ! found )
310       return(False) ;
311   }
312
313   euser_id = geteuid();
314   user_id = getuid();
315
316   setuid(0);  /* Solaris seems to want to give info only to super-user */
317   seteuid(0);
318
319 #if defined(SUNOS5)
320   DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
321   if((file=open(name, O_RDONLY))<0) {
322     setuid(user_id);  /* Restore the original UID status */
323     seteuid(euser_id);
324     return(False);
325   }
326   command.op = Q_GETQUOTA;
327   command.uid = euser_id;
328   command.addr = (caddr_t) &D;
329   ret = ioctl(file, Q_QUOTACTL, &command);
330   close(file);
331 #else
332   DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
333   ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
334 #endif
335
336   setuid(user_id); /* Restore the original uid status. */
337   seteuid(euser_id);
338
339   if (ret < 0) {
340     DEBUG(2,("disk_quotas ioctl (Solaris) failed\n"));
341     return(False);
342   }
343
344
345   /* Use softlimit to determine disk space. A user exceeding the quota is told
346    * that there's no space left. Writes might actually work for a bit if the
347    * hardlimit is set higher than softlimit. Effectively the disk becomes
348    * made of rubber latex and begins to expand to accommodate the user :-)
349    */
350
351   if (D.dqb_bsoftlimit==0)
352     return(False);
353   *bsize = 512;
354   *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
355   *dsize = D.dqb_bsoftlimit;
356   if(*dfree < 0)
357     {
358      *dfree = 0;
359      *dsize = D.dqb_curblocks;
360     }
361       
362 DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %d, dfree %d, dsize %d\n",
363          path,*bsize,*dfree,*dsize));
364
365       return(True);
366 }
367
368
369 #elif defined(OSF1)
370 #include <ufs/quota.h>
371
372 /****************************************************************************
373 try to get the disk space from disk quotas - OFS1 version
374 ****************************************************************************/
375 BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
376 {
377   uid_t user_id, euser_id;
378   int r, save_errno;
379   struct dqblk D;
380   SMB_STRUCT_STAT S;
381
382   euser_id = geteuid();
383   user_id = getuid();
384
385   setreuid(euser_id, -1);
386   r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
387   if (r)
388      save_errno = errno;
389
390   if (setreuid(user_id, -1) == -1)
391     DEBUG(5,("Unable to reset uid to %d\n", user_id));
392
393   *bsize = DEV_BSIZE;
394
395   if (r)
396   {
397       if (save_errno == EDQUOT)   // disk quota exceeded
398       {
399          *dfree = 0;
400          *dsize = D.dqb_curblocks;
401          return (True);
402       }
403       else
404          return (False);  
405   }
406
407   /* Use softlimit to determine disk space, except when it has been exceeded */
408
409   if (D.dqb_bsoftlimit==0)
410     return(False);
411
412   if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
413     *dfree = 0;
414     *dsize = D.dqb_curblocks;
415   } else {
416     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
417     *dsize = D.dqb_bsoftlimit;
418   }
419   return (True);
420 }
421
422 #elif defined (SGI6)
423 /****************************************************************************
424 try to get the disk space from disk quotas (IRIX 6.2 version)
425 ****************************************************************************/
426
427 #include <sys/quota.h>
428 #include <mntent.h>
429
430 BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
431 {
432   uid_t euser_id;
433   int r;
434   struct dqblk D;
435   struct fs_disk_quota        F;
436   SMB_STRUCT_STAT S;
437   FILE *fp;
438   struct mntent *mnt;
439   SMB_DEV_T devno;
440   int found;
441   
442   /* find the block device file */
443   
444   if ( sys_stat(path, &S) == -1 ) {
445     return(False) ;
446   }
447
448   devno = S.st_dev ;
449   
450   fp = setmntent(MOUNTED,"r");
451   found = False ;
452   
453   while ((mnt = getmntent(fp))) {
454     if ( sys_stat(mnt->mnt_dir,&S) == -1 )
455       continue ;
456     if (S.st_dev == devno) {
457       found = True ;
458       break ;
459     }
460   }
461   endmntent(fp) ;
462   
463   if (!found) {
464     return(False);
465   }
466
467   euser_id=geteuid();
468   seteuid(0);  
469
470   /* Use softlimit to determine disk space, except when it has been exceeded */
471
472   *bsize = 512;
473
474   if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
475   {
476     r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
477
478     seteuid(euser_id); /* Restore the original uid status. */
479
480     if (r==-1)
481       return(False);
482         
483     /* Use softlimit to determine disk space, except when it has been exceeded */
484     if (
485         (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
486         (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
487         (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
488         (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
489        )
490     {
491       *dfree = 0;
492       *dsize = D.dqb_curblocks;
493     }
494     else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
495     {
496       return(False);
497     }
498     else 
499     {
500       *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
501       *dsize = D.dqb_bsoftlimit;
502     }
503
504   }
505   else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
506   {
507     r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
508
509     seteuid(euser_id); /* Restore the original uid status. */
510
511     if (r==-1)
512       return(False);
513         
514     /* Use softlimit to determine disk space, except when it has been exceeded */
515     if (
516         (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
517         (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
518         (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
519         (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
520        )
521     {
522       /*
523        * Fixme!: these are __uint64_t, this may truncate values
524        */
525       *dfree = 0;
526       *dsize = (int) F.d_bcount;
527     }
528     else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
529     {
530       return(False);
531     }
532     else 
533     {
534       *dfree = (int)(F.d_blk_softlimit - F.d_bcount);
535       *dsize = (int)F.d_blk_softlimit;
536     }
537
538   }
539   else
540   {
541     seteuid(euser_id); /* Restore the original uid status. */
542     return(False);
543   }
544
545   return (True);
546
547 }
548
549 #else
550
551 #if    defined(__FreeBSD__) || defined(__OpenBSD__)
552 #include <ufs/ufs/quota.h>
553 #include <machine/param.h>
554 #elif         AIX
555 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
556 #include <jfs/quota.h>
557 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
558 #define dqb_curfiles dqb_curinodes
559 #define dqb_fhardlimit dqb_ihardlimit
560 #define dqb_fsoftlimit dqb_isoftlimit
561 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
562 #include <sys/quota.h>
563 #include <devnm.h>
564 #endif
565
566 /****************************************************************************
567 try to get the disk space from disk quotas - default version
568 ****************************************************************************/
569 BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
570 {
571   uid_t euser_id;
572   int r;
573   struct dqblk D;
574 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
575   char dev_disk[256];
576   SMB_STRUCT_STAT S;
577   /* find the block device file */
578   if ((sys_stat(path, &S)<0) ||
579       (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
580 #endif
581
582   euser_id = geteuid();
583
584 #ifdef HPUX
585   {
586     uid_t user_id;
587
588     /* for HPUX, real uid must be same as euid to execute quotactl for euid */
589     user_id = getuid();
590     setresuid(euser_id,-1,-1);
591     r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
592     if (setresuid(user_id,-1,-1))
593       DEBUG(5,("Unable to reset uid to %d\n", user_id));
594   }
595 #else 
596 #if defined(__FreeBSD__) || defined(__OpenBSD__)
597   {
598     /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
599     uid_t user_id;
600     gid_t egrp_id;
601  
602     /* Need to be root to get quotas in FreeBSD */
603     user_id = getuid();
604     egrp_id = getegid();
605     setuid(0);
606     seteuid(0);
607     r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
608
609     /* As FreeBSD has group quotas, if getting the user
610        quota fails, try getting the group instead. */
611     if (r)
612       r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
613     setuid(user_id);
614     seteuid(euser_id);
615   }
616 #elif defined(AIX)
617   /* AIX has both USER and GROUP quotas: 
618      Get the USER quota (ohnielse@fysik.dtu.dk) */
619   r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
620 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
621   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
622 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
623 #endif /* HAVE_SETRES */
624
625   /* Use softlimit to determine disk space, except when it has been exceeded */
626 #if defined(__FreeBSD__) || defined(__OpenBSD__)
627   *bsize = DEV_BSIZE;
628 #else /* !__FreeBSD__ && !__OpenBSD__ */
629   *bsize = 1024;
630 #endif /*!__FreeBSD__ && !__OpenBSD__ */
631
632   if (r)
633     {
634       if (errno == EDQUOT) 
635         {
636           *dfree =0;
637           *dsize =D.dqb_curblocks;
638           return (True);
639         }
640       else return(False);
641     }
642   if (D.dqb_bsoftlimit==0)
643     return(False);
644   /* Use softlimit to determine disk space, except when it has been exceeded */
645   if ((D.dqb_curblocks>D.dqb_bsoftlimit)
646 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
647 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
648 #endif
649     ) {
650       *dfree = 0;
651       *dsize = D.dqb_curblocks;
652     }
653   else {
654     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
655     *dsize = D.dqb_bsoftlimit;
656   }
657   return (True);
658 }
659
660 #endif
661
662 #else
663 /* this keeps fussy compilers happy */
664  void quotas_dummy(void) {}
665 #endif /* QUOTAS */
666