a424602d5fe519d44e5e5c908d1a2ab0af4f5f90
[ira/wip.git] / source3 / smbd / quotas.c
1 /* 
2    Unix SMB/CIFS implementation.
3    support for quotas
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20
21 /* 
22  * This is one of the most system dependent parts of Samba, and its
23  * done a litle differently. Each system has its own way of doing 
24  * things :-(
25  */
26
27 #include "includes.h"
28
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_QUOTA
31
32 #ifndef HAVE_SYS_QUOTAS
33
34 /* just a quick hack because sysquotas.h is included before linux/quota.h */
35 #ifdef QUOTABLOCK_SIZE
36 #undef QUOTABLOCK_SIZE
37 #endif
38
39 #ifdef WITH_QUOTAS
40
41 #if defined(VXFS_QUOTA)
42
43 /*
44  * In addition to their native filesystems, some systems have Veritas VxFS.
45  * Declare here, define at end: reduces likely "include" interaction problems.
46  *      David Lee <T.D.Lee@durham.ac.uk>
47  */
48 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize);
49
50 #endif /* VXFS_QUOTA */
51
52 #ifdef LINUX
53
54 #include <sys/types.h>
55 #include <mntent.h>
56
57 /*
58  * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
59  * So we include all the files has *should* be in the system into a large,
60  * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA.
61  */
62
63 #include "samba_linux_quota.h"
64
65 typedef struct _LINUX_SMB_DISK_QUOTA {
66         uint64_t bsize;
67         uint64_t hardlimit; /* In bsize units. */
68         uint64_t softlimit; /* In bsize units. */
69         uint64_t curblocks; /* In bsize units. */
70         uint64_t ihardlimit; /* inode hard limit. */
71         uint64_t isoftlimit; /* inode soft limit. */
72         uint64_t curinodes; /* Current used inodes. */
73 } LINUX_SMB_DISK_QUOTA;
74
75
76 #ifdef HAVE_LINUX_DQBLK_XFS_H
77 #include <linux/dqblk_xfs.h>
78
79 /****************************************************************************
80  Abstract out the XFS Quota Manager quota get call.
81 ****************************************************************************/
82
83 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
84 {
85         struct fs_disk_quota D;
86         int ret;
87
88         ZERO_STRUCT(D);
89
90         ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
91
92         if (ret)
93                 ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
94
95         if (ret)
96                 return ret;
97
98         dp->bsize = (uint64_t)512;
99         dp->softlimit = (uint64_t)D.d_blk_softlimit;
100         dp->hardlimit = (uint64_t)D.d_blk_hardlimit;
101         dp->ihardlimit = (uint64_t)D.d_ino_hardlimit;
102         dp->isoftlimit = (uint64_t)D.d_ino_softlimit;
103         dp->curinodes = (uint64_t)D.d_icount;
104         dp->curblocks = (uint64_t)D.d_bcount;
105
106         return ret;
107 }
108 #else
109 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
110 {
111         DEBUG(0,("XFS quota support not available\n"));
112         errno = ENOSYS;
113         return -1;
114 }
115 #endif
116
117
118 /****************************************************************************
119  Abstract out the old and new Linux quota get calls.
120 ****************************************************************************/
121
122 static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
123 {
124         struct v1_kern_dqblk D;
125         int ret;
126
127         ZERO_STRUCT(D);
128
129         ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
130
131         if (ret && errno != EDQUOT)
132                 ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
133
134         if (ret && errno != EDQUOT)
135                 return ret;
136
137         dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
138         dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
139         dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
140         dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
141         dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
142         dp->curinodes = (uint64_t)D.dqb_curinodes;
143         dp->curblocks = (uint64_t)D.dqb_curblocks;
144
145         return ret;
146 }
147
148 static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
149 {
150         struct v2_kern_dqblk D;
151         int ret;
152
153         ZERO_STRUCT(D);
154
155         ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
156
157         if (ret && errno != EDQUOT)
158                 ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
159
160         if (ret && errno != EDQUOT)
161                 return ret;
162
163         dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
164         dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
165         dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
166         dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
167         dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
168         dp->curinodes = (uint64_t)D.dqb_curinodes;
169         dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
170
171         return ret;
172 }
173
174 /****************************************************************************
175  Brand-new generic quota interface.
176 ****************************************************************************/
177
178 static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
179 {
180         struct if_dqblk D;
181         int ret;
182
183         ZERO_STRUCT(D);
184
185         ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
186
187         if (ret && errno != EDQUOT)
188                 ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
189
190         if (ret && errno != EDQUOT)
191                 return ret;
192
193         dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
194         dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
195         dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
196         dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
197         dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
198         dp->curinodes = (uint64_t)D.dqb_curinodes;
199         dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
200
201         return ret;
202 }
203
204 /****************************************************************************
205  Try to get the disk space from disk quotas (LINUX version).
206 ****************************************************************************/
207
208 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
209 {
210         int r;
211         SMB_STRUCT_STAT S;
212         FILE *fp;
213         LINUX_SMB_DISK_QUOTA D;
214         struct mntent *mnt;
215         SMB_DEV_T devno;
216         int found;
217         uid_t euser_id;
218         gid_t egrp_id;
219
220         ZERO_STRUCT(D);
221
222         euser_id = geteuid();
223         egrp_id = getegid();
224
225         /* find the block device file */
226
227         if ( sys_stat(path, &S, lp_fake_dir_create_times()) == -1 )
228                 return(False) ;
229
230         devno = S.st_ex_dev ;
231
232         if ((fp = setmntent(MOUNTED,"r")) == NULL)
233                 return(False) ;
234
235         found = False ;
236
237         while ((mnt = getmntent(fp))) {
238                 if ( sys_stat(mnt->mnt_dir, &S, lp_fake_dir_create_times())
239                      == -1 )
240                         continue ;
241
242                 if (S.st_ex_dev == devno) {
243                         found = True ;
244                         break;
245                 }
246         }
247
248         endmntent(fp) ;
249
250         if (!found)
251                 return(False);
252
253         become_root();
254
255         if (strcmp(mnt->mnt_type, "xfs")==0) {
256                 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
257         } else {
258                 r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
259                 if (r == -1 && errno != EDQUOT) {
260                         r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
261                         if (r == -1 && errno != EDQUOT)
262                                 r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
263                 }
264         }
265
266         unbecome_root();
267
268         /* Use softlimit to determine disk space, except when it has been exceeded */
269         *bsize = D.bsize;
270         if (r == -1) {
271                 if (errno == EDQUOT) {
272                         *dfree =0;
273                         *dsize =D.curblocks;
274                         return (True);
275                 } else {
276                         return(False);
277                 }
278         }
279
280         /* Use softlimit to determine disk space, except when it has been exceeded */
281         if (
282                 (D.softlimit && D.curblocks >= D.softlimit) ||
283                 (D.hardlimit && D.curblocks >= D.hardlimit) ||
284                 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
285                 (D.ihardlimit && D.curinodes>=D.ihardlimit)
286         ) {
287                 *dfree = 0;
288                 *dsize = D.curblocks;
289         } else if (D.softlimit==0 && D.hardlimit==0) {
290                 return(False);
291         } else {
292                 if (D.softlimit == 0)
293                         D.softlimit = D.hardlimit;
294                 *dfree = D.softlimit - D.curblocks;
295                 *dsize = D.softlimit;
296         }
297
298         return (True);
299 }
300
301 #elif defined(CRAY)
302
303 #include <sys/quota.h>
304 #include <mntent.h>
305
306 /****************************************************************************
307 try to get the disk space from disk quotas (CRAY VERSION)
308 ****************************************************************************/
309
310 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
311 {
312         struct mntent *mnt;
313         FILE *fd;
314         SMB_STRUCT_STAT sbuf;
315         SMB_DEV_T devno ;
316         struct q_request request ;
317         struct qf_header header ;
318         int quota_default = 0 ;
319         bool found = false;
320
321         if (sys_stat(path, &sbuf, lp_fake_dir_create_times()) == -1) {
322                 return false;
323         }
324
325         devno = sbuf.st_ex_dev ;
326
327         if ((fd = setmntent(KMTAB)) == NULL) {
328                 return false;
329         }
330
331         while ((mnt = getmntent(fd)) != NULL) {
332                 if (sys_stat(mnt->mnt_dir, &sbuf, lp_fake_dir_create_times())
333                     == -1) {
334                         continue;
335                 }
336                 if (sbuf.st_ex_dev == devno) {
337                         found = frue ;
338                         break;
339                 }
340         }
341
342         name = talloc_strdup(talloc_tos(), mnt->mnt_dir);
343         endmntent(fd);
344         if (!found) {
345                 return false;
346         }
347
348         if (!name) {
349                 return false;
350         }
351
352         request.qf_magic = QF_MAGIC ;
353         request.qf_entry.id = geteuid() ;
354
355         if (quotactl(name, Q_GETQUOTA, &request) == -1) {
356                 return false;
357         }
358
359         if (!request.user) {
360                 return False;
361         }
362
363         if (request.qf_entry.user_q.f_quota == QFV_DEFAULT) {
364                 if (!quota_default) {
365                         if (quotactl(name, Q_GETHEADER, &header) == -1) {
366                                 return false;
367                         } else {
368                                 quota_default = header.user_h.def_fq;
369                         }
370                 }
371                 *dfree = quota_default;
372         } else if (request.qf_entry.user_q.f_quota == QFV_PREVENT) {
373                 *dfree = 0;
374         } else {
375                 *dfree = request.qf_entry.user_q.f_quota;
376         }
377
378         *dsize = request.qf_entry.user_q.f_use;
379
380         if (*dfree < *dsize) {
381                 *dfree = 0;
382         } else {
383                 *dfree -= *dsize;
384         }
385
386         *bsize = 4096 ;  /* Cray blocksize */
387         return true;
388 }
389
390
391 #elif defined(SUNOS5) || defined(SUNOS4)
392
393 #include <fcntl.h>
394 #include <sys/param.h>
395 #if defined(SUNOS5)
396 #include <sys/fs/ufs_quota.h>
397 #include <sys/mnttab.h>
398 #include <sys/mntent.h>
399 #else /* defined(SUNOS4) */
400 #include <ufs/quota.h>
401 #include <mntent.h>
402 #endif
403
404 #if defined(SUNOS5)
405
406 /****************************************************************************
407  Allows querying of remote hosts for quotas on NFS mounted shares.
408  Supports normal NFS and AMD mounts.
409  Alan Romeril <a.romeril@ic.ac.uk> July 2K.
410 ****************************************************************************/
411
412 #include <rpc/rpc.h>
413 #include <rpc/types.h>
414 #include <rpcsvc/rquota.h>
415 #include <rpc/nettype.h>
416 #include <rpc/xdr.h>
417
418 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
419 {
420         if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
421                 return(0);
422         if (!xdr_int(xdrsp, &args->gqa_uid))
423                 return(0);
424         return (1);
425 }
426
427 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
428 {
429         int quotastat;
430
431         if (!xdr_int(xdrsp, &quotastat)) {
432                 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
433                 return 0;
434         }
435         gqr->status = quotastat;
436
437         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
438                 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
439                 return 0;
440         }
441         if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
442                 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
443                 return 0;
444         }
445         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
446                 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
447                 return 0;
448         }
449         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
450                 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
451                 return 0;
452         }
453         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
454                 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
455                 return 0;
456         }
457         return (1);
458 }
459
460 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
461 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
462 {
463         uid_t uid = euser_id;
464         struct dqblk D;
465         char *mnttype = nfspath;
466         CLIENT *clnt;
467         struct getquota_rslt gqr;
468         struct getquota_args args;
469         char *cutstr, *pathname, *host, *testpath;
470         int len;
471         static struct timeval timeout = {2,0};
472         enum clnt_stat clnt_stat;
473         bool ret = True;
474
475         *bsize = *dfree = *dsize = (uint64_t)0;
476
477         len=strcspn(mnttype, ":");
478         pathname=strstr(mnttype, ":");
479         cutstr = (char *) SMB_MALLOC(len+1);
480         if (!cutstr)
481                 return False;
482
483         memset(cutstr, '\0', len+1);
484         host = strncat(cutstr,mnttype, sizeof(char) * len );
485         DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
486         DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
487         testpath=strchr_m(mnttype, ':');
488         args.gqa_pathp = testpath+1;
489         args.gqa_uid = uid;
490
491         DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
492
493         if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
494                 ret = False;
495                 goto out;
496         }
497
498         clnt->cl_auth = authunix_create_default();
499         DEBUG(9,("nfs_quotas: auth_success\n"));
500
501         clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
502
503         if (clnt_stat != RPC_SUCCESS) {
504                 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
505                 ret = False;
506                 goto out;
507         }
508
509         /*
510          * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
511          * no quota set, and 3 if no permission to get the quota.  If 0 or 3 return
512          * something sensible.
513          */
514
515         switch (gqr.status) {
516         case 0:
517                 DEBUG(9,("nfs_quotas: Remote Quotas Failed!  Error \"%i\" \n", gqr.status));
518                 ret = False;
519                 goto out;
520
521         case 1:
522                 DEBUG(9,("nfs_quotas: Good quota data\n"));
523                 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
524                 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
525                 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
526                 break;
527
528         case 2:
529         case 3:
530                 D.dqb_bsoftlimit = 1;
531                 D.dqb_curblocks = 1;
532                 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
533                 break;
534
535         default:
536                 DEBUG(9,("nfs_quotas: Remote Quotas Questionable!  Error \"%i\" \n", gqr.status ));
537                 break;
538         }
539
540         DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
541                         gqr.status,
542                         gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
543                         gqr.getquota_rslt_u.gqr_rquota.rq_active,
544                         gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
545                         gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
546                         gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
547
548         *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
549         *dsize = D.dqb_bsoftlimit;
550
551         if (D.dqb_curblocks == 1)
552                 *bsize = 512;
553
554         if (D.dqb_curblocks > D.dqb_bsoftlimit) {
555                 *dfree = 0;
556                 *dsize = D.dqb_curblocks;
557         } else
558                 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
559
560   out:
561
562         if (clnt) {
563                 if (clnt->cl_auth)
564                         auth_destroy(clnt->cl_auth);
565                 clnt_destroy(clnt);
566         }
567
568         DEBUG(5,("nfs_quotas: For path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
569
570         SAFE_FREE(cutstr);
571         DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
572         return ret;
573 }
574 #endif
575
576 /****************************************************************************
577 try to get the disk space from disk quotas (SunOS & Solaris2 version)
578 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
579 ****************************************************************************/
580
581 bool disk_quotas(const char *path,
582                 uint64_t *bsize,
583                 uint64_t *dfree,
584                 uint64_t *dsize)
585 {
586         uid_t euser_id;
587         int ret;
588         struct dqblk D;
589 #if defined(SUNOS5)
590         struct quotctl command;
591         int file;
592         struct mnttab mnt;
593 #else /* SunOS4 */
594         struct mntent *mnt;
595 #endif
596         char *name = NULL;
597         FILE *fd;
598         SMB_STRUCT_STAT sbuf;
599         SMB_DEV_T devno;
600         bool found = false;
601
602         euser_id = geteuid();
603
604         if (sys_stat(path, &sbuf, lp_fake_dir_create_times()) == -1) {
605                 return false;
606         }
607
608         devno = sbuf.st_ex_dev ;
609         DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
610                 path, (unsigned int)devno));
611 #if defined(SUNOS5)
612         if ((fd = sys_fopen(MNTTAB, "r")) == NULL) {
613                 return false;
614         }
615
616         while (getmntent(fd, &mnt) == 0) {
617                 if (sys_stat(mnt.mnt_mountp, &sbuf,
618                              lp_fake_dir_create_times()) == -1) {
619                         continue;
620                 }
621
622                 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
623                         mnt.mnt_mountp, (unsigned int)devno));
624
625                 /* quotas are only on vxfs, UFS or NFS */
626                 if ((sbuf.st_ex_dev == devno) && (
627                         strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
628                         strcmp( mnt.mnt_fstype, "nfs" ) == 0    ||
629                         strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
630                                 found = true;
631                                 name = talloc_asprintf(talloc_tos(),
632                                                 "%s/quotas",
633                                                 mnt.mnt_mountp);
634                                 break;
635                 }
636         }
637
638         fclose(fd);
639 #else /* SunOS4 */
640         if ((fd = setmntent(MOUNTED, "r")) == NULL) {
641                 return false;
642         }
643
644         while ((mnt = getmntent(fd)) != NULL) {
645                 if (sys_stat(mnt->mnt_dir, &sbuf,
646                              lp_fake_dir_create_times()) == -1) {
647                         continue;
648                 }
649                 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
650                                         mnt->mnt_dir,
651                                         (unsigned int)sbuf.st_ex_dev));
652                 if (sbuf.st_ex_dev == devno) {
653                         found = true;
654                         name = talloc_strdup(talloc_tos(),
655                                         mnt->mnt_fsname);
656                         break;
657                 }
658         }
659
660         endmntent(fd);
661 #endif
662         if (!found) {
663                 return false;
664         }
665
666         if (!name) {
667                 return false;
668         }
669         become_root();
670
671 #if defined(SUNOS5)
672         if (strcmp(mnt.mnt_fstype, "nfs") == 0) {
673                 bool retval;
674                 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n",
675                                         mnt.mnt_special));
676                 retval = nfs_quotas(mnt.mnt_special,
677                                 euser_id, bsize, dfree, dsize);
678                 unbecome_root();
679                 return retval;
680         }
681
682         DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
683         if((file=sys_open(name, O_RDONLY,0))<0) {
684                 unbecome_root();
685                 return false;
686         }
687         command.op = Q_GETQUOTA;
688         command.uid = euser_id;
689         command.addr = (caddr_t) &D;
690         ret = ioctl(file, Q_QUOTACTL, &command);
691         close(file);
692 #else
693         DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
694         ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
695 #endif
696
697         unbecome_root();
698
699         if (ret < 0) {
700                 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n",
701                                         strerror(errno) ));
702
703 #if defined(SUNOS5) && defined(VXFS_QUOTA)
704                 /* If normal quotactl() fails, try vxfs private calls */
705                 set_effective_uid(euser_id);
706                 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
707                 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
708                         bool retval;
709                         retval = disk_quotas_vxfs(name, path,
710                                         bsize, dfree, dsize);
711                         return retval;
712                 }
713 #else
714                 return false;
715 #endif
716         }
717
718         /* If softlimit is zero, set it equal to hardlimit.
719          */
720
721         if (D.dqb_bsoftlimit==0) {
722                 D.dqb_bsoftlimit = D.dqb_bhardlimit;
723         }
724
725         /* Use softlimit to determine disk space. A user exceeding the quota
726          * is told that there's no space left. Writes might actually work for
727          * a bit if the hardlimit is set higher than softlimit. Effectively
728          * the disk becomes made of rubber latex and begins to expand to
729          * accommodate the user :-)
730          */
731
732         if (D.dqb_bsoftlimit==0)
733                 return(False);
734         *bsize = DEV_BSIZE;
735         *dsize = D.dqb_bsoftlimit;
736
737         if (D.dqb_curblocks > D.dqb_bsoftlimit) {
738                 *dfree = 0;
739                 *dsize = D.dqb_curblocks;
740         } else {
741                 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
742         }
743
744         DEBUG(5,("disk_quotas for path \"%s\" returning "
745                 "bsize %.0f, dfree %.0f, dsize %.0f\n",
746                 path,(double)*bsize,(double)*dfree,(double)*dsize));
747
748         return true;
749 }
750
751
752 #elif defined(OSF1)
753 #include <ufs/quota.h>
754
755 /****************************************************************************
756 try to get the disk space from disk quotas - OSF1 version
757 ****************************************************************************/
758
759 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
760 {
761   int r, save_errno;
762   struct dqblk D;
763   SMB_STRUCT_STAT S;
764   uid_t euser_id;
765
766   /*
767    * This code presumes that OSF1 will only
768    * give out quota info when the real uid 
769    * matches the effective uid. JRA.
770    */
771   euser_id = geteuid();
772   save_re_uid();
773   if (set_re_uid() != 0) return False;
774
775   r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
776   if (r) {
777      save_errno = errno;
778   }
779
780   restore_re_uid();
781
782   *bsize = DEV_BSIZE;
783
784   if (r)
785   {
786       if (save_errno == EDQUOT)   /* disk quota exceeded */
787       {
788          *dfree = 0;
789          *dsize = D.dqb_curblocks;
790          return (True);
791       }
792       else
793          return (False);  
794   }
795
796   /* If softlimit is zero, set it equal to hardlimit.
797    */
798
799   if (D.dqb_bsoftlimit==0)
800     D.dqb_bsoftlimit = D.dqb_bhardlimit;
801
802   /* Use softlimit to determine disk space, except when it has been exceeded */
803
804   if (D.dqb_bsoftlimit==0)
805     return(False);
806
807   if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
808     *dfree = 0;
809     *dsize = D.dqb_curblocks;
810   } else {
811     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
812     *dsize = D.dqb_bsoftlimit;
813   }
814   return (True);
815 }
816
817 #elif defined (IRIX6)
818 /****************************************************************************
819 try to get the disk space from disk quotas (IRIX 6.2 version)
820 ****************************************************************************/
821
822 #include <sys/quota.h>
823 #include <mntent.h>
824
825 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
826 {
827   uid_t euser_id;
828   int r;
829   struct dqblk D;
830   struct fs_disk_quota        F;
831   SMB_STRUCT_STAT S;
832   FILE *fp;
833   struct mntent *mnt;
834   SMB_DEV_T devno;
835   int found;
836   
837   /* find the block device file */
838   
839   if ( sys_stat(path, &S, lp_fake_dir_create_times()) == -1 ) {
840     return(False) ;
841   }
842
843   devno = S.st_ex_dev ;
844   
845   fp = setmntent(MOUNTED,"r");
846   found = False ;
847   
848   while ((mnt = getmntent(fp))) {
849     if ( sys_stat(mnt->mnt_dir, &S, lp_fake_dir_create_times()) == -1 )
850       continue ;
851     if (S.st_ex_dev == devno) {
852       found = True ;
853       break ;
854     }
855   }
856   endmntent(fp) ;
857   
858   if (!found) {
859     return(False);
860   }
861
862   euser_id=geteuid();
863   become_root();
864
865   /* Use softlimit to determine disk space, except when it has been exceeded */
866
867   *bsize = 512;
868
869   if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
870   {
871     r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
872
873     unbecome_root();
874
875     if (r==-1)
876       return(False);
877         
878     /* Use softlimit to determine disk space, except when it has been exceeded */
879     if (
880         (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
881         (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
882         (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
883         (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
884        )
885     {
886       *dfree = 0;
887       *dsize = D.dqb_curblocks;
888     }
889     else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
890     {
891       return(False);
892     }
893     else 
894     {
895       *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
896       *dsize = D.dqb_bsoftlimit;
897     }
898
899   }
900   else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
901   {
902     r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
903
904     unbecome_root();
905
906     if (r==-1)
907     {
908       DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
909       return(False);
910     }
911         
912     /* No quota for this user. */
913     if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
914     {
915       return(False);
916     }
917
918     /* Use softlimit to determine disk space, except when it has been exceeded */
919     if (
920         (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
921         (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
922         (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
923         (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
924        )
925     {
926       *dfree = 0;
927       *dsize = F.d_bcount;
928     }
929     else 
930     {
931       *dfree = (F.d_blk_softlimit - F.d_bcount);
932       *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
933     }
934
935   }
936   else
937   {
938           unbecome_root();
939           return(False);
940   }
941
942   return (True);
943
944 }
945
946 #else
947
948 #if    defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
949 #include <ufs/ufs/quota.h>
950 #include <machine/param.h>
951 #elif         AIX
952 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
953 #include <jfs/quota.h>
954 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
955 #define dqb_curfiles dqb_curinodes
956 #define dqb_fhardlimit dqb_ihardlimit
957 #define dqb_fsoftlimit dqb_isoftlimit
958 #ifdef _AIXVERSION_530 
959 #include <sys/statfs.h>
960 #include <sys/vmount.h>
961 #endif /* AIX 5.3 */
962 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
963 #include <sys/quota.h>
964 #include <devnm.h>
965 #endif
966
967 #if defined(__FreeBSD__) || defined(__DragonFly__)
968
969 #include <rpc/rpc.h>
970 #include <rpc/types.h>
971 #include <rpcsvc/rquota.h>
972 #ifdef HAVE_RPC_NETTYPE_H
973 #include <rpc/nettype.h>
974 #endif
975 #include <rpc/xdr.h>
976
977 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
978 {
979         if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
980                 return(0);
981         if (!xdr_int(xdrsp, &args->gqa_uid))
982                 return(0);
983         return (1);
984 }
985
986 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
987 {
988         int quotastat;
989
990         if (!xdr_int(xdrsp, &quotastat)) {
991                 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
992                 return 0;
993         }
994         gqr->status = quotastat;
995
996         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
997                 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
998                 return 0;
999         }
1000         if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
1001                 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
1002                 return 0;
1003         }
1004         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
1005                 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
1006                 return 0;
1007         }
1008         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
1009                 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
1010                 return 0;
1011         }
1012         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
1013                 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
1014                 return 0;
1015         }
1016         return (1);
1017 }
1018
1019 /* Works on FreeBSD, too. :-) */
1020 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1021 {
1022         uid_t uid = euser_id;
1023         struct dqblk D;
1024         char *mnttype = nfspath;
1025         CLIENT *clnt;
1026         struct getquota_rslt gqr;
1027         struct getquota_args args;
1028         char *cutstr, *pathname, *host, *testpath;
1029         int len;
1030         static struct timeval timeout = {2,0};
1031         enum clnt_stat clnt_stat;
1032         bool ret = True;
1033
1034         *bsize = *dfree = *dsize = (uint64_t)0;
1035
1036         len=strcspn(mnttype, ":");
1037         pathname=strstr(mnttype, ":");
1038         cutstr = (char *) SMB_MALLOC(len+1);
1039         if (!cutstr)
1040                 return False;
1041
1042         memset(cutstr, '\0', len+1);
1043         host = strncat(cutstr,mnttype, sizeof(char) * len );
1044         DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1045         DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1046         testpath=strchr_m(mnttype, ':');
1047         args.gqa_pathp = testpath+1;
1048         args.gqa_uid = uid;
1049
1050         DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1051
1052         if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1053                 ret = False;
1054                 goto out;
1055         }
1056
1057         clnt->cl_auth = authunix_create_default();
1058         DEBUG(9,("nfs_quotas: auth_success\n"));
1059
1060         clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, (const xdrproc_t) my_xdr_getquota_args, (caddr_t)&args, (const xdrproc_t) my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
1061
1062         if (clnt_stat != RPC_SUCCESS) {
1063                 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1064                 ret = False;
1065                 goto out;
1066         }
1067
1068         /* 
1069          * gqr->status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1070          * no quota set, and 3 if no permission to get the quota.  If 0 or 3 return
1071          * something sensible.
1072          */   
1073
1074         switch (gqr.status) {
1075         case 0:
1076                 DEBUG(9,("nfs_quotas: Remote Quotas Failed!  Error \"%i\" \n", gqr.status));
1077                 ret = False;
1078                 goto out;
1079
1080         case 1:
1081                 DEBUG(9,("nfs_quotas: Good quota data\n"));
1082                 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1083                 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1084                 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1085                 break;
1086
1087         case 2:
1088         case 3:
1089                 D.dqb_bsoftlimit = 1;
1090                 D.dqb_curblocks = 1;
1091                 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
1092                 break;
1093
1094         default:
1095                 DEBUG(9,("nfs_quotas: Remote Quotas Questionable!  Error \"%i\" \n", gqr.status));
1096                 break;
1097         }
1098
1099         DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
1100                         gqr.status,
1101                         gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1102                         gqr.getquota_rslt_u.gqr_rquota.rq_active,
1103                         gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1104                         gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1105                         gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1106
1107         if (D.dqb_bsoftlimit == 0)
1108                 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1109         if (D.dqb_bsoftlimit == 0)
1110                 return False;
1111
1112         *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1113         *dsize = D.dqb_bsoftlimit;
1114
1115         if (D.dqb_curblocks == 1)
1116                 *bsize = DEV_BSIZE;
1117
1118         if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1119                 *dfree = 0;
1120                 *dsize = D.dqb_curblocks;
1121         } else
1122                 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1123
1124   out:
1125
1126         if (clnt) {
1127                 if (clnt->cl_auth)
1128                         auth_destroy(clnt->cl_auth);
1129                 clnt_destroy(clnt);
1130         }
1131
1132         DEBUG(5,("nfs_quotas: For path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1133
1134         SAFE_FREE(cutstr);
1135         DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1136         return ret;
1137 }
1138
1139 #endif
1140
1141 /****************************************************************************
1142 try to get the disk space from disk quotas - default version
1143 ****************************************************************************/
1144
1145 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1146 {
1147   int r;
1148   struct dqblk D;
1149   uid_t euser_id;
1150 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1151   char dev_disk[256];
1152   SMB_STRUCT_STAT S;
1153
1154   /* find the block device file */
1155
1156 #ifdef HPUX
1157   /* Need to set the cache flag to 1 for HPUX. Seems
1158    * to have a significant performance boost when
1159    * lstat calls on /dev access this function.
1160    */
1161   if ((sys_stat(path, &S, lp_fake_dir_create_times())<0)
1162       || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 1)<0))
1163 #else
1164   if ((sys_stat(path, &S, lp_fake_dir_create_times())<0)
1165       || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 0)<0))
1166         return (False);
1167 #endif /* ifdef HPUX */
1168
1169 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1170
1171   euser_id = geteuid();
1172
1173 #ifdef HPUX
1174   /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1175   save_re_uid();
1176   if (set_re_uid() != 0) return False;
1177   
1178   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1179
1180   restore_re_uid();
1181 #else 
1182 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1183   {
1184     /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1185     gid_t egrp_id;
1186 #if defined(__FreeBSD__) || defined(__DragonFly__)
1187     SMB_DEV_T devno;
1188     struct statfs *mnts;
1189     SMB_STRUCT_STAT st;
1190     int mntsize, i;
1191     
1192     if (sys_stat(path, &st, lp_fake_dir_create_times()) < 0)
1193         return False;
1194     devno = st.st_ex_dev;
1195
1196     mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1197     if (mntsize <= 0)
1198         return False;
1199
1200     for (i = 0; i < mntsize; i++) {
1201         if (sys_stat(mnts[i].f_mntonname, &st, lp_fake_dir_create_times()) < 0)
1202             return False;
1203         if (st.st_ex_dev == devno)
1204             break;
1205     }
1206     if (i == mntsize)
1207         return False;
1208 #endif
1209     
1210     become_root();
1211
1212 #if defined(__FreeBSD__) || defined(__DragonFly__)
1213     if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1214         bool retval;
1215         retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1216         unbecome_root();
1217         return retval;
1218     }
1219 #endif
1220
1221     egrp_id = getegid();
1222     r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1223
1224     /* As FreeBSD has group quotas, if getting the user
1225        quota fails, try getting the group instead. */
1226     if (r) {
1227             r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1228     }
1229
1230     unbecome_root();
1231   }
1232 #elif defined(AIX)
1233   /* AIX has both USER and GROUP quotas: 
1234      Get the USER quota (ohnielse@fysik.dtu.dk) */
1235 #ifdef _AIXVERSION_530
1236   {
1237     struct statfs statbuf;
1238     quota64_t user_quota;
1239     if (statfs(path,&statbuf) != 0)
1240       return False;
1241     if(statbuf.f_vfstype == MNT_J2)
1242     {
1243     /* For some reason we need to be root for jfs2 */
1244       become_root();
1245       r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
1246       unbecome_root();
1247     /* Copy results to old struct to let the following code work as before */
1248       D.dqb_curblocks  = user_quota.bused;
1249       D.dqb_bsoftlimit = user_quota.bsoft;
1250       D.dqb_bhardlimit = user_quota.bhard;
1251       D.dqb_curfiles   = user_quota.iused;
1252       D.dqb_fsoftlimit = user_quota.isoft;
1253       D.dqb_fhardlimit = user_quota.ihard;
1254     }
1255     else if(statbuf.f_vfstype == MNT_JFS)
1256     {
1257 #endif /* AIX 5.3 */
1258   save_re_uid();
1259   if (set_re_uid() != 0) 
1260     return False;
1261   r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1262   restore_re_uid();
1263 #ifdef _AIXVERSION_530
1264     }
1265     else
1266       r = 1; /* Fail for other FS-types */
1267   }
1268 #endif /* AIX 5.3 */
1269 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1270   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1271 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1272 #endif /* HPUX */
1273
1274   /* Use softlimit to determine disk space, except when it has been exceeded */
1275 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1276   *bsize = DEV_BSIZE;
1277 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1278   *bsize = 1024;
1279 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1280
1281   if (r)
1282     {
1283       if (errno == EDQUOT) 
1284         {
1285           *dfree =0;
1286           *dsize =D.dqb_curblocks;
1287           return (True);
1288         }
1289       else return(False);
1290     }
1291
1292   /* If softlimit is zero, set it equal to hardlimit.
1293    */
1294
1295   if (D.dqb_bsoftlimit==0)
1296     D.dqb_bsoftlimit = D.dqb_bhardlimit;
1297
1298   if (D.dqb_bsoftlimit==0)
1299     return(False);
1300   /* Use softlimit to determine disk space, except when it has been exceeded */
1301   if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1302 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1303 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1304 #endif
1305     ) {
1306       *dfree = 0;
1307       *dsize = D.dqb_curblocks;
1308     }
1309   else {
1310     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1311     *dsize = D.dqb_bsoftlimit;
1312   }
1313   return (True);
1314 }
1315
1316 #endif
1317
1318 #if defined(VXFS_QUOTA)
1319
1320 /****************************************************************************
1321 Try to get the disk space from Veritas disk quotas.
1322     David Lee <T.D.Lee@durham.ac.uk> August 1999.
1323
1324 Background assumptions:
1325     Potentially under many Operating Systems.  Initially Solaris 2.
1326
1327     My guess is that Veritas is largely, though not entirely,
1328     independent of OS.  So I have separated it out.
1329
1330     There may be some details.  For example, OS-specific "include" files.
1331
1332     It is understood that HPUX 10 somehow gets Veritas quotas without
1333     any special effort; if so, this routine need not be compiled in.
1334         Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1335
1336 Warning:
1337     It is understood that Veritas do not publicly support this ioctl interface.
1338     Rather their preference would be for the user (us) to call the native
1339     OS and then for the OS itself to call through to the VxFS filesystem.
1340     Presumably HPUX 10, see above, does this.
1341
1342 Hints for porting:
1343     Add your OS to "IFLIST" below.
1344     Get it to compile successfully:
1345         Almost certainly "include"s require attention: see SUNOS5.
1346     In the main code above, arrange for it to be called: see SUNOS5.
1347     Test!
1348     
1349 ****************************************************************************/
1350
1351 /* "IFLIST"
1352  * This "if" is a list of ports:
1353  *      if defined(OS1) || defined(OS2) || ...
1354  */
1355 #if defined(SUNOS5)
1356
1357 #if defined(SUNOS5)
1358 #include <sys/fs/vx_solaris.h>
1359 #endif
1360 #include <sys/fs/vx_machdep.h>
1361 #include <sys/fs/vx_layout.h>
1362 #include <sys/fs/vx_quota.h>
1363 #include <sys/fs/vx_aioctl.h>
1364 #include <sys/fs/vx_ioctl.h>
1365
1366 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1367 {
1368   uid_t user_id, euser_id;
1369   int ret;
1370   struct vx_dqblk D;
1371   struct vx_quotctl quotabuf;
1372   struct vx_genioctl genbuf;
1373   char *qfname;
1374   int file;
1375
1376   /*
1377    * "name" may or may not include a trailing "/quotas".
1378    * Arranging consistency of calling here in "quotas.c" may not be easy and
1379    * it might be easier to examine and adjust it here.
1380    * Fortunately, VxFS seems not to mind at present.
1381    */
1382   qfname = talloc_strdup(talloc_tos(), name);
1383   if (!qfname) {
1384           return false;
1385   }
1386   /* pstrcat(qfname, "/quotas") ; */    /* possibly examine and adjust "name" */
1387
1388   euser_id = geteuid();
1389   set_effective_uid(0);
1390
1391   DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1392   if((file=sys_open(qfname, O_RDONLY,0))<0) {
1393     set_effective_uid(euser_id);
1394     return(False);
1395   }
1396   genbuf.ioc_cmd = VX_QUOTACTL;
1397   genbuf.ioc_up = (void *) &quotabuf;
1398
1399   quotabuf.cmd = VX_GETQUOTA;
1400   quotabuf.uid = euser_id;
1401   quotabuf.addr = (caddr_t) &D;
1402   ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1403   close(file);
1404
1405   set_effective_uid(euser_id);
1406
1407   if (ret < 0) {
1408     DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1409     return(False);
1410   }
1411
1412   /* If softlimit is zero, set it equal to hardlimit.
1413    */
1414
1415   if (D.dqb_bsoftlimit==0)
1416     D.dqb_bsoftlimit = D.dqb_bhardlimit;
1417
1418   /* Use softlimit to determine disk space. A user exceeding the quota is told
1419    * that there's no space left. Writes might actually work for a bit if the
1420    * hardlimit is set higher than softlimit. Effectively the disk becomes
1421    * made of rubber latex and begins to expand to accommodate the user :-)
1422    */
1423   DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1424          path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1425          D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1426
1427   if (D.dqb_bsoftlimit==0)
1428     return(False);
1429   *bsize = DEV_BSIZE;
1430   *dsize = D.dqb_bsoftlimit;
1431
1432   if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1433      *dfree = 0;
1434      *dsize = D.dqb_curblocks;
1435   } else
1436     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1437       
1438   DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",
1439          path,(double)*bsize,(double)*dfree,(double)*dsize));
1440
1441   return(True);
1442 }
1443
1444 #endif /* SUNOS5 || ... */
1445
1446 #endif /* VXFS_QUOTA */
1447
1448 #else /* WITH_QUOTAS */
1449
1450 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1451 {
1452         (*bsize) = 512; /* This value should be ignored */
1453
1454         /* And just to be sure we set some values that hopefully */
1455         /* will be larger that any possible real-world value     */
1456         (*dfree) = (uint64_t)-1;
1457         (*dsize) = (uint64_t)-1;
1458
1459         /* As we have select not to use quotas, allways fail */
1460         return false;
1461 }
1462 #endif /* WITH_QUOTAS */
1463
1464 #else /* HAVE_SYS_QUOTAS */
1465 /* wrapper to the new sys_quota interface
1466    this file should be removed later
1467    */
1468 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1469 {
1470         int r;
1471         SMB_DISK_QUOTA D;
1472         unid_t id;
1473
1474         id.uid = geteuid();
1475
1476         ZERO_STRUCT(D);
1477         r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1478
1479         /* Use softlimit to determine disk space, except when it has been exceeded */
1480         *bsize = D.bsize;
1481         if (r == -1) {
1482                 if (errno == EDQUOT) {
1483                         *dfree =0;
1484                         *dsize =D.curblocks;
1485                         return (True);
1486                 } else {
1487                         goto try_group_quota;
1488                 }
1489         }
1490
1491         /* Use softlimit to determine disk space, except when it has been exceeded */
1492         if (
1493                 (D.softlimit && D.curblocks >= D.softlimit) ||
1494                 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1495                 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1496                 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1497         ) {
1498                 *dfree = 0;
1499                 *dsize = D.curblocks;
1500         } else if (D.softlimit==0 && D.hardlimit==0) {
1501                 goto try_group_quota;
1502         } else {
1503                 if (D.softlimit == 0)
1504                         D.softlimit = D.hardlimit;
1505                 *dfree = D.softlimit - D.curblocks;
1506                 *dsize = D.softlimit;
1507         }
1508
1509         return True;
1510         
1511 try_group_quota:
1512         id.gid = getegid();
1513
1514         ZERO_STRUCT(D);
1515         r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1516
1517         /* Use softlimit to determine disk space, except when it has been exceeded */
1518         *bsize = D.bsize;
1519         if (r == -1) {
1520                 if (errno == EDQUOT) {
1521                         *dfree =0;
1522                         *dsize =D.curblocks;
1523                         return (True);
1524                 } else {
1525                         return False;
1526                 }
1527         }
1528
1529         /* Use softlimit to determine disk space, except when it has been exceeded */
1530         if (
1531                 (D.softlimit && D.curblocks >= D.softlimit) ||
1532                 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1533                 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1534                 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1535         ) {
1536                 *dfree = 0;
1537                 *dsize = D.curblocks;
1538         } else if (D.softlimit==0 && D.hardlimit==0) {
1539                 return False;
1540         } else {
1541                 if (D.softlimit == 0)
1542                         D.softlimit = D.hardlimit;
1543                 *dfree = D.softlimit - D.curblocks;
1544                 *dsize = D.softlimit;
1545         }
1546
1547         return (True);
1548 }
1549 #endif /* HAVE_SYS_QUOTAS */