2
Unix SMB/CIFS implementation.
4
Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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.
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
31
#define DBGC_CLASS DBGC_QUOTA
33
#ifndef HAVE_SYS_QUOTAS
35
/* just a quick hack because sysquotas.h is included before linux/quota.h */
36
#ifdef QUOTABLOCK_SIZE
37
#undef QUOTABLOCK_SIZE
42
#if defined(VXFS_QUOTA)
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>
49
BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
51
#endif /* VXFS_QUOTA */
55
#include <sys/types.h>
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.
64
#include "samba_linux_quota.h"
65
#include "samba_xfs_quota.h"
67
typedef struct _LINUX_SMB_DISK_QUOTA {
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;
77
/****************************************************************************
78
Abstract out the XFS Quota Manager quota get call.
79
****************************************************************************/
81
static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
83
struct fs_disk_quota D;
88
ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
91
ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
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;
107
/****************************************************************************
108
Abstract out the old and new Linux quota get calls.
109
****************************************************************************/
111
static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
113
struct v1_kern_dqblk D;
118
ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
120
if (ret && errno != EDQUOT)
121
ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
123
if (ret && errno != EDQUOT)
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;
137
static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
139
struct v2_kern_dqblk D;
144
ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
146
if (ret && errno != EDQUOT)
147
ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
149
if (ret && errno != EDQUOT)
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;
163
/****************************************************************************
164
Brand-new generic quota interface.
165
****************************************************************************/
167
static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
174
ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
176
if (ret && errno != EDQUOT)
177
ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
179
if (ret && errno != EDQUOT)
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;
193
/****************************************************************************
194
Try to get the disk space from disk quotas (LINUX version).
195
****************************************************************************/
197
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
202
LINUX_SMB_DISK_QUOTA D;
211
euser_id = geteuid();
214
/* find the block device file */
216
if ( sys_stat(path, &S) == -1 )
221
if ((fp = setmntent(MOUNTED,"r")) == NULL)
226
while ((mnt = getmntent(fp))) {
227
if ( sys_stat(mnt->mnt_dir,&S) == -1 )
230
if (S.st_dev == devno) {
242
set_effective_uid(0);
244
if (strcmp(mnt->mnt_type, "xfs")==0) {
245
r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
247
r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
248
if (r == -1 && errno != EDQUOT) {
249
r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
250
if (r == -1 && errno != EDQUOT)
251
r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
257
/* Use softlimit to determine disk space, except when it has been exceeded */
260
if (errno == EDQUOT) {
269
/* Use softlimit to determine disk space, except when it has been exceeded */
271
(D.softlimit && D.curblocks >= D.softlimit) ||
272
(D.hardlimit && D.curblocks >= D.hardlimit) ||
273
(D.isoftlimit && D.curinodes >= D.isoftlimit) ||
274
(D.ihardlimit && D.curinodes>=D.ihardlimit)
277
*dsize = D.curblocks;
278
} else if (D.softlimit==0 && D.hardlimit==0) {
281
if (D.softlimit == 0)
282
D.softlimit = D.hardlimit;
283
*dfree = D.softlimit - D.curblocks;
284
*dsize = D.softlimit;
292
#include <sys/quota.h>
295
/****************************************************************************
296
try to get the disk space from disk quotas (CRAY VERSION)
297
****************************************************************************/
299
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
303
SMB_STRUCT_STAT sbuf;
305
static SMB_DEV_T devno_cached = 0 ;
307
struct q_request request ;
308
struct qf_header header ;
309
static int quota_default = 0 ;
312
if ( sys_stat(path,&sbuf) == -1 )
315
devno = sbuf.st_dev ;
317
if ( devno != devno_cached ) {
319
devno_cached = devno ;
321
if ((fd = setmntent(KMTAB)) == NULL)
326
while ((mnt = getmntent(fd)) != NULL) {
328
if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
331
if (sbuf.st_dev == devno) {
340
pstrcpy(name,mnt->mnt_dir) ;
347
request.qf_magic = QF_MAGIC ;
348
request.qf_entry.id = geteuid() ;
350
if (quotactl(name, Q_GETQUOTA, &request) == -1)
353
if ( ! request.user )
356
if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
358
if ( ! quota_default ) {
360
if ( quotactl(name, Q_GETHEADER, &header) == -1 )
363
quota_default = header.user_h.def_fq ;
366
*dfree = quota_default ;
368
}else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
374
*dfree = request.qf_entry.user_q.f_quota ;
378
*dsize = request.qf_entry.user_q.f_use ;
380
if ( *dfree < *dsize )
385
*bsize = 4096 ; /* Cray blocksize */
392
#elif defined(SUNOS5) || defined(SUNOS4)
395
#include <sys/param.h>
397
#include <sys/fs/ufs_quota.h>
398
#include <sys/mnttab.h>
399
#include <sys/mntent.h>
400
#else /* defined(SUNOS4) */
401
#include <ufs/quota.h>
407
/****************************************************************************
408
Allows querying of remote hosts for quotas on NFS mounted shares.
409
Supports normal NFS and AMD mounts.
410
Alan Romeril <a.romeril@ic.ac.uk> July 2K.
411
****************************************************************************/
414
#include <rpc/types.h>
415
#include <rpcsvc/rquota.h>
416
#include <rpc/nettype.h>
419
static int quotastat;
421
static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
423
if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
425
if (!xdr_int(xdrsp, &args->gqa_uid))
430
static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
432
if (!xdr_int(xdrsp, "astat)) {
433
DEBUG(6,("nfs_quotas: Status bad or zero\n"));
436
if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
437
DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
440
if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
441
DEBUG(6,("nfs_quotas: Active bad or zero\n"));
444
if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
445
DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
448
if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
449
DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
452
if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
453
DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
459
/* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
460
static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
462
uid_t uid = euser_id;
464
char *mnttype = nfspath;
466
struct getquota_rslt gqr;
467
struct getquota_args args;
468
char *cutstr, *pathname, *host, *testpath;
470
static struct timeval timeout = {2,0};
471
enum clnt_stat clnt_stat;
474
*bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
476
len=strcspn(mnttype, ":");
477
pathname=strstr(mnttype, ":");
478
cutstr = (char *) SMB_MALLOC(len+1);
482
memset(cutstr, '\0', len+1);
483
host = strncat(cutstr,mnttype, sizeof(char) * len );
484
DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
485
DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
486
testpath=strchr_m(mnttype, ':');
487
args.gqa_pathp = testpath+1;
490
DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
492
if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
497
clnt->cl_auth = authunix_create_default();
498
DEBUG(9,("nfs_quotas: auth_success\n"));
500
clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
502
if (clnt_stat != RPC_SUCCESS) {
503
DEBUG(9,("nfs_quotas: clnt_call fail\n"));
509
* quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
510
* no quota set, and 3 if no permission to get the quota. If 0 or 3 return
511
* something sensible.
514
switch ( quotastat ) {
516
DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
521
DEBUG(9,("nfs_quotas: Good quota data\n"));
522
D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
523
D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
524
D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
529
D.dqb_bsoftlimit = 1;
531
DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
535
DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
539
DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
541
gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
542
gqr.getquota_rslt_u.gqr_rquota.rq_active,
543
gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
544
gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
545
gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
547
*bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
548
*dsize = D.dqb_bsoftlimit;
550
if (D.dqb_curblocks == D.dqb_curblocks == 1)
553
if (D.dqb_curblocks > D.dqb_bsoftlimit) {
555
*dsize = D.dqb_curblocks;
557
*dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
563
auth_destroy(clnt->cl_auth);
567
DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
570
DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
575
/****************************************************************************
576
try to get the disk space from disk quotas (SunOS & Solaris2 version)
577
Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
578
****************************************************************************/
580
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
586
struct quotctl command;
588
static struct mnttab mnt;
596
SMB_STRUCT_STAT sbuf;
598
static SMB_DEV_T devno_cached = 0 ;
601
euser_id = geteuid();
603
if ( sys_stat(path,&sbuf) == -1 )
606
devno = sbuf.st_dev ;
607
DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,(unsigned int)devno));
608
if ( devno != devno_cached ) {
609
devno_cached = devno ;
611
if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
615
slprintf(devopt, sizeof(devopt) - 1, "dev=%x", (unsigned int)devno);
616
while (getmntent(fd, &mnt) == 0) {
617
if( !hasmntopt(&mnt, devopt) )
620
DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt));
622
/* quotas are only on vxfs, UFS or NFS */
623
if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
624
strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
625
strcmp( mnt.mnt_fstype, "vxfs" ) == 0 ) {
631
pstrcpy(name,mnt.mnt_mountp) ;
632
pstrcat(name,"/quotas") ;
635
if ((fd = setmntent(MOUNTED, "r")) == NULL)
639
while ((mnt = getmntent(fd)) != NULL) {
640
if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
642
DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev));
643
if (sbuf.st_dev == devno) {
649
pstrcpy(name,mnt->mnt_fsname) ;
658
set_effective_uid(0);
661
if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) {
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);
669
DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
670
if((file=sys_open(name, O_RDONLY,0))<0) {
674
command.op = Q_GETQUOTA;
675
command.uid = euser_id;
676
command.addr = (caddr_t) &D;
677
ret = ioctl(file, Q_QUOTACTL, &command);
680
DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
681
ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
687
DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
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" )) {
695
retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
703
/* If softlimit is zero, set it equal to hardlimit.
706
if (D.dqb_bsoftlimit==0)
707
D.dqb_bsoftlimit = D.dqb_bhardlimit;
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 :-)
715
if (D.dqb_bsoftlimit==0)
718
*dsize = D.dqb_bsoftlimit;
720
if (D.dqb_curblocks > D.dqb_bsoftlimit) {
722
*dsize = D.dqb_curblocks;
724
*dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
726
DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
727
path,(double)*bsize,(double)*dfree,(double)*dsize));
734
#include <ufs/quota.h>
736
/****************************************************************************
737
try to get the disk space from disk quotas - OSF1 version
738
****************************************************************************/
740
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
748
* This code presumes that OSF1 will only
749
* give out quota info when the real uid
750
* matches the effective uid. JRA.
752
euser_id = geteuid();
754
if (set_re_uid() != 0) return False;
756
r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
767
if (save_errno == EDQUOT) /* disk quota exceeded */
770
*dsize = D.dqb_curblocks;
777
/* If softlimit is zero, set it equal to hardlimit.
780
if (D.dqb_bsoftlimit==0)
781
D.dqb_bsoftlimit = D.dqb_bhardlimit;
783
/* Use softlimit to determine disk space, except when it has been exceeded */
785
if (D.dqb_bsoftlimit==0)
788
if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
790
*dsize = D.dqb_curblocks;
792
*dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
793
*dsize = D.dqb_bsoftlimit;
798
#elif defined (IRIX6)
799
/****************************************************************************
800
try to get the disk space from disk quotas (IRIX 6.2 version)
801
****************************************************************************/
803
#include <sys/quota.h>
806
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
811
struct fs_disk_quota F;
818
/* find the block device file */
820
if ( sys_stat(path, &S) == -1 ) {
826
fp = setmntent(MOUNTED,"r");
829
while ((mnt = getmntent(fp))) {
830
if ( sys_stat(mnt->mnt_dir,&S) == -1 )
832
if (S.st_dev == devno) {
845
set_effective_uid(0);
847
/* Use softlimit to determine disk space, except when it has been exceeded */
851
if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
853
r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
860
/* Use softlimit to determine disk space, except when it has been exceeded */
862
(D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
863
(D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
864
(D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
865
(D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
869
*dsize = D.dqb_curblocks;
871
else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
877
*dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
878
*dsize = D.dqb_bsoftlimit;
882
else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
884
r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
890
DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
894
/* No quota for this user. */
895
if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
900
/* Use softlimit to determine disk space, except when it has been exceeded */
902
(F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
903
(F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
904
(F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
905
(F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
913
*dfree = (F.d_blk_softlimit - F.d_bcount);
914
*dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
930
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
931
#include <ufs/ufs/quota.h>
932
#include <machine/param.h>
934
/* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
935
#include <jfs/quota.h>
936
/* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
937
#define dqb_curfiles dqb_curinodes
938
#define dqb_fhardlimit dqb_ihardlimit
939
#define dqb_fsoftlimit dqb_isoftlimit
940
#else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
941
#include <sys/quota.h>
945
#if defined(__FreeBSD__) || defined(__DragonFly__)
948
#include <rpc/types.h>
949
#include <rpcsvc/rquota.h>
950
#ifdef HAVE_RPC_NETTYPE_H
951
#include <rpc/nettype.h>
955
static int quotastat;
957
static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
959
if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
961
if (!xdr_int(xdrsp, &args->gqa_uid))
966
static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
968
if (!xdr_int(xdrsp, "astat)) {
969
DEBUG(6,("nfs_quotas: Status bad or zero\n"));
972
if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
973
DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
976
if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
977
DEBUG(6,("nfs_quotas: Active bad or zero\n"));
980
if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
981
DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
984
if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
985
DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
988
if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
989
DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
995
/* Works on FreeBSD, too. :-) */
996
static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
998
uid_t uid = euser_id;
1000
char *mnttype = nfspath;
1002
struct getquota_rslt gqr;
1003
struct getquota_args args;
1004
char *cutstr, *pathname, *host, *testpath;
1006
static struct timeval timeout = {2,0};
1007
enum clnt_stat clnt_stat;
1010
*bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
1012
len=strcspn(mnttype, ":");
1013
pathname=strstr(mnttype, ":");
1014
cutstr = (char *) SMB_MALLOC(len+1);
1018
memset(cutstr, '\0', len+1);
1019
host = strncat(cutstr,mnttype, sizeof(char) * len );
1020
DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1021
DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1022
testpath=strchr_m(mnttype, ':');
1023
args.gqa_pathp = testpath+1;
1026
DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1028
if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1033
clnt->cl_auth = authunix_create_default();
1034
DEBUG(9,("nfs_quotas: auth_success\n"));
1036
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);
1038
if (clnt_stat != RPC_SUCCESS) {
1039
DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1045
* quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1046
* no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1047
* something sensible.
1050
switch ( quotastat ) {
1052
DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
1057
DEBUG(9,("nfs_quotas: Good quota data\n"));
1058
D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1059
D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1060
D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1065
D.dqb_bsoftlimit = 1;
1066
D.dqb_curblocks = 1;
1067
DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
1071
DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
1075
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",
1077
gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1078
gqr.getquota_rslt_u.gqr_rquota.rq_active,
1079
gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1080
gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1081
gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1083
if (D.dqb_bsoftlimit == 0)
1084
D.dqb_bsoftlimit = D.dqb_bhardlimit;
1085
if (D.dqb_bsoftlimit == 0)
1088
*bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1089
*dsize = D.dqb_bsoftlimit;
1091
if (D.dqb_curblocks == D.dqb_curblocks == 1)
1094
if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1096
*dsize = D.dqb_curblocks;
1098
*dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1104
auth_destroy(clnt->cl_auth);
1108
DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1111
DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1117
/****************************************************************************
1118
try to get the disk space from disk quotas - default version
1119
****************************************************************************/
1121
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1126
#if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1130
/* find the block device file */
1133
/* Need to set the cache flag to 1 for HPUX. Seems
1134
* to have a significant performance boost when
1135
* lstat calls on /dev access this function.
1137
if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0))
1139
if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0))
1141
#endif /* ifdef HPUX */
1143
#endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1145
euser_id = geteuid();
1148
/* for HPUX, real uid must be same as euid to execute quotactl for euid */
1150
if (set_re_uid() != 0) return False;
1152
r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1156
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1158
/* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1160
#if defined(__FreeBSD__) || defined(__DragonFly__)
1162
struct statfs *mnts;
1166
if (sys_stat(path,&st) < 0)
1170
mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1174
for (i = 0; i < mntsize; i++) {
1175
if (sys_stat(mnts[i].f_mntonname,&st) < 0)
1177
if (st.st_dev == devno)
1185
set_effective_uid(0);
1187
#if defined(__FreeBSD__) || defined(__DragonFly__)
1188
if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1190
retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1196
egrp_id = getegid();
1197
r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1199
/* As FreeBSD has group quotas, if getting the user
1200
quota fails, try getting the group instead. */
1202
r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1208
/* AIX has both USER and GROUP quotas:
1209
Get the USER quota (ohnielse@fysik.dtu.dk) */
1211
if (set_re_uid() != 0)
1213
r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1215
#else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1216
r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1217
#endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1220
/* Use softlimit to determine disk space, except when it has been exceeded */
1221
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1223
#else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1225
#endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1229
if (errno == EDQUOT)
1232
*dsize =D.dqb_curblocks;
1238
/* If softlimit is zero, set it equal to hardlimit.
1241
if (D.dqb_bsoftlimit==0)
1242
D.dqb_bsoftlimit = D.dqb_bhardlimit;
1244
if (D.dqb_bsoftlimit==0)
1246
/* Use softlimit to determine disk space, except when it has been exceeded */
1247
if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1248
#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1249
||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1253
*dsize = D.dqb_curblocks;
1256
*dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1257
*dsize = D.dqb_bsoftlimit;
1264
#if defined(VXFS_QUOTA)
1266
/****************************************************************************
1267
Try to get the disk space from Veritas disk quotas.
1268
David Lee <T.D.Lee@durham.ac.uk> August 1999.
1270
Background assumptions:
1271
Potentially under many Operating Systems. Initially Solaris 2.
1273
My guess is that Veritas is largely, though not entirely,
1274
independent of OS. So I have separated it out.
1276
There may be some details. For example, OS-specific "include" files.
1278
It is understood that HPUX 10 somehow gets Veritas quotas without
1279
any special effort; if so, this routine need not be compiled in.
1280
Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1283
It is understood that Veritas do not publicly support this ioctl interface.
1284
Rather their preference would be for the user (us) to call the native
1285
OS and then for the OS itself to call through to the VxFS filesystem.
1286
Presumably HPUX 10, see above, does this.
1289
Add your OS to "IFLIST" below.
1290
Get it to compile successfully:
1291
Almost certainly "include"s require attention: see SUNOS5.
1292
In the main code above, arrange for it to be called: see SUNOS5.
1295
****************************************************************************/
1298
* This "if" is a list of ports:
1299
* if defined(OS1) || defined(OS2) || ...
1304
#include <sys/fs/vx_solaris.h>
1306
#include <sys/fs/vx_machdep.h>
1307
#include <sys/fs/vx_layout.h>
1308
#include <sys/fs/vx_quota.h>
1309
#include <sys/fs/vx_aioctl.h>
1310
#include <sys/fs/vx_ioctl.h>
1312
BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1314
uid_t user_id, euser_id;
1317
struct vx_quotctl quotabuf;
1318
struct vx_genioctl genbuf;
1323
* "name" may or may not include a trailing "/quotas".
1324
* Arranging consistency of calling here in "quotas.c" may not be easy and
1325
* it might be easier to examine and adjust it here.
1326
* Fortunately, VxFS seems not to mind at present.
1328
pstrcpy(qfname, name) ;
1329
/* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1331
euser_id = geteuid();
1332
set_effective_uid(0);
1334
DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1335
if((file=sys_open(qfname, O_RDONLY,0))<0) {
1336
set_effective_uid(euser_id);
1339
genbuf.ioc_cmd = VX_QUOTACTL;
1340
genbuf.ioc_up = (void *) "abuf;
1342
quotabuf.cmd = VX_GETQUOTA;
1343
quotabuf.uid = euser_id;
1344
quotabuf.addr = (caddr_t) &D;
1345
ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1348
set_effective_uid(euser_id);
1351
DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1355
/* If softlimit is zero, set it equal to hardlimit.
1358
if (D.dqb_bsoftlimit==0)
1359
D.dqb_bsoftlimit = D.dqb_bhardlimit;
1361
/* Use softlimit to determine disk space. A user exceeding the quota is told
1362
* that there's no space left. Writes might actually work for a bit if the
1363
* hardlimit is set higher than softlimit. Effectively the disk becomes
1364
* made of rubber latex and begins to expand to accommodate the user :-)
1366
DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1367
path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1368
D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1370
if (D.dqb_bsoftlimit==0)
1373
*dsize = D.dqb_bsoftlimit;
1375
if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1377
*dsize = D.dqb_curblocks;
1379
*dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1381
DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1382
path,(double)*bsize,(double)*dfree,(double)*dsize));
1387
#endif /* SUNOS5 || ... */
1389
#endif /* VXFS_QUOTA */
1391
#else /* WITH_QUOTAS */
1393
BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1395
(*bsize) = 512; /* This value should be ignored */
1397
/* And just to be sure we set some values that hopefully */
1398
/* will be larger that any possible real-world value */
1399
(*dfree) = (SMB_BIG_UINT)-1;
1400
(*dsize) = (SMB_BIG_UINT)-1;
1402
/* As we have select not to use quotas, allways fail */
1405
#endif /* WITH_QUOTAS */
1407
#else /* HAVE_SYS_QUOTAS */
1408
/* wrapper to the new sys_quota interface
1409
this file should be removed later
1411
BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1420
r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1422
/* Use softlimit to determine disk space, except when it has been exceeded */
1425
if (errno == EDQUOT) {
1427
*dsize =D.curblocks;
1430
goto try_group_quota;
1434
/* Use softlimit to determine disk space, except when it has been exceeded */
1436
(D.softlimit && D.curblocks >= D.softlimit) ||
1437
(D.hardlimit && D.curblocks >= D.hardlimit) ||
1438
(D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1439
(D.ihardlimit && D.curinodes>=D.ihardlimit)
1442
*dsize = D.curblocks;
1443
} else if (D.softlimit==0 && D.hardlimit==0) {
1444
goto try_group_quota;
1446
if (D.softlimit == 0)
1447
D.softlimit = D.hardlimit;
1448
*dfree = D.softlimit - D.curblocks;
1449
*dsize = D.softlimit;
1458
r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1460
/* Use softlimit to determine disk space, except when it has been exceeded */
1463
if (errno == EDQUOT) {
1465
*dsize =D.curblocks;
1472
/* Use softlimit to determine disk space, except when it has been exceeded */
1474
(D.softlimit && D.curblocks >= D.softlimit) ||
1475
(D.hardlimit && D.curblocks >= D.hardlimit) ||
1476
(D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1477
(D.ihardlimit && D.curinodes>=D.ihardlimit)
1480
*dsize = D.curblocks;
1481
} else if (D.softlimit==0 && D.hardlimit==0) {
1484
if (D.softlimit == 0)
1485
D.softlimit = D.hardlimit;
1486
*dfree = D.softlimit - D.curblocks;
1487
*dsize = D.softlimit;
1492
#endif /* HAVE_SYS_QUOTAS */