This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[idra/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 #ifndef AUTOCONF_TEST
23
24 #include "includes.h"
25
26 #ifdef HAVE_SYS_QUOTAS
27
28 #if defined(HAVE_QUOTACTL_4A) 
29 /* long quotactl(int cmd, char *special, qid_t id, caddr_t addr) */
30 /* this is used by: linux,HPUX,IRIX */
31
32 /****************************************************************************
33  Abstract out the old and new Linux quota get calls.
34 ****************************************************************************/
35 static int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
36 {
37         int ret = -1;
38         uint32 qflags = 0;
39         struct SYS_DQBLK D;
40         SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
41
42         if (!path||!bdev||!dp)
43                 smb_panic("sys_get_vfs_quota: called with NULL pointer");
44
45         ZERO_STRUCT(D);
46         ZERO_STRUCT(*dp);
47         dp->qtype = qtype;
48
49         switch (qtype) {
50                 case SMB_USER_QUOTA_TYPE:
51                         /* we use id.uid == 0 for default quotas */
52                         if (id.uid == 0) {
53                                 ret = 0;
54                                 break;
55                         }
56         
57                         if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (CADDR_T)&D))) {
58                                 return ret;
59                         }
60
61                         if ((D.dqb_curblocks==0)&&
62                                 (D.dqb_bsoftlimit==0)&&
63                                 (D.dqb_bhardlimit==0)) {
64                                 /* the upper layer functions don't want empty quota records...*/
65                                 return -1;
66                         }
67
68                         break;
69 #ifdef HAVE_GROUP_QUOTA
70                 case SMB_GROUP_QUOTA_TYPE:
71                         if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (CADDR_T)&D))) {
72                                 return ret;
73                         }
74
75                         if ((D.dqb_curblocks==0)&&
76                                 (D.dqb_bsoftlimit==0)&&
77                                 (D.dqb_bhardlimit==0)) {
78                                 /* the upper layer functions don't want empty quota records...*/
79                                 return -1;
80                         }
81
82                         break;
83 #endif /* HAVE_GROUP_QUOTA */
84                 case SMB_USER_FS_QUOTA_TYPE:
85                         id.uid = getuid();
86
87                         if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (CADDR_T)&D))==0) {
88                                 qflags |= QUOTAS_DENY_DISK;
89                         }
90
91                         /* get the default quotas stored in the root's (uid =0) record */
92                         if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, 0, (CADDR_T)&D))) {
93                                 return ret;
94                         }
95
96                         ret = 0;
97                         break;
98                 default:
99                         errno = ENOSYS;
100                         return -1;
101         }
102
103         dp->bsize = bsize;
104         dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
105         dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
106         dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
107         dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
108         dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
109         dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
110
111
112         dp->qflags = qflags;
113
114         return ret;
115 }
116
117 /****************************************************************************
118  Abstract out the old and new Linux quota set calls.
119 ****************************************************************************/
120
121 static int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
122 {
123         int ret = -1;
124         uint32 qflags = 0;
125         struct SYS_DQBLK D;
126         SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
127
128         if (!path||!bdev||!dp)
129                 smb_panic("sys_set_vfs_quota: called with NULL pointer");
130
131         ZERO_STRUCT(D);
132
133         if (bsize == dp->bsize) {
134                 D.dqb_bsoftlimit = dp->softlimit;
135                 D.dqb_bhardlimit = dp->hardlimit;
136                 D.dqb_ihardlimit = dp->ihardlimit;
137                 D.dqb_isoftlimit = dp->isoftlimit;
138         } else {
139                 D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
140                 D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
141                 D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
142                 D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
143         }
144
145         qflags = dp->qflags;
146
147         switch (qtype) {
148                 case SMB_USER_QUOTA_TYPE:
149                         /* we use id.uid == 0 for default quotas */
150                         if (id.uid>0) {
151                                 ret = quotactl(QCMD(Q_SETQLIM,USRQUOTA), bdev, id.uid, (CADDR_T)&D);
152                         }
153                         break;
154 #ifdef HAVE_GROUP_QUOTA
155                 case SMB_GROUP_QUOTA_TYPE:
156                         ret = quotactl(QCMD(Q_SETQLIM,GRPQUOTA), bdev, id.gid, (CADDR_T)&D);
157                         break;
158 #endif /* HAVE_GROUP_QUOTA */
159                 case SMB_USER_FS_QUOTA_TYPE:
160                         /* this stuff didn't work as it should:
161                          * switching on/off quota via quotactl()
162                          * didn't work!
163                          * So we only set the default limits
164                          * --metze
165                          * 
166                          * On HPUX we didn't have the mount path,
167                          * we need to fix sys_path_to_bdev()
168                          *
169                          */
170 #if 0
171                         uid = getuid();
172
173                         ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, uid, (CADDR_T)&D);
174
175                         if ((qflags&QUOTAS_DENY_DISK)||(qflags&QUOTAS_ENABLED)) {
176                                 if (ret == 0) {
177                                         char *quota_file = NULL;
178                                         
179                                         asprintf(&quota_file,"/%s/%s%s",path, QUOTAFILENAME,USERQUOTAFILE_EXTENSION);
180                                         if (quota_file == NULL) {
181                                                 DEBUG(0,("asprintf() failed!\n"));
182                                                 errno = ENOMEM;
183                                                 return -1;
184                                         }
185                                         
186                                         ret = quotactl(QCMD(Q_QUOTAON,USRQUOTA), bdev, -1,(CADDR_T)quota_file);
187                                 } else {
188                                         ret = 0;        
189                                 }
190                         } else {
191                                 if (ret != 0) {
192                                         /* turn off */
193                                         ret = quotactl(QCMD(Q_QUOTAOFF,USRQUOTA), bdev, -1, (CADDR_T)0);        
194                                 } else {
195                                         ret = 0;
196                                 }               
197                         }
198
199                         DEBUG(0,("vfs_fs_quota: ret(%d) errno(%d)[%s] uid(%d) bdev[%s]\n",
200                                 ret,errno,strerror(errno),uid,bdev));
201 #endif
202                                 
203                         /* we use uid == 0 for default quotas */
204                         ret = quotactl(QCMD(Q_SETQLIM,USRQUOTA), bdev, 0, (CADDR_T)&D);
205                         
206                         break;
207
208                 default:
209                         errno = ENOSYS;
210                         return -1;
211         }
212
213         return ret;
214 }
215
216 /*#endif HAVE_QUOTACTL_4A */
217 #elif defined(HAVE_QUOTACTL_4B)
218
219 #error HAVE_QUOTACTL_4B not implemeted
220
221 /*#endif HAVE_QUOTACTL_4B */
222 #elif defined(HAVE_QUOTACTL_3)
223
224 #error HAVE_QUOTACTL_3 not implemented
225
226 /* #endif  HAVE_QUOTACTL_3 */
227 #else /* NO_QUOTACTL_USED */
228
229 static int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
230 {
231         int ret = -1;
232
233         if (!path||!bdev||!dp)
234                 smb_panic("sys_get_vfs_quota: called with NULL pointer");
235                 
236         errno = ENOSYS;
237
238         return ret;
239 }
240
241 static int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
242 {
243         int ret = -1;
244
245         if (!path||!bdev||!dp)
246                 smb_panic("sys_set_vfs_quota: called with NULL pointer");
247
248         errno = ENOSYS;
249
250         return ret;
251 }
252
253 #endif /* NO_QUOTACTL_USED */
254
255 #ifdef HAVE_MNTENT
256 static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
257 {
258         int ret = -1;
259         SMB_STRUCT_STAT S;
260         FILE *fp;
261         struct mntent *mnt;
262         SMB_DEV_T devno;
263
264         /* find the block device file */
265
266         if (!path||!mntpath||!bdev||!fs)
267                 smb_panic("sys_path_to_bdev: called with NULL pointer");
268
269         (*mntpath) = NULL;
270         (*bdev) = NULL;
271         (*fs) = NULL;
272         
273         if ( sys_stat(path, &S) == -1 )
274                 return (-1);
275
276         devno = S.st_dev ;
277
278         fp = setmntent(MOUNTED,"r");
279   
280         while ((mnt = getmntent(fp))) {
281                 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
282                         continue ;
283
284                 if (S.st_dev == devno) {
285                         (*mntpath) = strdup(mnt->mnt_dir);
286                         (*bdev) = strdup(mnt->mnt_fsname);
287                         (*fs)   = strdup(mnt->mnt_type);
288                         if ((*mntpath)&&(*bdev)&&(*fs)) {
289                                 ret = 0;
290                         } else {
291                                 SAFE_FREE(*mntpath);
292                                 SAFE_FREE(*bdev);
293                                 SAFE_FREE(*fs);
294                                 ret = -1;
295                         }
296
297                         break;
298                 }
299         }
300
301         endmntent(fp) ;
302
303         return ret;
304 }
305 /* #endif HAVE_MNTENT */
306 #elif defined(HAVE_DEVNM)
307
308 /* we have this on HPUX, ... */
309 static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
310 {
311         int ret = -1;
312         char dev_disk[256];
313         SMB_STRUCT_STAT S;
314
315         if (!path||!mntpath||!bdev||!fs)
316                 smb_panic("sys_path_to_bdev: called with NULL pointer");
317
318         (*mntpath) = NULL;
319         (*bdev) = NULL;
320         (*fs) = NULL;
321         
322         /* find the block device file */
323
324         if ((ret=sys_stat(path, &S))!=0) {
325                 return ret;
326         }
327         
328         if ((ret=devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1))!=0) {
329                 return ret;     
330         }
331
332         /* we should get the mntpath right...
333          * but I don't know how
334          * --metze
335          */
336         (*mntpath) = strdup(path);
337         (*bdev) = strdup(dev_disk);
338         if ((*mntpath)&&(*bdev)) {
339                 ret = 0;
340         } else {
341                 SAFE_FREE(*mntpath);
342                 SAFE_FREE(*bdev);
343                 ret = -1;
344         }       
345         
346         
347         return ret;     
348 }
349
350 /* #endif HAVE_DEVNM */
351 #else
352 /* we should fake this up...*/
353 static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
354 {
355         int ret = -1;
356
357         if (!path||!mntpath||!bdev||!fs)
358                 smb_panic("sys_path_to_bdev: called with NULL pointer");
359
360         (*mntpath) = NULL;
361         (*bdev) = NULL;
362         (*fs) = NULL;
363         
364         (*mntpath) = strdup(path);
365         if (*mntpath) {
366                 ret = 0;
367         } else {
368                 SAFE_FREE(*mntpath);
369                 ret = -1;
370         }
371
372         return ret;
373 }
374 #endif
375
376
377 /*********************************************************
378  if we have XFS QUOTAS we should use them
379  *********************************************************/
380 #ifdef HAVE_XFS_QUOTA
381 /****************************************************************************
382  Abstract out the XFS Quota Manager quota get call.
383 ****************************************************************************/
384 static int sys_get_xfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
385 {
386         int ret;
387         uint32 qflags = 0;
388         SMB_BIG_UINT bsize = (SMB_BIG_UINT)BBSIZE;
389         struct fs_disk_quota D;
390         struct fs_quota_stat F;
391         ZERO_STRUCT(D);
392         ZERO_STRUCT(F);
393
394         if (!bdev||!dp)
395                 smb_panic("sys_get_xfs_quota: called with NULL pointer");
396                 
397         ZERO_STRUCT(*dp);
398         dp->qtype = qtype;
399                 
400         switch (qtype) {
401                 case SMB_USER_QUOTA_TYPE:
402                         /* we use id.uid == 0 for default quotas */
403                         if (id.uid == 0) {
404                                 ret = 0;
405                                 break;
406                         }
407                         if ((ret=quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), bdev, id.uid, (CADDR_T)&D)))
408                                 return ret;
409                         break;
410 #ifdef HAVE_GROUP_QUOTA
411                 case SMB_GROUP_QUOTA_TYPE:
412                         if ((ret=quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), bdev, id.gid, (CADDR_T)&D)))
413                                 return ret;
414                         break;
415 #endif /* HAVE_GROUP_QUOTA */
416                 case SMB_USER_FS_QUOTA_TYPE:
417                         /* TODO: get quota status from quotactl() ... */        
418                         if ((ret = quotactl(QCMD(Q_XGETQSTAT,USRQUOTA), bdev, -1, (CADDR_T)&F)))
419                                 return ret;
420
421                         if (F.qs_flags & XFS_QUOTA_UDQ_ENFD) {
422                                 qflags |= QUOTAS_DENY_DISK;
423                         }
424                         else if (F.qs_flags & XFS_QUOTA_UDQ_ACCT) {
425                                 qflags |= QUOTAS_ENABLED;
426                         }
427
428                         /* we use uid == 0 for default quotas */
429                         if ((ret=quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), bdev, 0, (CADDR_T)&D)))
430                                 return ret;
431
432                         break;
433                 default:
434                         errno = ENOSYS;
435                         return -1;
436         }
437
438         dp->bsize = bsize;
439         dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit;
440         dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit;
441         dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit;
442         dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit;
443         dp->curinodes = (SMB_BIG_UINT)D.d_icount;
444         dp->curblocks = (SMB_BIG_UINT)D.d_bcount;
445         dp->qflags = qflags;
446
447         return ret;
448 }
449
450 /****************************************************************************
451  Abstract out the XFS Quota Manager quota set call.
452 ****************************************************************************/
453 static int sys_set_xfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
454 {
455         int ret = -1;
456         uint32 qflags = 0;
457         SMB_BIG_UINT bsize = (SMB_BIG_UINT)BBSIZE;
458         struct fs_disk_quota D;
459         struct fs_quota_stat F;
460         int q_on = 0;
461         int q_off = 0;
462         ZERO_STRUCT(D);
463         ZERO_STRUCT(F);
464
465         if (!bdev||!dp)
466                 smb_panic("sys_set_xfs_quota: called with NULL pointer");
467         
468         if (bsize == dp->bsize) {
469                 D.d_blk_softlimit = dp->softlimit;
470                 D.d_blk_hardlimit = dp->hardlimit;
471                 D.d_ino_hardlimit = dp->ihardlimit;
472                 D.d_ino_softlimit = dp->isoftlimit;
473         } else {
474                 D.d_blk_softlimit = (dp->softlimit*dp->bsize)/bsize;
475                 D.d_blk_hardlimit = (dp->hardlimit*dp->bsize)/bsize;
476                 D.d_ino_hardlimit = (dp->ihardlimit*dp->bsize)/bsize;
477                 D.d_ino_softlimit = (dp->isoftlimit*dp->bsize)/bsize;           
478         }
479
480         qflags = dp->qflags;
481
482         switch (qtype) {
483                 case SMB_USER_QUOTA_TYPE:
484                         /* we use uid == 0 for default quotas */
485                         if (id.uid>0) {
486                                 D.d_fieldmask |= FS_DQ_LIMIT_MASK;
487                                 ret = quotactl(QCMD(Q_XSETQLIM,USRQUOTA), bdev, id.uid, (CADDR_T)&D);
488                         }
489                         break;
490 #ifdef HAVE_GROUP_QUOTA
491                 case SMB_GROUP_QUOTA_TYPE:
492                         D.d_fieldmask |= FS_DQ_LIMIT_MASK;
493                         ret = quotactl(QCMD(Q_XSETQLIM,GRPQUOTA), bdev, id.gid, (CADDR_T)&D);
494                         break;
495 #endif /* HAVE_GROUP_QUOTA */
496                 case SMB_USER_FS_QUOTA_TYPE:
497                         /* TODO */
498                         quotactl(QCMD(Q_XGETQSTAT,USRQUOTA), bdev, -1, (CADDR_T)&F);
499                         
500                         if (qflags & QUOTAS_DENY_DISK) {
501                                 if (!(F.qs_flags & XFS_QUOTA_UDQ_ENFD))
502                                         q_on |= XFS_QUOTA_UDQ_ENFD;
503                                 if (!(F.qs_flags & XFS_QUOTA_UDQ_ACCT))
504                                         q_on |= XFS_QUOTA_UDQ_ACCT;
505                                 
506                                 if (q_on != 0) {
507                                         ret = quotactl(QCMD(Q_XQUOTAON,USRQUOTA),bdev, -1, (CADDR_T)&q_on);
508                                 }
509
510                         } else if (qflags & QUOTAS_ENABLED) {
511                                 if (F.qs_flags & XFS_QUOTA_UDQ_ENFD)
512                                         q_off |= XFS_QUOTA_UDQ_ENFD;
513
514                                 if (q_off != 0) {
515                                         ret = quotactl(QCMD(Q_XQUOTAOFF,USRQUOTA),bdev, -1, (CADDR_T)&q_off);
516                                 }
517
518                                 if (!(F.qs_flags & XFS_QUOTA_UDQ_ACCT))
519                                         q_on |= XFS_QUOTA_UDQ_ACCT;
520
521                                 if (q_on != 0) {
522                                         ret = quotactl(QCMD(Q_XQUOTAON,USRQUOTA),bdev, -1, (CADDR_T)&q_on);
523                                 }
524                         } else {
525 #if 0
526                         /* Switch on XFS_QUOTA_UDQ_ACCT didn't work!
527                          * only swittching off XFS_QUOTA_UDQ_ACCT work
528                          */
529                                 if (F.qs_flags & XFS_QUOTA_UDQ_ENFD)
530                                         q_off |= XFS_QUOTA_UDQ_ENFD;
531                                 if (F.qs_flags & XFS_QUOTA_UDQ_ACCT)
532                                         q_off |= XFS_QUOTA_UDQ_ACCT;
533
534                                 if (q_off !=0) {
535                                         ret = quotactl(QCMD(Q_XQUOTAOFF,USRQUOTA),bdev, -1, (CADDR_T)&q_off);
536                                 }
537 #endif
538                         }
539                         
540                         /* we use uid == 0 for default quotas */
541                         D.d_fieldmask |= FS_DQ_LIMIT_MASK;
542                         ret = quotactl(QCMD(Q_XSETQLIM,USRQUOTA), bdev, 0, (CADDR_T)&D);
543                         break;
544                 default:
545                         errno = ENOSYS;
546                         return -1;
547         }
548
549         return ret;
550 }
551 #endif /* HAVE_XFS_QUOTA */
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567 /*********************************************************************
568  Now the list of all filesystem specific quota systems we have found
569 **********************************************************************/
570 static struct {
571         const char *name;
572         int (*get_quota)(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
573         int (*set_quota)(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
574 } sys_quota_backends[] = {
575 #ifdef HAVE_XFS_QUOTA
576         {"xfs", sys_get_xfs_quota,      sys_set_xfs_quota},
577 #endif /* HAVE_XFS_QUOTA */
578         {NULL,  NULL,                   NULL}   
579 };
580
581 static int command_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
582 {
583         const char *get_quota_command;
584         
585         get_quota_command = lp_get_quota_command();
586         if (get_quota_command && *get_quota_command) {
587                 const char *p;
588                 char *p2;
589                 char **lines;
590                 pstring syscmd;
591                 int _id = -1;
592
593                 switch(qtype) {
594                         case SMB_USER_QUOTA_TYPE:
595                         case SMB_USER_FS_QUOTA_TYPE:
596                                 _id = id.uid;
597                                 break;
598                         case SMB_GROUP_QUOTA_TYPE:
599                         case SMB_GROUP_FS_QUOTA_TYPE:
600                                 _id = id.gid;
601                                 break;
602                         default:
603                                 DEBUG(0,("invalid quota type.\n"));
604                                 return -1;
605                 }
606
607                 slprintf(syscmd, sizeof(syscmd)-1, 
608                         "%s \"%s\" %d %d", 
609                         get_quota_command, path, qtype, _id);
610
611                 DEBUG (3, ("get_quota: Running command %s\n", syscmd));
612
613                 lines = file_lines_pload(syscmd, NULL);
614                 if (lines) {
615                         char *line = lines[0];
616
617                         DEBUG (3, ("Read output from get_quota, \"r%s\"\n", line));
618
619                         /* we need to deal with long long unsigned here, if supported */
620
621                         dp->qflags = (enum SMB_QUOTA_TYPE)strtoul(line, &p2, 10);
622                         p = p2;
623                         while (p && *p && isspace(*p))
624                                 p++;
625                         if (p && *p)
626                                 dp->curblocks = STR_TO_SMB_BIG_UINT(p, &p);
627                         else 
628                                 goto invalid_param;
629                         while (p && *p && isspace(*p))
630                                 p++;
631                         if (p && *p)
632                                 dp->softlimit = STR_TO_SMB_BIG_UINT(p, &p);
633                         else
634                                 goto invalid_param;
635                         while (p && *p && isspace(*p))
636                                 p++;
637                         if (p && *p)
638                                 dp->hardlimit = STR_TO_SMB_BIG_UINT(p, &p);
639                         else 
640                                 goto invalid_param;
641                         while (p && *p && isspace(*p))
642                                 p++;
643                         if (p && *p)
644                                 dp->curinodes = STR_TO_SMB_BIG_UINT(p, &p);
645                         else
646                                 goto invalid_param;
647                         while (p && *p && isspace(*p))
648                                 p++;
649                         if (p && *p)
650                                 dp->isoftlimit = STR_TO_SMB_BIG_UINT(p, &p);
651                         else
652                                 goto invalid_param;
653                         while (p && *p && isspace(*p))
654                                 p++;
655                         if (p && *p)
656                                 dp->ihardlimit = STR_TO_SMB_BIG_UINT(p, &p);
657                         else
658                                 goto invalid_param;     
659                         while (p && *p && isspace(*p))
660                                 p++;
661                         if (p && *p)
662                                 dp->bsize = STR_TO_SMB_BIG_UINT(p, NULL);
663                         else
664                                 dp->bsize = 1024;
665                         file_lines_free(lines);
666                         DEBUG (3, ("Parsed output of get_quota, ...\n"));
667
668 #ifdef LARGE_SMB_OFF_T
669                         DEBUGADD (5,( 
670                                 "qflags:%u curblocks:%llu softlimit:%llu hardlimit:%llu\n"
671                                 "curinodes:%llu isoftlimit:%llu ihardlimit:%llu bsize:%llu\n", 
672                                 dp->qflags,(long long unsigned)dp->curblocks,
673                                 (long long unsigned)dp->softlimit,(long long unsigned)dp->hardlimit,
674                                 (long long unsigned)dp->curinodes,
675                                 (long long unsigned)dp->isoftlimit,(long long unsigned)dp->ihardlimit,
676                                 (long long unsigned)dp->bsize));
677 #else /* LARGE_SMB_OFF_T */
678                         DEBUGADD (5,( 
679                                 "qflags:%u curblocks:%lu softlimit:%lu hardlimit:%lu\n"
680                                 "curinodes:%lu isoftlimit:%lu ihardlimit:%lu bsize:%lu\n", 
681                                 dp->qflags,(long unsigned)dp->curblocks,
682                                 (long unsigned)dp->softlimit,(long unsigned)dp->hardlimit,
683                                 (long unsigned)dp->curinodes,
684                                 (long unsigned)dp->isoftlimit,(long unsigned)dp->ihardlimit,
685                                 (long unsigned)dp->bsize));
686 #endif /* LARGE_SMB_OFF_T */
687                         return 0;
688                 }
689
690                 DEBUG (0, ("get_quota_command failed!\n"));
691                 return -1;
692         }
693
694         errno = ENOSYS;
695         return -1;
696         
697 invalid_param:
698         DEBUG(0,("The output of get_quota_command is invalid!\n"));
699         return -1;
700 }
701
702 static int command_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
703 {
704         const char *set_quota_command;
705         
706         set_quota_command = lp_set_quota_command();
707         if (set_quota_command && *set_quota_command) {
708                 char **lines;
709                 pstring syscmd;
710                 int _id = -1;
711
712                 switch(qtype) {
713                         case SMB_USER_QUOTA_TYPE:
714                         case SMB_USER_FS_QUOTA_TYPE:
715                                 _id = id.uid;
716                                 break;
717                         case SMB_GROUP_QUOTA_TYPE:
718                         case SMB_GROUP_FS_QUOTA_TYPE:
719                                 _id = id.gid;
720                                 break;
721                         default:
722                                 return -1;
723                 }
724
725 #ifdef LARGE_SMB_OFF_T
726                 slprintf(syscmd, sizeof(syscmd)-1, 
727                         "%s \"%s\" %d %d "
728                         "%u %llu %llu "
729                         "%llu %llu %llu ", 
730                         set_quota_command, path, qtype, _id, dp->qflags,
731                         (long long unsigned)dp->softlimit,(long long unsigned)dp->hardlimit,
732                         (long long unsigned)dp->isoftlimit,(long long unsigned)dp->ihardlimit,
733                         (long long unsigned)dp->bsize);
734 #else /* LARGE_SMB_OFF_T */
735                 slprintf(syscmd, sizeof(syscmd)-1, 
736                         "%s \"%s\" %d %d "
737                         "%u %lu %lu "
738                         "%lu %lu %lu ", 
739                         set_quota_command, path, qtype, _id, dp->qflags,
740                         (long unsigned)dp->softlimit,(long unsigned)dp->hardlimit,
741                         (long unsigned)dp->isoftlimit,(long unsigned)dp->ihardlimit,
742                         (long unsigned)dp->bsize);
743 #endif /* LARGE_SMB_OFF_T */
744
745
746
747                 DEBUG (3, ("get_quota: Running command %s\n", syscmd));
748
749                 lines = file_lines_pload(syscmd, NULL);
750                 if (lines) {
751                         char *line = lines[0];
752
753                         DEBUG (3, ("Read output from set_quota, \"%s\"\n", line));
754
755                         file_lines_free(lines);
756                         
757                         return 0;
758                 }
759                 DEBUG (0, ("set_quota_command failed!\n"));
760                 return -1;
761         }
762
763         errno = ENOSYS;
764         return -1;
765 }
766
767 int sys_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
768 {
769         int ret = -1;
770         int i;
771         BOOL ready = False;
772         char *mntpath = NULL;
773         char *bdev = NULL;
774         char *fs = NULL;
775
776         if (!path||!dp)
777                 smb_panic("sys_get_quota: called with NULL pointer");
778
779         if (command_get_quota(path, qtype, id, dp)==0) {        
780                 return 0;
781         } else if (errno != ENOSYS) {
782                 return -1;
783         }
784
785         if ((ret=sys_path_to_bdev(path,&mntpath,&bdev,&fs))!=0) {
786                 return ret;
787         }
788
789         for (i=0;(fs && sys_quota_backends[i].name && sys_quota_backends[i].get_quota);i++) {
790                 if (strcmp(fs,sys_quota_backends[i].name)==0) {
791                         ret = sys_quota_backends[i].get_quota(mntpath, bdev, qtype, id, dp);
792                         ready = True;
793                         break;  
794                 }               
795         }
796
797         if (!ready) {
798                 /* use the default vfs quota functions */
799                 ret = sys_get_vfs_quota(mntpath, bdev, qtype, id, dp);
800         }
801
802         SAFE_FREE(mntpath);
803         SAFE_FREE(bdev);
804         SAFE_FREE(fs);
805
806         if ((ret!=0)&& (errno == EDQUOT)) {
807                 return 0;
808         }
809
810         return ret;
811 }
812
813 int sys_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
814 {
815         int ret = -1;
816         int i;
817         BOOL ready = False;
818         char *mntpath = NULL;
819         char *bdev = NULL;
820         char *fs = NULL;
821
822         /* find the block device file */
823
824         if (!path||!dp)
825                 smb_panic("get_smb_quota: called with NULL pointer");
826
827         if (command_set_quota(path, qtype, id, dp)==0) {        
828                 return 0;
829         } else if (errno != ENOSYS) {
830                 return -1;
831         }
832
833         if ((ret=sys_path_to_bdev(path,&mntpath,&bdev,&fs))!=0) {
834                 return ret;
835         }
836
837         for (i=0;(fs && sys_quota_backends[i].name && sys_quota_backends[i].set_quota);i++) {
838                 if (strcmp(fs,sys_quota_backends[i].name)==0) {
839                         ret = sys_quota_backends[i].set_quota(mntpath, bdev, qtype, id, dp);
840                         ready = True;
841                         break;
842                 }               
843         }
844
845         if (!ready) {
846                 /* use the default vfs quota functions */
847                 ret=sys_set_vfs_quota(mntpath, bdev, qtype, id, dp);
848         }
849
850         SAFE_FREE(mntpath);
851         SAFE_FREE(bdev);
852         SAFE_FREE(fs);
853
854         if ((ret!=0)&& (errno == EDQUOT)) {
855                 return 0;
856         }
857
858         return ret;             
859 }
860
861 #else /* HAVE_SYS_QUOTAS */
862  void dummy_sysquotas_c(void)
863 {
864         return;
865 }
866 #endif /* HAVE_SYS_QUOTAS */
867
868 #else /* ! AUTOCONF_TEST */
869 /* this is the autoconf driver to test witch quota system we should use */
870
871 #if defined(HAVE_QUOTACTL_4A)
872 /* long quotactl(int cmd, char *special, qid_t id, caddr_t addr) */
873
874 #ifdef HAVE_SYS_TYPES_H
875 #include <sys/types.h>
876 #endif
877
878 #ifdef HAVE_ASM_TYPES_H
879 #include <asm/types.h>
880 #endif
881
882 #if defined(HAVE_LINUX_QUOTA_H)
883 # include <linux/quota.h>
884 # if defined(HAVE_STRUCT_IF_DQBLK)
885 #  define SYS_DQBLK if_dqblk
886 # elif defined(HAVE_STRUCT_MEM_DQBLK)
887 #  define SYS_DQBLK mem_dqblk
888 # endif
889 #elif defined(HAVE_SYS_QUOTA_H)
890 # include <sys/quota.h>
891 #endif
892
893 #ifndef SYS_DQBLK
894 #define SYS_DQBLK dqblk
895 #endif
896
897  int autoconf_quota(void)
898 {
899         int ret = -1;
900         struct SYS_DQBLK D;
901
902         ret = quotactl(Q_GETQUOTA,"/dev/hda1",0,(void *)&D);
903         
904         return ret;
905 }
906
907 #elif defined(HAVE_QUOTACTL_4B)
908 /* int quotactl(const char *path, int cmd, int id, char *addr); */
909
910 #ifdef HAVE_SYS_QUOTA_H
911 #include <sys/quota.h>
912 #else /* *BSD */
913 #include <sys/types.h>
914 #include <ufs/ufs/quota.h>
915 #include <machine/param.h>
916 #endif
917
918  int autoconf_quota(void)
919 {
920         int ret = -1;
921         struct dqblk D;
922
923         ret = quotactl("/",Q_GETQUOTA,0,(char *) &D);
924
925         return ret;
926 }
927
928 #elif defined(HAVE_QUOTACTL_3)
929 /* int quotactl (char *spec, int request, char *arg); */
930
931 #ifdef HAVE_SYS_TYPES_H
932 #include <sys/types.h>
933 #endif
934 #ifdef HAVE_SYS_QUOTA_H
935 #include <sys/quota.h>
936 #endif
937
938  int autoconf_quota(void)
939 {
940         int ret = -1;
941         struct q_request request;
942
943         ret = quotactl("/", Q_GETQUOTA, &request);
944
945         return ret;
946 }
947
948 #elif defined(HAVE_QUOTACTL_2)
949
950 #error HAVE_QUOTACTL_2 not implemented
951
952 #else
953
954 #error Unknow QUOTACTL prototype
955
956 #endif
957
958  int main(void)
959 {       
960         autoconf_quota();
961         return 0;
962 }
963 #endif /* AUTOCONF_TEST */