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