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