source: trunk/samba/source/smbd/quotas.c @ 26

Last change on this file since 26 was 26, checked in by Paul Smedley, 14 years ago

Updated source to 3.0.25rc1

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