s3:sysquota_xfs: fix logic so that we actually use this module on Linux
[Samba/gbeck.git] / source3 / lib / sysquotas.c
blob55d4730ab3d8fe5e39d2d6b0f566e8c2e549f8ec
1 /*
2 Unix SMB/CIFS implementation.
3 System QUOTA function wrappers
4 Copyright (C) Stefan (metze) Metzmacher 2003
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.
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.
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/>.
21 #include "includes.h"
23 #undef DBGC_CLASS
24 #define DBGC_CLASS DBGC_QUOTA
26 #ifdef HAVE_SYS_QUOTAS
28 #if defined(HAVE_QUOTACTL_4A)
30 /*#endif HAVE_QUOTACTL_4A */
31 #elif defined(HAVE_QUOTACTL_4B)
33 /*#endif HAVE_QUOTACTL_4B */
34 #elif defined(HAVE_QUOTACTL_3)
36 #error HAVE_QUOTACTL_3 not implemented
38 /* #endif HAVE_QUOTACTL_3 */
39 #else /* NO_QUOTACTL_USED */
41 #endif /* NO_QUOTACTL_USED */
43 #ifdef HAVE_MNTENT
44 static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
46 int ret = -1;
47 SMB_STRUCT_STAT S;
48 FILE *fp;
49 struct mntent *mnt;
50 SMB_DEV_T devno;
52 /* find the block device file */
54 if (!path||!mntpath||!bdev||!fs)
55 smb_panic("sys_path_to_bdev: called with NULL pointer");
57 (*mntpath) = NULL;
58 (*bdev) = NULL;
59 (*fs) = NULL;
61 if ( sys_stat(path, &S, false) == -1 )
62 return (-1);
64 devno = S.st_ex_dev ;
66 fp = setmntent(MOUNTED,"r");
67 if (fp == NULL) {
68 return -1;
71 while ((mnt = getmntent(fp))) {
72 if ( sys_stat(mnt->mnt_dir, &S, false) == -1 )
73 continue ;
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;
88 break;
92 endmntent(fp) ;
94 return ret;
96 /* #endif HAVE_MNTENT */
97 #elif defined(HAVE_DEVNM)
99 /* we have this on HPUX, ... */
100 static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
102 int ret = -1;
103 char dev_disk[256];
104 SMB_STRUCT_STAT S;
106 if (!path||!mntpath||!bdev||!fs)
107 smb_panic("sys_path_to_bdev: called with NULL pointer");
109 (*mntpath) = NULL;
110 (*bdev) = NULL;
111 (*fs) = NULL;
113 /* find the block device file */
115 if ((ret=sys_stat(path, &S, false))!=0) {
116 return ret;
119 if ((ret=devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 1))!=0) {
120 return ret;
123 /* we should get the mntpath right...
124 * but I don't know how
125 * --metze
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;
138 return ret;
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)
146 int ret = -1;
148 if (!path||!mntpath||!bdev||!fs)
149 smb_panic("sys_path_to_bdev: called with NULL pointer");
151 (*mntpath) = NULL;
152 (*bdev) = NULL;
153 (*fs) = NULL;
155 (*mntpath) = SMB_STRDUP(path);
156 if (*mntpath) {
157 ret = 0;
158 } else {
159 SAFE_FREE(*mntpath);
160 ret = -1;
163 return ret;
165 #endif
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 || defined HAVE_LINUX_XFS_QUOTAS
176 {"xfs", sys_get_xfs_quota, sys_set_xfs_quota},
177 #endif /* HAVE_XFS_QUOTAS */
178 #ifdef HAVE_NFS_QUOTAS
179 {"nfs", sys_get_nfs_quota, sys_set_nfs_quota},
180 {"nfs4", sys_get_nfs_quota, sys_set_nfs_quota},
181 #endif /* HAVE_NFS_QUOTAS */
182 {NULL, NULL, NULL}
185 static int command_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
187 const char *get_quota_command;
188 char **lines = NULL;
190 get_quota_command = lp_get_quota_command(talloc_tos());
191 if (get_quota_command && *get_quota_command) {
192 const char *p;
193 char *p2;
194 char *syscmd = NULL;
195 int _id = -1;
197 switch(qtype) {
198 case SMB_USER_QUOTA_TYPE:
199 case SMB_USER_FS_QUOTA_TYPE:
200 _id = id.uid;
201 break;
202 case SMB_GROUP_QUOTA_TYPE:
203 case SMB_GROUP_FS_QUOTA_TYPE:
204 _id = id.gid;
205 break;
206 default:
207 DEBUG(0,("invalid quota type.\n"));
208 return -1;
211 if (asprintf(&syscmd, "%s \"%s\" %d %d",
212 get_quota_command, path, qtype, _id) < 0) {
213 return -1;
216 DEBUG (3, ("get_quota: Running command %s\n", syscmd));
218 lines = file_lines_pload(syscmd, NULL);
219 SAFE_FREE(syscmd);
221 if (lines) {
222 char *line = lines[0];
224 DEBUG (3, ("Read output from get_quota, \"%s\"\n", line));
226 /* we need to deal with long long unsigned here, if supported */
228 dp->qflags = strtoul(line, &p2, 10);
229 p = p2;
230 while (p && *p && isspace(*p)) {
231 p++;
234 if (p && *p) {
235 dp->curblocks = STR_TO_SMB_BIG_UINT(p, &p);
236 } else {
237 goto invalid_param;
240 while (p && *p && isspace(*p)) {
241 p++;
244 if (p && *p) {
245 dp->softlimit = STR_TO_SMB_BIG_UINT(p, &p);
246 } else {
247 goto invalid_param;
250 while (p && *p && isspace(*p)) {
251 p++;
254 if (p && *p) {
255 dp->hardlimit = STR_TO_SMB_BIG_UINT(p, &p);
256 } else {
257 goto invalid_param;
260 while (p && *p && isspace(*p)) {
261 p++;
264 if (p && *p) {
265 dp->curinodes = STR_TO_SMB_BIG_UINT(p, &p);
266 } else {
267 goto invalid_param;
270 while (p && *p && isspace(*p)) {
271 p++;
274 if (p && *p) {
275 dp->isoftlimit = STR_TO_SMB_BIG_UINT(p, &p);
276 } else {
277 goto invalid_param;
280 while (p && *p && isspace(*p)) {
281 p++;
284 if (p && *p) {
285 dp->ihardlimit = STR_TO_SMB_BIG_UINT(p, &p);
286 } else {
287 goto invalid_param;
290 while (p && *p && isspace(*p)) {
291 p++;
294 if (p && *p) {
295 dp->bsize = STR_TO_SMB_BIG_UINT(p, NULL);
296 } else {
297 dp->bsize = 1024;
300 TALLOC_FREE(lines);
301 lines = NULL;
303 DEBUG (3, ("Parsed output of get_quota, ...\n"));
305 DEBUGADD (5,(
306 "qflags:%u curblocks:%llu softlimit:%llu hardlimit:%llu\n"
307 "curinodes:%llu isoftlimit:%llu ihardlimit:%llu bsize:%llu\n",
308 dp->qflags,(long long unsigned)dp->curblocks,
309 (long long unsigned)dp->softlimit,(long long unsigned)dp->hardlimit,
310 (long long unsigned)dp->curinodes,
311 (long long unsigned)dp->isoftlimit,(long long unsigned)dp->ihardlimit,
312 (long long unsigned)dp->bsize));
313 return 0;
316 DEBUG (0, ("get_quota_command failed!\n"));
317 return -1;
320 errno = ENOSYS;
321 return -1;
323 invalid_param:
325 TALLOC_FREE(lines);
326 DEBUG(0,("The output of get_quota_command is invalid!\n"));
327 return -1;
330 static int command_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
332 const char *set_quota_command;
334 set_quota_command = lp_set_quota_command(talloc_tos());
335 if (set_quota_command && *set_quota_command) {
336 char **lines = NULL;
337 char *syscmd = NULL;
338 int _id = -1;
340 switch(qtype) {
341 case SMB_USER_QUOTA_TYPE:
342 case SMB_USER_FS_QUOTA_TYPE:
343 _id = id.uid;
344 break;
345 case SMB_GROUP_QUOTA_TYPE:
346 case SMB_GROUP_FS_QUOTA_TYPE:
347 _id = id.gid;
348 break;
349 default:
350 return -1;
353 if (asprintf(&syscmd,
354 "%s \"%s\" %d %d "
355 "%u %llu %llu "
356 "%llu %llu %llu ",
357 set_quota_command, path, qtype, _id, dp->qflags,
358 (long long unsigned)dp->softlimit,(long long unsigned)dp->hardlimit,
359 (long long unsigned)dp->isoftlimit,(long long unsigned)dp->ihardlimit,
360 (long long unsigned)dp->bsize) < 0) {
361 return -1;
364 DEBUG (3, ("get_quota: Running command %s\n", syscmd));
366 lines = file_lines_pload(syscmd, NULL);
367 SAFE_FREE(syscmd);
368 if (lines) {
369 char *line = lines[0];
371 DEBUG (3, ("Read output from set_quota, \"%s\"\n", line));
373 TALLOC_FREE(lines);
375 return 0;
377 DEBUG (0, ("set_quota_command failed!\n"));
378 return -1;
381 errno = ENOSYS;
382 return -1;
385 int sys_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
387 int ret = -1;
388 int i;
389 bool ready = False;
390 char *mntpath = NULL;
391 char *bdev = NULL;
392 char *fs = NULL;
394 if (!path||!dp)
395 smb_panic("sys_get_quota: called with NULL pointer");
397 if (command_get_quota(path, qtype, id, dp)==0) {
398 return 0;
399 } else if (errno != ENOSYS) {
400 return -1;
403 if ((ret=sys_path_to_bdev(path,&mntpath,&bdev,&fs))!=0) {
404 DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
405 return ret;
408 errno = 0;
409 DEBUG(10,("sys_get_quota() uid(%u, %u)\n", (unsigned)getuid(), (unsigned)geteuid()));
411 for (i=0;(fs && sys_quota_backends[i].name && sys_quota_backends[i].get_quota);i++) {
412 if (strcmp(fs,sys_quota_backends[i].name)==0) {
413 ret = sys_quota_backends[i].get_quota(mntpath, bdev, qtype, id, dp);
414 if (ret!=0) {
415 DEBUG(3,("sys_get_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
416 fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
417 } else {
418 DEBUG(10,("sys_get_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
419 fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
421 ready = True;
422 break;
426 if (!ready) {
427 /* use the default vfs quota functions */
428 ret=sys_get_vfs_quota(mntpath, bdev, qtype, id, dp);
429 if (ret!=0) {
430 DEBUG(3,("sys_get_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s\n",
431 "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
432 } else {
433 DEBUG(10,("sys_get_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
434 "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
438 SAFE_FREE(mntpath);
439 SAFE_FREE(bdev);
440 SAFE_FREE(fs);
442 if ((ret!=0)&& (errno == EDQUOT)) {
443 DEBUG(10,("sys_get_quota() warning over quota!\n"));
444 return 0;
447 return ret;
450 int sys_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
452 int ret = -1;
453 int i;
454 bool ready = False;
455 char *mntpath = NULL;
456 char *bdev = NULL;
457 char *fs = NULL;
459 /* find the block device file */
461 if (!path||!dp)
462 smb_panic("get_smb_quota: called with NULL pointer");
464 if (command_set_quota(path, qtype, id, dp)==0) {
465 return 0;
466 } else if (errno != ENOSYS) {
467 return -1;
470 if ((ret=sys_path_to_bdev(path,&mntpath,&bdev,&fs))!=0) {
471 DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
472 return ret;
475 errno = 0;
476 DEBUG(10,("sys_set_quota() uid(%u, %u)\n", (unsigned)getuid(), (unsigned)geteuid()));
478 for (i=0;(fs && sys_quota_backends[i].name && sys_quota_backends[i].set_quota);i++) {
479 if (strcmp(fs,sys_quota_backends[i].name)==0) {
480 ret = sys_quota_backends[i].set_quota(mntpath, bdev, qtype, id, dp);
481 if (ret!=0) {
482 DEBUG(3,("sys_set_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
483 fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
484 } else {
485 DEBUG(10,("sys_set_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
486 fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
488 ready = True;
489 break;
493 if (!ready) {
494 /* use the default vfs quota functions */
495 ret=sys_set_vfs_quota(mntpath, bdev, qtype, id, dp);
496 if (ret!=0) {
497 DEBUG(3,("sys_set_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
498 "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
499 } else {
500 DEBUG(10,("sys_set_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
501 "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
505 SAFE_FREE(mntpath);
506 SAFE_FREE(bdev);
507 SAFE_FREE(fs);
509 if ((ret!=0)&& (errno == EDQUOT)) {
510 DEBUG(10,("sys_set_quota() warning over quota!\n"));
511 return 0;
514 return ret;
517 #else /* HAVE_SYS_QUOTAS */
518 void dummy_sysquotas_c(void);
520 void dummy_sysquotas_c(void)
522 return;
524 #endif /* HAVE_SYS_QUOTAS */