d5be15264e7452bd3861bee06da8b05bc70259d1
[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-1995
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
33 #ifdef LINUX
34
35 #ifdef __KERNEL__
36 # undef __KERNEL__
37 # include <sys/quota.h>
38 # define __KERNEL__
39 #else
40 # include <sys/quota.h>
41 #endif
42
43 #include <mntent.h>
44
45 /****************************************************************************
46 try to get the disk space from disk quotas (LINUX version)
47 ****************************************************************************/
48 /*
49 If you didn't make the symlink to the quota package, too bad :(
50 */
51 #include "quota/quotactl.c"
52 #include "quota/hasquota.c"
53 static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
54 {
55   uid_t euser_id;
56   struct dqblk D;
57   struct stat S;
58   dev_t devno ;
59   struct mntent *mnt;
60   FILE *fp;
61   int found ;
62   int qcmd, fd ;
63   char *qfpathname;
64   
65   /* find the block device file */
66   
67   if ( stat(path, &S) == -1 )
68     return(False) ;
69
70   devno = S.st_dev ;
71   
72   fp = setmntent(MOUNTED,"r");
73   found = False ;
74   
75   while ((mnt = getmntent(fp)) != (struct mntent *) 0) {
76     if ( stat(mnt->mnt_dir,&S) == -1 )
77       continue ;
78     if (S.st_dev == devno) {
79       found = True ;
80       break ;
81     }
82   }
83   endmntent(fp) ;
84   
85   if ( ! found )
86     return(False) ;
87   
88   qcmd = QCMD(Q_GETQUOTA, USRQUOTA);
89   
90   if (hasmntopt(mnt, MNTOPT_NOAUTO) || hasmntopt(mnt, MNTOPT_NOQUOTA))
91     return(False) ;
92   
93   if (!hasquota(mnt, USRQUOTA, &qfpathname))
94     return(False) ;
95   
96   euser_id = geteuid();
97   seteuid(0);
98   
99   if (quotactl(qcmd, mnt->mnt_fsname, euser_id, (caddr_t)&D) != 0) {
100     if ((fd = open(qfpathname, O_RDONLY)) < 0) {
101       seteuid(euser_id);
102       return(False);
103     }
104     lseek(fd, (long) dqoff(euser_id), L_SET);
105     switch (read(fd, &D, sizeof(struct dqblk))) {
106     case 0:/* EOF */
107       memset((caddr_t)&D, 0, sizeof(struct dqblk));
108       break;
109     case sizeof(struct dqblk):   /* OK */
110       break;
111     default:   /* ERROR */
112       close(fd);
113       seteuid(euser_id);
114       return(False);
115     }
116   }
117   seteuid(euser_id);
118   *bsize=1024;
119
120   if (D.dqb_bsoftlimit==0)
121     return(False);
122   if ((D.dqb_curblocks>D.dqb_bsoftlimit)||(D.dqb_curinodes>D.dqb_isoftlimit))
123     {
124       *dfree = 0;
125       *dsize = D.dqb_curblocks;
126     }
127   else {
128     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
129     *dsize = D.dqb_bsoftlimit;
130   }
131   return (True);
132 }
133
134 #elif defined(CRAY)
135
136 #include <sys/quota.h>
137 #include <mntent.h>
138
139 /****************************************************************************
140 try to get the disk space from disk quotas (CRAY VERSION)
141 ****************************************************************************/
142 static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
143 {
144   struct mntent *mnt;
145   FILE *fd;
146   struct stat sbuf;
147   dev_t devno ;
148   static dev_t devno_cached = 0 ;
149   static char name[MNTMAXSTR] ;
150   struct q_request request ;
151   struct qf_header header ;
152   static int quota_default = 0 ;
153   int found ;
154   
155   if ( stat(path,&sbuf) == -1 )
156     return(False) ;
157   
158   devno = sbuf.st_dev ;
159   
160   if ( devno != devno_cached ) {
161     
162     devno_cached = devno ;
163     
164     if ((fd = setmntent(KMTAB)) == NULL)
165       return(False) ;
166     
167     found = False ;
168     
169     while ((mnt = getmntent(fd)) != NULL) {
170       
171       if ( stat(mnt->mnt_dir,&sbuf) == -1 )
172         continue ;
173       
174       if (sbuf.st_dev == devno) {
175         
176         found = True ;
177         break ;
178         
179       }
180       
181     }
182     
183     strcpy(name,mnt->mnt_dir) ;
184     endmntent(fd) ;
185     
186     if ( ! found )
187       return(False) ;
188   }
189   
190   request.qf_magic = QF_MAGIC ;
191   request.qf_entry.id = geteuid() ;
192   
193   if (quotactl(name, Q_GETQUOTA, &request) == -1)
194     return(False) ;
195   
196   if ( ! request.user )
197     return(False) ;
198   
199   if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
200     
201     if ( ! quota_default ) {
202       
203       if ( quotactl(name, Q_GETHEADER, &header) == -1 )
204         return(False) ;
205       else
206         quota_default = header.user_h.def_fq ;
207     }
208     
209     *dfree = quota_default ;
210     
211   }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
212     
213     *dfree = 0 ;
214     
215   }else{
216     
217     *dfree = request.qf_entry.user_q.f_quota ;
218     
219   }
220   
221   *dsize = request.qf_entry.user_q.f_use ;
222   
223   if ( *dfree )
224     *dfree -= *dsize ;
225   
226   if ( *dfree < 0 )
227     *dfree = 0 ;
228   
229   *bsize = 4096 ;  /* Cray blocksize */
230   
231   return(True) ;
232   
233 }
234
235
236 #elif defined(SUNOS5)
237
238 #include <devnm.h>
239 #include <fcntl.h>
240 #include <sys/fs/ufs_quota.h>
241
242 /****************************************************************************
243 try to get the disk space from disk quotas (solaris 2 version)
244 ****************************************************************************/
245 /* Quota code by Peter Urbanec (amiga@cse.unsw.edu.au) */
246 static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
247 {
248   uid_t user_id, euser_id;
249   int r;
250   struct dqblk D;
251   struct quotctl command;
252   int file;
253   int ret;
254  
255   if((file=open(path, O_RDONLY))<0) return(False);
256
257   euser_id = geteuid();
258   user_id = getuid();
259
260   command.op = Q_GETQUOTA;
261   command.uid = euser_id;
262   command.addr = (caddr_t) &D;
263  
264   setuid(0);  /* Solaris seems to want to give info only to super-user */
265   seteuid(0);
266
267   ret = ioctl(file, Q_QUOTACTL, &command);
268
269   setuid(user_id);  /* Restore the original UID status */
270   seteuid(euser_id);
271
272   if (ret < 0) {
273     close(file);
274     DEBUG(2,("disk_quotas ioctl (Solaris) failed\n"));
275     return(False);
276   }
277   close(file);
278
279
280   /* Use softlimit to determine disk space. A user exceeding the quota is told
281    * that there's no space left. Writes might actually work for a bit if the
282    * hardlimit is set higher than softlimit. Effectively the disk becomes
283    * made of rubber latex and begins to expand to accommodate the user :-)
284    */
285
286   *bsize = 512;
287   *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
288   *dsize = D.dqb_bsoftlimit;
289   if(*dfree < 0)
290     {
291      *dfree = 0;
292      *dsize = D.dqb_curblocks;
293     }
294       
295 DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %d, dfree %d, dsize %d\n",
296          path,*bsize,*dfree,*dsize));
297
298       return(True);
299 }
300
301 #else
302
303 #include <sys/quota.h>
304 #include <devnm.h>
305
306 /****************************************************************************
307 try to get the disk space from disk quotas - default version
308 ****************************************************************************/
309 static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
310 {
311   uid_t user_id, euser_id;
312   int r;
313   char dev_disk[256];
314   struct dqblk D;
315   struct stat S;
316   /* find the block device file */
317   if ((stat(path, &S)<0) ||
318       (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
319
320   euser_id = geteuid();
321
322 #ifdef USE_SETRES
323   /* for HPUX, real uid must be same as euid to execute quotactl for euid */
324   user_id = getuid();
325   setresuid(euser_id,-1,-1);
326 #endif
327   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
328   #ifdef USE_SETRES
329   if (setresuid(user_id,-1,-1))
330     DEBUG(5,("Unable to reset uid to %d\n", user_id));
331   #endif
332   /* Use softlimit to determine disk space, except when it has been exceeded */
333   *bsize = 1024;
334   if (r)
335     {
336       if (errno == EDQUOT) 
337         {
338           *dfree =0;
339           *dsize =D.dqb_curblocks;
340           return (True);
341         }
342       else return(False);
343     }
344   /* Use softlimit to determine disk space, except when it has been exceeded */
345   if ((D.dqb_curblocks>D.dqb_bsoftlimit)||(D.dqb_curfiles>D.dqb_fsoftlimit)) 
346     {
347       *dfree = 0;
348       *dsize = D.dqb_curblocks;
349     }
350   else {
351     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
352     *dsize = D.dqb_bsoftlimit;
353   }
354   return (True);
355 }
356
357 #endif
358
359 #else
360 /* this keeps fussy compilers happy */
361  void quotas_dummy(void) {}
362 #endif /* QUOTAS */
363