s3-registry: Check return code of push_reg_sz().
[kai/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 /*#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, false) == -1 )
62                 return (-1);
63
64         devno = S.st_ex_dev ;
65
66         fp = setmntent(MOUNTED,"r");
67         if (fp == NULL) {
68                 return -1;
69         }
70   
71         while ((mnt = getmntent(fp))) {
72                 if ( sys_stat(mnt->mnt_dir, &S, false) == -1 )
73                         continue ;
74
75                 if (S.st_ex_dev == devno) {
76                         (*mntpath) = SMB_STRDUP(mnt->mnt_dir);
77                         (*bdev) = SMB_STRDUP(mnt->mnt_fsname);
78                         (*fs)   = SMB_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, false))!=0) {
116                 return ret;
117         }
118         
119         if ((ret=devnm(S_IFBLK, S.st_ex_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) = SMB_STRDUP(path);
128         (*bdev) = SMB_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) = SMB_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 #if defined HAVE_XFS_QUOTAS
176         {"xfs", sys_get_xfs_quota,      sys_set_xfs_quota},
177         {"gfs", sys_get_xfs_quota,      sys_set_xfs_quota},
178         {"gfs2", sys_get_xfs_quota,     sys_set_xfs_quota},
179 #endif /* HAVE_XFS_QUOTAS */
180 #ifdef HAVE_NFS_QUOTAS
181         {"nfs", sys_get_nfs_quota,      sys_set_nfs_quota},
182         {"nfs4", sys_get_nfs_quota,     sys_set_nfs_quota},
183 #endif /* HAVE_NFS_QUOTAS */
184         {NULL,  NULL,                   NULL}
185 };
186
187 static int command_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
188 {
189         const char *get_quota_command;
190         char **lines = NULL;
191
192         get_quota_command = lp_get_quota_command(talloc_tos());
193         if (get_quota_command && *get_quota_command) {
194                 const char *p;
195                 char *p2;
196                 char *syscmd = NULL;
197                 int _id = -1;
198
199                 switch(qtype) {
200                         case SMB_USER_QUOTA_TYPE:
201                         case SMB_USER_FS_QUOTA_TYPE:
202                                 _id = id.uid;
203                                 break;
204                         case SMB_GROUP_QUOTA_TYPE:
205                         case SMB_GROUP_FS_QUOTA_TYPE:
206                                 _id = id.gid;
207                                 break;
208                         default:
209                                 DEBUG(0,("invalid quota type.\n"));
210                                 return -1;
211                 }
212
213                 if (asprintf(&syscmd, "%s %s %d %d",
214                         get_quota_command, path, qtype, _id) < 0) {
215                         return -1;
216                 }
217
218                 DEBUG (3, ("get_quota: Running command %s\n", syscmd));
219
220                 lines = file_lines_pload(syscmd, NULL);
221                 SAFE_FREE(syscmd);
222
223                 if (lines) {
224                         char *line = lines[0];
225
226                         DEBUG (3, ("Read output from get_quota, \"%s\"\n", line));
227
228                         /* we need to deal with long long unsigned here, if supported */
229
230                         dp->qflags = strtoul(line, &p2, 10);
231                         p = p2;
232                         while (p && *p && isspace(*p)) {
233                                 p++;
234                         }
235
236                         if (p && *p) {
237                                 dp->curblocks = STR_TO_SMB_BIG_UINT(p, &p);
238                         } else {
239                                 goto invalid_param;
240                         }
241
242                         while (p && *p && isspace(*p)) {
243                                 p++;
244                         }
245
246                         if (p && *p) {
247                                 dp->softlimit = STR_TO_SMB_BIG_UINT(p, &p);
248                         } else {
249                                 goto invalid_param;
250                         }
251
252                         while (p && *p && isspace(*p)) {
253                                 p++;
254                         }
255
256                         if (p && *p) {
257                                 dp->hardlimit = STR_TO_SMB_BIG_UINT(p, &p);
258                         } else {
259                                 goto invalid_param;
260                         }
261
262                         while (p && *p && isspace(*p)) {
263                                 p++;
264                         }
265
266                         if (p && *p) {
267                                 dp->curinodes = STR_TO_SMB_BIG_UINT(p, &p);
268                         } else {
269                                 goto invalid_param;
270                         }
271
272                         while (p && *p && isspace(*p)) {
273                                 p++;
274                         }
275
276                         if (p && *p) {
277                                 dp->isoftlimit = STR_TO_SMB_BIG_UINT(p, &p);
278                         } else {
279                                 goto invalid_param;
280                         }
281
282                         while (p && *p && isspace(*p)) {
283                                 p++;
284                         }
285
286                         if (p && *p) {
287                                 dp->ihardlimit = STR_TO_SMB_BIG_UINT(p, &p);
288                         } else {
289                                 goto invalid_param;     
290                         }
291
292                         while (p && *p && isspace(*p)) {
293                                 p++;
294                         }
295
296                         if (p && *p) {
297                                 dp->bsize = STR_TO_SMB_BIG_UINT(p, NULL);
298                         } else {
299                                 dp->bsize = 1024;
300                         }
301
302                         TALLOC_FREE(lines);
303                         lines = NULL;
304
305                         DEBUG (3, ("Parsed output of get_quota, ...\n"));
306
307                         DEBUGADD (5,( 
308                                 "qflags:%u curblocks:%llu softlimit:%llu hardlimit:%llu\n"
309                                 "curinodes:%llu isoftlimit:%llu ihardlimit:%llu bsize:%llu\n", 
310                                 dp->qflags,(long long unsigned)dp->curblocks,
311                                 (long long unsigned)dp->softlimit,(long long unsigned)dp->hardlimit,
312                                 (long long unsigned)dp->curinodes,
313                                 (long long unsigned)dp->isoftlimit,(long long unsigned)dp->ihardlimit,
314                                 (long long unsigned)dp->bsize));
315                         return 0;
316                 }
317
318                 DEBUG (0, ("get_quota_command failed!\n"));
319                 return -1;
320         }
321
322         errno = ENOSYS;
323         return -1;
324
325 invalid_param:
326
327         TALLOC_FREE(lines);
328         DEBUG(0,("The output of get_quota_command is invalid!\n"));
329         return -1;
330 }
331
332 static int command_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
333 {
334         const char *set_quota_command;
335
336         set_quota_command = lp_set_quota_command(talloc_tos());
337         if (set_quota_command && *set_quota_command) {
338                 char **lines = NULL;
339                 char *syscmd = NULL;
340                 int _id = -1;
341
342                 switch(qtype) {
343                         case SMB_USER_QUOTA_TYPE:
344                         case SMB_USER_FS_QUOTA_TYPE:
345                                 _id = id.uid;
346                                 break;
347                         case SMB_GROUP_QUOTA_TYPE:
348                         case SMB_GROUP_FS_QUOTA_TYPE:
349                                 _id = id.gid;
350                                 break;
351                         default:
352                                 return -1;
353                 }
354
355                 if (asprintf(&syscmd,
356                         "%s %s %d %d "
357                         "%u %llu %llu "
358                         "%llu %llu %llu ",
359                         set_quota_command, path, qtype, _id, dp->qflags,
360                         (long long unsigned)dp->softlimit,(long long unsigned)dp->hardlimit,
361                         (long long unsigned)dp->isoftlimit,(long long unsigned)dp->ihardlimit,
362                         (long long unsigned)dp->bsize) < 0) {
363                         return -1;
364                 }
365
366                 DEBUG (3, ("get_quota: Running command %s\n", syscmd));
367
368                 lines = file_lines_pload(syscmd, NULL);
369                 SAFE_FREE(syscmd);
370                 if (lines) {
371                         char *line = lines[0];
372
373                         DEBUG (3, ("Read output from set_quota, \"%s\"\n", line));
374
375                         TALLOC_FREE(lines);
376
377                         return 0;
378                 }
379                 DEBUG (0, ("set_quota_command failed!\n"));
380                 return -1;
381         }
382
383         errno = ENOSYS;
384         return -1;
385 }
386
387 int sys_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
388 {
389         int ret = -1;
390         int i;
391         bool ready = False;
392         char *mntpath = NULL;
393         char *bdev = NULL;
394         char *fs = NULL;
395
396         if (!path||!dp)
397                 smb_panic("sys_get_quota: called with NULL pointer");
398
399         if (command_get_quota(path, qtype, id, dp)==0) {        
400                 return 0;
401         } else if (errno != ENOSYS) {
402                 return -1;
403         }
404
405         if ((ret=sys_path_to_bdev(path,&mntpath,&bdev,&fs))!=0) {
406                 DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
407                 return ret;
408         }
409
410         errno = 0;
411         DEBUG(10,("sys_get_quota() uid(%u, %u), fs(%s)\n", (unsigned)getuid(), (unsigned)geteuid(), fs));
412
413         for (i=0;(fs && sys_quota_backends[i].name && sys_quota_backends[i].get_quota);i++) {
414                 if (strcmp(fs,sys_quota_backends[i].name)==0) {
415                         ret = sys_quota_backends[i].get_quota(mntpath, bdev, qtype, id, dp);
416                         if (ret!=0) {
417                                 DEBUG(3,("sys_get_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
418                                         fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
419                         } else {
420                                 DEBUG(10,("sys_get_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
421                                         fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
422                         }
423                         ready = True;
424                         break;  
425                 }               
426         }
427
428         if (!ready) {
429                 /* use the default vfs quota functions */
430                 ret=sys_get_vfs_quota(mntpath, bdev, qtype, id, dp);
431                 if (ret!=0) {
432                         DEBUG(3,("sys_get_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s\n",
433                                 "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
434                 } else {
435                         DEBUG(10,("sys_get_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
436                                 "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
437                 }
438         }
439
440         SAFE_FREE(mntpath);
441         SAFE_FREE(bdev);
442         SAFE_FREE(fs);
443
444         if ((ret!=0)&& (errno == EDQUOT)) {
445                 DEBUG(10,("sys_get_quota() warning over quota!\n"));
446                 return 0;
447         }
448
449         return ret;
450 }
451
452 int sys_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
453 {
454         int ret = -1;
455         int i;
456         bool ready = False;
457         char *mntpath = NULL;
458         char *bdev = NULL;
459         char *fs = NULL;
460
461         /* find the block device file */
462
463         if (!path||!dp)
464                 smb_panic("get_smb_quota: called with NULL pointer");
465
466         if (command_set_quota(path, qtype, id, dp)==0) {        
467                 return 0;
468         } else if (errno != ENOSYS) {
469                 return -1;
470         }
471
472         if ((ret=sys_path_to_bdev(path,&mntpath,&bdev,&fs))!=0) {
473                 DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
474                 return ret;
475         }
476
477         errno = 0;
478         DEBUG(10,("sys_set_quota() uid(%u, %u)\n", (unsigned)getuid(), (unsigned)geteuid())); 
479
480         for (i=0;(fs && sys_quota_backends[i].name && sys_quota_backends[i].set_quota);i++) {
481                 if (strcmp(fs,sys_quota_backends[i].name)==0) {
482                         ret = sys_quota_backends[i].set_quota(mntpath, bdev, qtype, id, dp);
483                         if (ret!=0) {
484                                 DEBUG(3,("sys_set_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
485                                         fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
486                         } else {
487                                 DEBUG(10,("sys_set_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
488                                         fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
489                         }
490                         ready = True;
491                         break;
492                 }               
493         }
494
495         if (!ready) {
496                 /* use the default vfs quota functions */
497                 ret=sys_set_vfs_quota(mntpath, bdev, qtype, id, dp);
498                 if (ret!=0) {
499                         DEBUG(3,("sys_set_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
500                                 "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
501                 } else {
502                         DEBUG(10,("sys_set_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
503                                 "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
504                 }
505         }
506
507         SAFE_FREE(mntpath);
508         SAFE_FREE(bdev);
509         SAFE_FREE(fs);
510
511         if ((ret!=0)&& (errno == EDQUOT)) {
512                 DEBUG(10,("sys_set_quota() warning over quota!\n"));
513                 return 0;
514         }
515
516         return ret;             
517 }
518
519 #else /* HAVE_SYS_QUOTAS */
520  void dummy_sysquotas_c(void);
521
522  void dummy_sysquotas_c(void)
523 {
524         return;
525 }
526 #endif /* HAVE_SYS_QUOTAS */
527