67b158f80df405fb6576294db22335a9a0018c7d
[amitay/samba.git] / source3 / lib / sysquotas.c
1 /* 
2    Unix SMB/CIFS implementation.
3    System QUOTA function wrappers
4    Copyright (C) Stefan (metze) Metzmacher      2003
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 3 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, see <http://www.gnu.org/licenses/>.
18 */
19
20
21 #include "includes.h"
22
23 #undef DBGC_CLASS
24 #define DBGC_CLASS DBGC_QUOTA
25
26 #ifdef HAVE_SYS_QUOTAS
27
28 #if defined(HAVE_QUOTACTL_4A) 
29
30 /*#endif HAVE_QUOTACTL_4A */
31 #elif defined(HAVE_QUOTACTL_4B)
32
33 #error HAVE_QUOTACTL_4B not implemeted
34
35 /*#endif HAVE_QUOTACTL_4B */
36 #elif defined(HAVE_QUOTACTL_3)
37
38 #error HAVE_QUOTACTL_3 not implemented
39
40 /* #endif  HAVE_QUOTACTL_3 */
41 #else /* NO_QUOTACTL_USED */
42
43 #endif /* NO_QUOTACTL_USED */
44
45 #ifdef HAVE_MNTENT
46 static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
47 {
48         int ret = -1;
49         SMB_STRUCT_STAT S;
50         FILE *fp;
51         struct mntent *mnt;
52         SMB_DEV_T devno;
53
54         /* find the block device file */
55
56         if (!path||!mntpath||!bdev||!fs)
57                 smb_panic("sys_path_to_bdev: called with NULL pointer");
58
59         (*mntpath) = NULL;
60         (*bdev) = NULL;
61         (*fs) = NULL;
62         
63         if ( sys_stat(path, &S) == -1 )
64                 return (-1);
65
66         devno = S.st_dev ;
67
68         fp = setmntent(MOUNTED,"r");
69         if (fp == NULL) {
70                 return -1;
71         }
72   
73         while ((mnt = getmntent(fp))) {
74                 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
75                         continue ;
76
77                 if (S.st_dev == devno) {
78                         (*mntpath) = SMB_STRDUP(mnt->mnt_dir);
79                         (*bdev) = SMB_STRDUP(mnt->mnt_fsname);
80                         (*fs)   = SMB_STRDUP(mnt->mnt_type);
81                         if ((*mntpath)&&(*bdev)&&(*fs)) {
82                                 ret = 0;
83                         } else {
84                                 SAFE_FREE(*mntpath);
85                                 SAFE_FREE(*bdev);
86                                 SAFE_FREE(*fs);
87                                 ret = -1;
88                         }
89
90                         break;
91                 }
92         }
93
94         endmntent(fp) ;
95
96         return ret;
97 }
98 /* #endif HAVE_MNTENT */
99 #elif defined(HAVE_DEVNM)
100
101 /* we have this on HPUX, ... */
102 static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
103 {
104         int ret = -1;
105         char dev_disk[256];
106         SMB_STRUCT_STAT S;
107
108         if (!path||!mntpath||!bdev||!fs)
109                 smb_panic("sys_path_to_bdev: called with NULL pointer");
110
111         (*mntpath) = NULL;
112         (*bdev) = NULL;
113         (*fs) = NULL;
114         
115         /* find the block device file */
116
117         if ((ret=sys_stat(path, &S))!=0) {
118                 return ret;
119         }
120         
121         if ((ret=devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1))!=0) {
122                 return ret;     
123         }
124
125         /* we should get the mntpath right...
126          * but I don't know how
127          * --metze
128          */
129         (*mntpath) = SMB_STRDUP(path);
130         (*bdev) = SMB_STRDUP(dev_disk);
131         if ((*mntpath)&&(*bdev)) {
132                 ret = 0;
133         } else {
134                 SAFE_FREE(*mntpath);
135                 SAFE_FREE(*bdev);
136                 ret = -1;
137         }       
138         
139         
140         return ret;     
141 }
142
143 /* #endif HAVE_DEVNM */
144 #else
145 /* we should fake this up...*/
146 static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
147 {
148         int ret = -1;
149
150         if (!path||!mntpath||!bdev||!fs)
151                 smb_panic("sys_path_to_bdev: called with NULL pointer");
152
153         (*mntpath) = NULL;
154         (*bdev) = NULL;
155         (*fs) = NULL;
156         
157         (*mntpath) = SMB_STRDUP(path);
158         if (*mntpath) {
159                 ret = 0;
160         } else {
161                 SAFE_FREE(*mntpath);
162                 ret = -1;
163         }
164
165         return ret;
166 }
167 #endif
168
169 /*********************************************************************
170  Now the list of all filesystem specific quota systems we have found
171 **********************************************************************/
172 static struct {
173         const char *name;
174         int (*get_quota)(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
175         int (*set_quota)(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
176 } sys_quota_backends[] = {
177 #ifdef HAVE_XFS_QUOTAS
178         {"xfs", sys_get_xfs_quota,      sys_set_xfs_quota},
179 #endif /* HAVE_XFS_QUOTAS */
180         {NULL,  NULL,                   NULL}   
181 };
182
183 static int command_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
184 {
185         const char *get_quota_command;
186         char **lines = NULL;
187         
188         get_quota_command = lp_get_quota_command();
189         if (get_quota_command && *get_quota_command) {
190                 const char *p;
191                 char *p2;
192                 pstring syscmd;
193                 int _id = -1;
194
195                 switch(qtype) {
196                         case SMB_USER_QUOTA_TYPE:
197                         case SMB_USER_FS_QUOTA_TYPE:
198                                 _id = id.uid;
199                                 break;
200                         case SMB_GROUP_QUOTA_TYPE:
201                         case SMB_GROUP_FS_QUOTA_TYPE:
202                                 _id = id.gid;
203                                 break;
204                         default:
205                                 DEBUG(0,("invalid quota type.\n"));
206                                 return -1;
207                 }
208
209                 slprintf(syscmd, sizeof(syscmd)-1, 
210                         "%s \"%s\" %d %d", 
211                         get_quota_command, path, qtype, _id);
212
213                 DEBUG (3, ("get_quota: Running command %s\n", syscmd));
214
215                 lines = file_lines_pload(syscmd, NULL);
216                 if (lines) {
217                         char *line = lines[0];
218
219                         DEBUG (3, ("Read output from get_quota, \"%s\"\n", line));
220
221                         /* we need to deal with long long unsigned here, if supported */
222
223                         dp->qflags = (enum SMB_QUOTA_TYPE)strtoul(line, &p2, 10);
224                         p = p2;
225                         while (p && *p && isspace(*p)) {
226                                 p++;
227                         }
228
229                         if (p && *p) {
230                                 dp->curblocks = STR_TO_SMB_BIG_UINT(p, &p);
231                         } else {
232                                 goto invalid_param;
233                         }
234
235                         while (p && *p && isspace(*p)) {
236                                 p++;
237                         }
238
239                         if (p && *p) {
240                                 dp->softlimit = STR_TO_SMB_BIG_UINT(p, &p);
241                         } else {
242                                 goto invalid_param;
243                         }
244
245                         while (p && *p && isspace(*p)) {
246                                 p++;
247                         }
248
249                         if (p && *p) {
250                                 dp->hardlimit = STR_TO_SMB_BIG_UINT(p, &p);
251                         } else {
252                                 goto invalid_param;
253                         }
254
255                         while (p && *p && isspace(*p)) {
256                                 p++;
257                         }
258
259                         if (p && *p) {
260                                 dp->curinodes = STR_TO_SMB_BIG_UINT(p, &p);
261                         } else {
262                                 goto invalid_param;
263                         }
264
265                         while (p && *p && isspace(*p)) {
266                                 p++;
267                         }
268
269                         if (p && *p) {
270                                 dp->isoftlimit = STR_TO_SMB_BIG_UINT(p, &p);
271                         } else {
272                                 goto invalid_param;
273                         }
274
275                         while (p && *p && isspace(*p)) {
276                                 p++;
277                         }
278
279                         if (p && *p) {
280                                 dp->ihardlimit = STR_TO_SMB_BIG_UINT(p, &p);
281                         } else {
282                                 goto invalid_param;     
283                         }
284
285                         while (p && *p && isspace(*p)) {
286                                 p++;
287                         }
288
289                         if (p && *p) {
290                                 dp->bsize = STR_TO_SMB_BIG_UINT(p, NULL);
291                         } else {
292                                 dp->bsize = 1024;
293                         }
294
295                         file_lines_free(lines);
296                         lines = NULL;
297
298                         DEBUG (3, ("Parsed output of get_quota, ...\n"));
299
300 #ifdef LARGE_SMB_OFF_T
301                         DEBUGADD (5,( 
302                                 "qflags:%u curblocks:%llu softlimit:%llu hardlimit:%llu\n"
303                                 "curinodes:%llu isoftlimit:%llu ihardlimit:%llu bsize:%llu\n", 
304                                 dp->qflags,(long long unsigned)dp->curblocks,
305                                 (long long unsigned)dp->softlimit,(long long unsigned)dp->hardlimit,
306                                 (long long unsigned)dp->curinodes,
307                                 (long long unsigned)dp->isoftlimit,(long long unsigned)dp->ihardlimit,
308                                 (long long unsigned)dp->bsize));
309 #else /* LARGE_SMB_OFF_T */
310                         DEBUGADD (5,( 
311                                 "qflags:%u curblocks:%lu softlimit:%lu hardlimit:%lu\n"
312                                 "curinodes:%lu isoftlimit:%lu ihardlimit:%lu bsize:%lu\n", 
313                                 dp->qflags,(long unsigned)dp->curblocks,
314                                 (long unsigned)dp->softlimit,(long unsigned)dp->hardlimit,
315                                 (long unsigned)dp->curinodes,
316                                 (long unsigned)dp->isoftlimit,(long unsigned)dp->ihardlimit,
317                                 (long unsigned)dp->bsize));
318 #endif /* LARGE_SMB_OFF_T */
319                         return 0;
320                 }
321
322                 DEBUG (0, ("get_quota_command failed!\n"));
323                 return -1;
324         }
325
326         errno = ENOSYS;
327         return -1;
328         
329 invalid_param:
330
331         file_lines_free(lines);
332         DEBUG(0,("The output of get_quota_command is invalid!\n"));
333         return -1;
334 }
335
336 static int command_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
337 {
338         const char *set_quota_command;
339         
340         set_quota_command = lp_set_quota_command();
341         if (set_quota_command && *set_quota_command) {
342                 char **lines;
343                 pstring syscmd;
344                 int _id = -1;
345
346                 switch(qtype) {
347                         case SMB_USER_QUOTA_TYPE:
348                         case SMB_USER_FS_QUOTA_TYPE:
349                                 _id = id.uid;
350                                 break;
351                         case SMB_GROUP_QUOTA_TYPE:
352                         case SMB_GROUP_FS_QUOTA_TYPE:
353                                 _id = id.gid;
354                                 break;
355                         default:
356                                 return -1;
357                 }
358
359 #ifdef LARGE_SMB_OFF_T
360                 slprintf(syscmd, sizeof(syscmd)-1, 
361                         "%s \"%s\" %d %d "
362                         "%u %llu %llu "
363                         "%llu %llu %llu ", 
364                         set_quota_command, path, qtype, _id, dp->qflags,
365                         (long long unsigned)dp->softlimit,(long long unsigned)dp->hardlimit,
366                         (long long unsigned)dp->isoftlimit,(long long unsigned)dp->ihardlimit,
367                         (long long unsigned)dp->bsize);
368 #else /* LARGE_SMB_OFF_T */
369                 slprintf(syscmd, sizeof(syscmd)-1, 
370                         "%s \"%s\" %d %d "
371                         "%u %lu %lu "
372                         "%lu %lu %lu ", 
373                         set_quota_command, path, qtype, _id, dp->qflags,
374                         (long unsigned)dp->softlimit,(long unsigned)dp->hardlimit,
375                         (long unsigned)dp->isoftlimit,(long unsigned)dp->ihardlimit,
376                         (long unsigned)dp->bsize);
377 #endif /* LARGE_SMB_OFF_T */
378
379
380
381                 DEBUG (3, ("get_quota: Running command %s\n", syscmd));
382
383                 lines = file_lines_pload(syscmd, NULL);
384                 if (lines) {
385                         char *line = lines[0];
386
387                         DEBUG (3, ("Read output from set_quota, \"%s\"\n", line));
388
389                         file_lines_free(lines);
390                         
391                         return 0;
392                 }
393                 DEBUG (0, ("set_quota_command failed!\n"));
394                 return -1;
395         }
396
397         errno = ENOSYS;
398         return -1;
399 }
400
401 int sys_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
402 {
403         int ret = -1;
404         int i;
405         BOOL ready = False;
406         char *mntpath = NULL;
407         char *bdev = NULL;
408         char *fs = NULL;
409
410         if (!path||!dp)
411                 smb_panic("sys_get_quota: called with NULL pointer");
412
413         if (command_get_quota(path, qtype, id, dp)==0) {        
414                 return 0;
415         } else if (errno != ENOSYS) {
416                 return -1;
417         }
418
419         if ((ret=sys_path_to_bdev(path,&mntpath,&bdev,&fs))!=0) {
420                 DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
421                 return ret;
422         }
423
424         errno = 0;
425         DEBUG(10,("sys_get_quota() uid(%u, %u)\n", (unsigned)getuid(), (unsigned)geteuid()));
426
427         for (i=0;(fs && sys_quota_backends[i].name && sys_quota_backends[i].get_quota);i++) {
428                 if (strcmp(fs,sys_quota_backends[i].name)==0) {
429                         ret = sys_quota_backends[i].get_quota(mntpath, bdev, qtype, id, dp);
430                         if (ret!=0) {
431                                 DEBUG(3,("sys_get_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
432                                         fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
433                         } else {
434                                 DEBUG(10,("sys_get_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
435                                         fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
436                         }
437                         ready = True;
438                         break;  
439                 }               
440         }
441
442         if (!ready) {
443                 /* use the default vfs quota functions */
444                 ret=sys_get_vfs_quota(mntpath, bdev, qtype, id, dp);
445                 if (ret!=0) {
446                         DEBUG(3,("sys_get_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s\n",
447                                 "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
448                 } else {
449                         DEBUG(10,("sys_get_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
450                                 "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
451                 }
452         }
453
454         SAFE_FREE(mntpath);
455         SAFE_FREE(bdev);
456         SAFE_FREE(fs);
457
458         if ((ret!=0)&& (errno == EDQUOT)) {
459                 DEBUG(10,("sys_get_quota() warning over quota!\n"));
460                 return 0;
461         }
462
463         return ret;
464 }
465
466 int sys_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
467 {
468         int ret = -1;
469         int i;
470         BOOL ready = False;
471         char *mntpath = NULL;
472         char *bdev = NULL;
473         char *fs = NULL;
474
475         /* find the block device file */
476
477         if (!path||!dp)
478                 smb_panic("get_smb_quota: called with NULL pointer");
479
480         if (command_set_quota(path, qtype, id, dp)==0) {        
481                 return 0;
482         } else if (errno != ENOSYS) {
483                 return -1;
484         }
485
486         if ((ret=sys_path_to_bdev(path,&mntpath,&bdev,&fs))!=0) {
487                 DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
488                 return ret;
489         }
490
491         errno = 0;
492         DEBUG(10,("sys_set_quota() uid(%u, %u)\n", (unsigned)getuid(), (unsigned)geteuid())); 
493
494         for (i=0;(fs && sys_quota_backends[i].name && sys_quota_backends[i].set_quota);i++) {
495                 if (strcmp(fs,sys_quota_backends[i].name)==0) {
496                         ret = sys_quota_backends[i].set_quota(mntpath, bdev, qtype, id, dp);
497                         if (ret!=0) {
498                                 DEBUG(3,("sys_set_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
499                                         fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
500                         } else {
501                                 DEBUG(10,("sys_set_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
502                                         fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
503                         }
504                         ready = True;
505                         break;
506                 }               
507         }
508
509         if (!ready) {
510                 /* use the default vfs quota functions */
511                 ret=sys_set_vfs_quota(mntpath, bdev, qtype, id, dp);
512                 if (ret!=0) {
513                         DEBUG(3,("sys_set_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
514                                 "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
515                 } else {
516                         DEBUG(10,("sys_set_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
517                                 "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
518                 }
519         }
520
521         SAFE_FREE(mntpath);
522         SAFE_FREE(bdev);
523         SAFE_FREE(fs);
524
525         if ((ret!=0)&& (errno == EDQUOT)) {
526                 DEBUG(10,("sys_set_quota() warning over quota!\n"));
527                 return 0;
528         }
529
530         return ret;             
531 }
532
533 #else /* HAVE_SYS_QUOTAS */
534  void dummy_sysquotas_c(void);
535
536  void dummy_sysquotas_c(void)
537 {
538         return;
539 }
540 #endif /* HAVE_SYS_QUOTAS */
541