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