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