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