s3: Remove the smbd_messaging_context from spoolss_init_cb
[amitay/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, false) == -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, false) == -1)
239                         continue ;
240
241                 if (S.st_ex_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, false) == -1) {
321                 return false;
322         }
323
324         devno = sbuf.st_ex_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, false) == -1) {
332                         continue;
333                 }
334                 if (sbuf.st_ex_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, false) == -1) {
603                 return false;
604         }
605
606         devno = sbuf.st_ex_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, false) == -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_ex_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, false) == -1) {
643                         continue;
644                 }
645                 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
646                                         mnt->mnt_dir,
647                                         (unsigned int)sbuf.st_ex_dev));
648                 if (sbuf.st_ex_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, false) == -1 ) {
836     return(False) ;
837   }
838
839   devno = S.st_ex_dev ;
840   
841   fp = setmntent(MOUNTED,"r");
842   found = False ;
843   
844   while ((mnt = getmntent(fp))) {
845     if ( sys_stat(mnt->mnt_dir, &S, false) == -1 )
846       continue ;
847     if (S.st_ex_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, false)<0)
1158       || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 1)<0))
1159 #else
1160   if ((sys_stat(path, &S, false)<0)
1161       || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 0)<0))
1162         return (False);
1163 #endif /* ifdef HPUX */
1164
1165 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1166
1167   euser_id = geteuid();
1168
1169 #ifdef HPUX
1170   /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1171   save_re_uid();
1172   if (set_re_uid() != 0) return False;
1173   
1174   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1175
1176   restore_re_uid();
1177 #else 
1178 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1179   {
1180     /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1181     gid_t egrp_id;
1182 #if defined(__FreeBSD__) || defined(__DragonFly__)
1183     SMB_DEV_T devno;
1184     struct statfs *mnts;
1185     SMB_STRUCT_STAT st;
1186     int mntsize, i;
1187     
1188     if (sys_stat(path, &st, false) < 0)
1189         return False;
1190     devno = st.st_ex_dev;
1191
1192     mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1193     if (mntsize <= 0)
1194         return False;
1195
1196     for (i = 0; i < mntsize; i++) {
1197         if (sys_stat(mnts[i].f_mntonname, &st, false) < 0)
1198             return False;
1199         if (st.st_ex_dev == devno)
1200             break;
1201     }
1202     if (i == mntsize)
1203         return False;
1204 #endif
1205     
1206     become_root();
1207
1208 #if defined(__FreeBSD__) || defined(__DragonFly__)
1209     if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1210         bool retval;
1211         retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1212         unbecome_root();
1213         return retval;
1214     }
1215 #endif
1216
1217     egrp_id = getegid();
1218     r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1219
1220     /* As FreeBSD has group quotas, if getting the user
1221        quota fails, try getting the group instead. */
1222     if (r) {
1223             r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1224     }
1225
1226     unbecome_root();
1227   }
1228 #elif defined(AIX)
1229   /* AIX has both USER and GROUP quotas: 
1230      Get the USER quota (ohnielse@fysik.dtu.dk) */
1231 #ifdef _AIXVERSION_530
1232   {
1233     struct statfs statbuf;
1234     quota64_t user_quota;
1235     if (statfs(path,&statbuf) != 0)
1236       return False;
1237     if(statbuf.f_vfstype == MNT_J2)
1238     {
1239     /* For some reason we need to be root for jfs2 */
1240       become_root();
1241       r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
1242       unbecome_root();
1243     /* Copy results to old struct to let the following code work as before */
1244       D.dqb_curblocks  = user_quota.bused;
1245       D.dqb_bsoftlimit = user_quota.bsoft;
1246       D.dqb_bhardlimit = user_quota.bhard;
1247       D.dqb_curfiles   = user_quota.iused;
1248       D.dqb_fsoftlimit = user_quota.isoft;
1249       D.dqb_fhardlimit = user_quota.ihard;
1250     }
1251     else if(statbuf.f_vfstype == MNT_JFS)
1252     {
1253 #endif /* AIX 5.3 */
1254   save_re_uid();
1255   if (set_re_uid() != 0) 
1256     return False;
1257   r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1258   restore_re_uid();
1259 #ifdef _AIXVERSION_530
1260     }
1261     else
1262       r = 1; /* Fail for other FS-types */
1263   }
1264 #endif /* AIX 5.3 */
1265 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1266   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1267 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1268 #endif /* HPUX */
1269
1270   /* Use softlimit to determine disk space, except when it has been exceeded */
1271 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1272   *bsize = DEV_BSIZE;
1273 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1274   *bsize = 1024;
1275 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1276
1277   if (r)
1278     {
1279       if (errno == EDQUOT) 
1280         {
1281           *dfree =0;
1282           *dsize =D.dqb_curblocks;
1283           return (True);
1284         }
1285       else return(False);
1286     }
1287
1288   /* If softlimit is zero, set it equal to hardlimit.
1289    */
1290
1291   if (D.dqb_bsoftlimit==0)
1292     D.dqb_bsoftlimit = D.dqb_bhardlimit;
1293
1294   if (D.dqb_bsoftlimit==0)
1295     return(False);
1296   /* Use softlimit to determine disk space, except when it has been exceeded */
1297   if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1298 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1299 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1300 #endif
1301     ) {
1302       *dfree = 0;
1303       *dsize = D.dqb_curblocks;
1304     }
1305   else {
1306     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1307     *dsize = D.dqb_bsoftlimit;
1308   }
1309   return (True);
1310 }
1311
1312 #endif
1313
1314 #if defined(VXFS_QUOTA)
1315
1316 /****************************************************************************
1317 Try to get the disk space from Veritas disk quotas.
1318     David Lee <T.D.Lee@durham.ac.uk> August 1999.
1319
1320 Background assumptions:
1321     Potentially under many Operating Systems.  Initially Solaris 2.
1322
1323     My guess is that Veritas is largely, though not entirely,
1324     independent of OS.  So I have separated it out.
1325
1326     There may be some details.  For example, OS-specific "include" files.
1327
1328     It is understood that HPUX 10 somehow gets Veritas quotas without
1329     any special effort; if so, this routine need not be compiled in.
1330         Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1331
1332 Warning:
1333     It is understood that Veritas do not publicly support this ioctl interface.
1334     Rather their preference would be for the user (us) to call the native
1335     OS and then for the OS itself to call through to the VxFS filesystem.
1336     Presumably HPUX 10, see above, does this.
1337
1338 Hints for porting:
1339     Add your OS to "IFLIST" below.
1340     Get it to compile successfully:
1341         Almost certainly "include"s require attention: see SUNOS5.
1342     In the main code above, arrange for it to be called: see SUNOS5.
1343     Test!
1344     
1345 ****************************************************************************/
1346
1347 /* "IFLIST"
1348  * This "if" is a list of ports:
1349  *      if defined(OS1) || defined(OS2) || ...
1350  */
1351 #if defined(SUNOS5)
1352
1353 #if defined(SUNOS5)
1354 #include <sys/fs/vx_solaris.h>
1355 #endif
1356 #include <sys/fs/vx_machdep.h>
1357 #include <sys/fs/vx_layout.h>
1358 #include <sys/fs/vx_quota.h>
1359 #include <sys/fs/vx_aioctl.h>
1360 #include <sys/fs/vx_ioctl.h>
1361
1362 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1363 {
1364   uid_t user_id, euser_id;
1365   int ret;
1366   struct vx_dqblk D;
1367   struct vx_quotctl quotabuf;
1368   struct vx_genioctl genbuf;
1369   char *qfname;
1370   int file;
1371
1372   /*
1373    * "name" may or may not include a trailing "/quotas".
1374    * Arranging consistency of calling here in "quotas.c" may not be easy and
1375    * it might be easier to examine and adjust it here.
1376    * Fortunately, VxFS seems not to mind at present.
1377    */
1378   qfname = talloc_strdup(talloc_tos(), name);
1379   if (!qfname) {
1380           return false;
1381   }
1382   /* pstrcat(qfname, "/quotas") ; */    /* possibly examine and adjust "name" */
1383
1384   euser_id = geteuid();
1385   set_effective_uid(0);
1386
1387   DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1388   if((file=sys_open(qfname, O_RDONLY,0))<0) {
1389     set_effective_uid(euser_id);
1390     return(False);
1391   }
1392   genbuf.ioc_cmd = VX_QUOTACTL;
1393   genbuf.ioc_up = (void *) &quotabuf;
1394
1395   quotabuf.cmd = VX_GETQUOTA;
1396   quotabuf.uid = euser_id;
1397   quotabuf.addr = (caddr_t) &D;
1398   ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1399   close(file);
1400
1401   set_effective_uid(euser_id);
1402
1403   if (ret < 0) {
1404     DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1405     return(False);
1406   }
1407
1408   /* If softlimit is zero, set it equal to hardlimit.
1409    */
1410
1411   if (D.dqb_bsoftlimit==0)
1412     D.dqb_bsoftlimit = D.dqb_bhardlimit;
1413
1414   /* Use softlimit to determine disk space. A user exceeding the quota is told
1415    * that there's no space left. Writes might actually work for a bit if the
1416    * hardlimit is set higher than softlimit. Effectively the disk becomes
1417    * made of rubber latex and begins to expand to accommodate the user :-)
1418    */
1419   DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1420          path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1421          D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1422
1423   if (D.dqb_bsoftlimit==0)
1424     return(False);
1425   *bsize = DEV_BSIZE;
1426   *dsize = D.dqb_bsoftlimit;
1427
1428   if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1429      *dfree = 0;
1430      *dsize = D.dqb_curblocks;
1431   } else
1432     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1433       
1434   DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",
1435          path,(double)*bsize,(double)*dfree,(double)*dsize));
1436
1437   return(True);
1438 }
1439
1440 #endif /* SUNOS5 || ... */
1441
1442 #endif /* VXFS_QUOTA */
1443
1444 #else /* WITH_QUOTAS */
1445
1446 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1447 {
1448         (*bsize) = 512; /* This value should be ignored */
1449
1450         /* And just to be sure we set some values that hopefully */
1451         /* will be larger that any possible real-world value     */
1452         (*dfree) = (uint64_t)-1;
1453         (*dsize) = (uint64_t)-1;
1454
1455         /* As we have select not to use quotas, allways fail */
1456         return false;
1457 }
1458 #endif /* WITH_QUOTAS */
1459
1460 #else /* HAVE_SYS_QUOTAS */
1461 /* wrapper to the new sys_quota interface
1462    this file should be removed later
1463    */
1464 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1465 {
1466         int r;
1467         SMB_DISK_QUOTA D;
1468         unid_t id;
1469
1470         id.uid = geteuid();
1471
1472         ZERO_STRUCT(D);
1473         r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1474
1475         /* Use softlimit to determine disk space, except when it has been exceeded */
1476         *bsize = D.bsize;
1477         if (r == -1) {
1478                 if (errno == EDQUOT) {
1479                         *dfree =0;
1480                         *dsize =D.curblocks;
1481                         return (True);
1482                 } else {
1483                         goto try_group_quota;
1484                 }
1485         }
1486
1487         /* Use softlimit to determine disk space, except when it has been exceeded */
1488         if (
1489                 (D.softlimit && D.curblocks >= D.softlimit) ||
1490                 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1491                 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1492                 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1493         ) {
1494                 *dfree = 0;
1495                 *dsize = D.curblocks;
1496         } else if (D.softlimit==0 && D.hardlimit==0) {
1497                 goto try_group_quota;
1498         } else {
1499                 if (D.softlimit == 0)
1500                         D.softlimit = D.hardlimit;
1501                 *dfree = D.softlimit - D.curblocks;
1502                 *dsize = D.softlimit;
1503         }
1504
1505         return True;
1506         
1507 try_group_quota:
1508         id.gid = getegid();
1509
1510         ZERO_STRUCT(D);
1511         r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1512
1513         /* Use softlimit to determine disk space, except when it has been exceeded */
1514         *bsize = D.bsize;
1515         if (r == -1) {
1516                 if (errno == EDQUOT) {
1517                         *dfree =0;
1518                         *dsize =D.curblocks;
1519                         return (True);
1520                 } else {
1521                         return False;
1522                 }
1523         }
1524
1525         /* Use softlimit to determine disk space, except when it has been exceeded */
1526         if (
1527                 (D.softlimit && D.curblocks >= D.softlimit) ||
1528                 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1529                 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1530                 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1531         ) {
1532                 *dfree = 0;
1533                 *dsize = D.curblocks;
1534         } else if (D.softlimit==0 && D.hardlimit==0) {
1535                 return False;
1536         } else {
1537                 if (D.softlimit == 0)
1538                         D.softlimit = D.hardlimit;
1539                 *dfree = D.softlimit - D.curblocks;
1540                 *dsize = D.softlimit;
1541         }
1542
1543         return (True);
1544 }
1545 #endif /* HAVE_SYS_QUOTAS */