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