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