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 3 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, see <http://www.gnu.org/licenses/>.
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
30 #define DBGC_CLASS DBGC_QUOTA
32 #ifndef HAVE_SYS_QUOTAS
34 /* just a quick hack because sysquotas.h is included before linux/quota.h */
35 #ifdef QUOTABLOCK_SIZE
36 #undef QUOTABLOCK_SIZE
41 #if defined(VXFS_QUOTA)
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>
48 bool disk_quotas_vxfs(const char *name
, char *path
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
);
50 #endif /* VXFS_QUOTA */
54 #include <sys/types.h>
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.
63 #include "samba_linux_quota.h"
65 typedef struct _LINUX_SMB_DISK_QUOTA
{
67 uint64_t hardlimit
; /* In bsize units. */
68 uint64_t softlimit
; /* In bsize units. */
69 uint64_t curblocks
; /* In bsize units. */
70 uint64_t ihardlimit
; /* inode hard limit. */
71 uint64_t isoftlimit
; /* inode soft limit. */
72 uint64_t curinodes
; /* Current used inodes. */
73 } LINUX_SMB_DISK_QUOTA
;
76 #ifdef HAVE_LINUX_DQBLK_XFS_H
77 #include <linux/dqblk_xfs.h>
79 /****************************************************************************
80 Abstract out the XFS Quota Manager quota get call.
81 ****************************************************************************/
83 static int get_smb_linux_xfs_quota(char *path
, uid_t euser_id
, gid_t egrp_id
, LINUX_SMB_DISK_QUOTA
*dp
)
85 struct fs_disk_quota D
;
90 ret
= quotactl(QCMD(Q_XGETQUOTA
,USRQUOTA
), path
, euser_id
, (caddr_t
)&D
);
93 ret
= quotactl(QCMD(Q_XGETQUOTA
,GRPQUOTA
), path
, egrp_id
, (caddr_t
)&D
);
98 dp
->bsize
= (uint64_t)512;
99 dp
->softlimit
= (uint64_t)D
.d_blk_softlimit
;
100 dp
->hardlimit
= (uint64_t)D
.d_blk_hardlimit
;
101 dp
->ihardlimit
= (uint64_t)D
.d_ino_hardlimit
;
102 dp
->isoftlimit
= (uint64_t)D
.d_ino_softlimit
;
103 dp
->curinodes
= (uint64_t)D
.d_icount
;
104 dp
->curblocks
= (uint64_t)D
.d_bcount
;
109 static int get_smb_linux_xfs_quota(char *path
, uid_t euser_id
, gid_t egrp_id
, LINUX_SMB_DISK_QUOTA
*dp
)
111 DEBUG(0,("XFS quota support not available\n"));
118 /****************************************************************************
119 Abstract out the old and new Linux quota get calls.
120 ****************************************************************************/
122 static int get_smb_linux_v1_quota(char *path
, uid_t euser_id
, gid_t egrp_id
, LINUX_SMB_DISK_QUOTA
*dp
)
124 struct v1_kern_dqblk D
;
129 ret
= quotactl(QCMD(Q_V1_GETQUOTA
,USRQUOTA
), path
, euser_id
, (caddr_t
)&D
);
131 if (ret
&& errno
!= EDQUOT
)
132 ret
= quotactl(QCMD(Q_V1_GETQUOTA
,GRPQUOTA
), path
, egrp_id
, (caddr_t
)&D
);
134 if (ret
&& errno
!= EDQUOT
)
137 dp
->bsize
= (uint64_t)QUOTABLOCK_SIZE
;
138 dp
->softlimit
= (uint64_t)D
.dqb_bsoftlimit
;
139 dp
->hardlimit
= (uint64_t)D
.dqb_bhardlimit
;
140 dp
->ihardlimit
= (uint64_t)D
.dqb_ihardlimit
;
141 dp
->isoftlimit
= (uint64_t)D
.dqb_isoftlimit
;
142 dp
->curinodes
= (uint64_t)D
.dqb_curinodes
;
143 dp
->curblocks
= (uint64_t)D
.dqb_curblocks
;
148 static int get_smb_linux_v2_quota(char *path
, uid_t euser_id
, gid_t egrp_id
, LINUX_SMB_DISK_QUOTA
*dp
)
150 struct v2_kern_dqblk D
;
155 ret
= quotactl(QCMD(Q_V2_GETQUOTA
,USRQUOTA
), path
, euser_id
, (caddr_t
)&D
);
157 if (ret
&& errno
!= EDQUOT
)
158 ret
= quotactl(QCMD(Q_V2_GETQUOTA
,GRPQUOTA
), path
, egrp_id
, (caddr_t
)&D
);
160 if (ret
&& errno
!= EDQUOT
)
163 dp
->bsize
= (uint64_t)QUOTABLOCK_SIZE
;
164 dp
->softlimit
= (uint64_t)D
.dqb_bsoftlimit
;
165 dp
->hardlimit
= (uint64_t)D
.dqb_bhardlimit
;
166 dp
->ihardlimit
= (uint64_t)D
.dqb_ihardlimit
;
167 dp
->isoftlimit
= (uint64_t)D
.dqb_isoftlimit
;
168 dp
->curinodes
= (uint64_t)D
.dqb_curinodes
;
169 dp
->curblocks
= ((uint64_t)D
.dqb_curspace
) / dp
->bsize
;
174 /****************************************************************************
175 Brand-new generic quota interface.
176 ****************************************************************************/
178 static int get_smb_linux_gen_quota(char *path
, uid_t euser_id
, gid_t egrp_id
, LINUX_SMB_DISK_QUOTA
*dp
)
185 ret
= quotactl(QCMD(Q_GETQUOTA
,USRQUOTA
), path
, euser_id
, (caddr_t
)&D
);
187 if (ret
&& errno
!= EDQUOT
)
188 ret
= quotactl(QCMD(Q_GETQUOTA
,GRPQUOTA
), path
, egrp_id
, (caddr_t
)&D
);
190 if (ret
&& errno
!= EDQUOT
)
193 dp
->bsize
= (uint64_t)QUOTABLOCK_SIZE
;
194 dp
->softlimit
= (uint64_t)D
.dqb_bsoftlimit
;
195 dp
->hardlimit
= (uint64_t)D
.dqb_bhardlimit
;
196 dp
->ihardlimit
= (uint64_t)D
.dqb_ihardlimit
;
197 dp
->isoftlimit
= (uint64_t)D
.dqb_isoftlimit
;
198 dp
->curinodes
= (uint64_t)D
.dqb_curinodes
;
199 dp
->curblocks
= ((uint64_t)D
.dqb_curspace
) / dp
->bsize
;
204 /****************************************************************************
205 Try to get the disk space from disk quotas (LINUX version).
206 ****************************************************************************/
208 bool disk_quotas(const char *path
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
213 LINUX_SMB_DISK_QUOTA D
;
222 euser_id
= geteuid();
225 /* find the block device file */
227 if (sys_stat(path
, &S
, false) == -1 )
230 devno
= S
.st_ex_dev
;
232 if ((fp
= setmntent(MOUNTED
,"r")) == NULL
)
237 while ((mnt
= getmntent(fp
))) {
238 if (sys_stat(mnt
->mnt_dir
, &S
, false) == -1)
241 if (S
.st_ex_dev
== devno
) {
254 if (strcmp(mnt
->mnt_type
, "xfs")==0) {
255 r
=get_smb_linux_xfs_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
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
);
267 /* Use softlimit to determine disk space, except when it has been exceeded */
270 if (errno
== EDQUOT
) {
279 /* Use softlimit to determine disk space, except when it has been exceeded */
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
)
287 *dsize
= D
.curblocks
;
288 } else if (D
.softlimit
==0 && D
.hardlimit
==0) {
291 if (D
.softlimit
== 0)
292 D
.softlimit
= D
.hardlimit
;
293 *dfree
= D
.softlimit
- D
.curblocks
;
294 *dsize
= D
.softlimit
;
302 #include <sys/quota.h>
305 /****************************************************************************
306 try to get the disk space from disk quotas (CRAY VERSION)
307 ****************************************************************************/
309 bool disk_quotas(const char *path
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
313 SMB_STRUCT_STAT sbuf
;
315 struct q_request request
;
316 struct qf_header header
;
317 int quota_default
= 0 ;
320 if (sys_stat(path
, &sbuf
, false) == -1) {
324 devno
= sbuf
.st_ex_dev
;
326 if ((fd
= setmntent(KMTAB
)) == NULL
) {
330 while ((mnt
= getmntent(fd
)) != NULL
) {
331 if (sys_stat(mnt
->mnt_dir
, &sbuf
, false) {
334 if (sbuf
.st_ex_dev
== devno
) {
340 name
= talloc_strdup(talloc_tos(), mnt
->mnt_dir
);
350 request
.qf_magic
= QF_MAGIC
;
351 request
.qf_entry
.id
= geteuid() ;
353 if (quotactl(name
, Q_GETQUOTA
, &request
) == -1) {
361 if (request
.qf_entry
.user_q
.f_quota
== QFV_DEFAULT
) {
362 if (!quota_default
) {
363 if (quotactl(name
, Q_GETHEADER
, &header
) == -1) {
366 quota_default
= header
.user_h
.def_fq
;
369 *dfree
= quota_default
;
370 } else if (request
.qf_entry
.user_q
.f_quota
== QFV_PREVENT
) {
373 *dfree
= request
.qf_entry
.user_q
.f_quota
;
376 *dsize
= request
.qf_entry
.user_q
.f_use
;
378 if (*dfree
< *dsize
) {
384 *bsize
= 4096 ; /* Cray blocksize */
389 #elif defined(SUNOS5) || defined(SUNOS4)
392 #include <sys/param.h>
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>
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 ****************************************************************************/
411 #include <rpc/types.h>
412 #include <rpcsvc/rquota.h>
413 #include <rpc/nettype.h>
416 static int my_xdr_getquota_args(XDR
*xdrsp
, struct getquota_args
*args
)
418 if (!xdr_string(xdrsp
, &args
->gqa_pathp
, RQ_PATHLEN
))
420 if (!xdr_int(xdrsp
, &args
->gqa_uid
))
425 static int my_xdr_getquota_rslt(XDR
*xdrsp
, struct getquota_rslt
*gqr
)
429 if (!xdr_int(xdrsp
, "astat
)) {
430 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
433 gqr
->status
= quotastat
;
435 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsize
)) {
436 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
439 if (!xdr_bool(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_active
)) {
440 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
443 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
)) {
444 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
447 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
)) {
448 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
451 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_curblocks
)) {
452 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
458 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
459 static bool nfs_quotas(char *nfspath
, uid_t euser_id
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
461 uid_t uid
= euser_id
;
463 char *mnttype
= nfspath
;
465 struct getquota_rslt gqr
;
466 struct getquota_args args
;
467 char *cutstr
, *pathname
, *host
, *testpath
;
469 static struct timeval timeout
= {2,0};
470 enum clnt_stat clnt_stat
;
473 *bsize
= *dfree
= *dsize
= (uint64_t)0;
475 len
=strcspn(mnttype
, ":");
476 pathname
=strstr(mnttype
, ":");
477 cutstr
= (char *) SMB_MALLOC(len
+1);
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;
489 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host
, RQUOTAPROG
, RQUOTAVERS
, "udp"));
491 if ((clnt
= clnt_create(host
, RQUOTAPROG
, RQUOTAVERS
, "udp")) == NULL
) {
496 clnt
->cl_auth
= authunix_create_default();
497 DEBUG(9,("nfs_quotas: auth_success\n"));
499 clnt_stat
=clnt_call(clnt
, RQUOTAPROC_GETQUOTA
, my_xdr_getquota_args
, (caddr_t
)&args
, my_xdr_getquota_rslt
, (caddr_t
)&gqr
, timeout
);
501 if (clnt_stat
!= RPC_SUCCESS
) {
502 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
508 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
509 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
510 * something sensible.
513 switch (gqr
.status
) {
515 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr
.status
));
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
;
528 D
.dqb_bsoftlimit
= 1;
530 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr
.status
));
534 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr
.status
));
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",
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
));
546 *bsize
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
;
547 *dsize
= D
.dqb_bsoftlimit
;
549 if (D
.dqb_curblocks
== 1)
552 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
554 *dsize
= D
.dqb_curblocks
;
556 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
562 auth_destroy(clnt
->cl_auth
);
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
));
569 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
574 /****************************************************************************
575 try to get the disk space from disk quotas (SunOS & Solaris2 version)
576 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
577 ****************************************************************************/
579 bool disk_quotas(const char *path
,
588 struct quotctl command
;
596 SMB_STRUCT_STAT sbuf
;
600 euser_id
= geteuid();
602 if (sys_stat(path
, &sbuf
, false) {
606 devno
= sbuf
.st_ex_dev
;
607 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
608 path
, (unsigned int)devno
));
610 if ((fd
= sys_fopen(MNTTAB
, "r")) == NULL
) {
614 while (getmntent(fd
, &mnt
) == 0) {
615 if (sys_stat(mnt
.mnt_mountp
, &sbuf
, false) == -1) {
619 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
620 mnt
.mnt_mountp
, (unsigned int)devno
));
622 /* quotas are only on vxfs, UFS or NFS */
623 if ((sbuf
.st_ex_dev
== devno
) && (
624 strcmp( mnt
.mnt_fstype
, MNTTYPE_UFS
) == 0 ||
625 strcmp( mnt
.mnt_fstype
, "nfs" ) == 0 ||
626 strcmp( mnt
.mnt_fstype
, "vxfs" ) == 0 )) {
628 name
= talloc_asprintf(talloc_tos(),
637 if ((fd
= setmntent(MOUNTED
, "r")) == NULL
) {
641 while ((mnt
= getmntent(fd
)) != NULL
) {
642 if (sys_stat(mnt
->mnt_dir
, &sbuf
, false) == -1) {
645 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
647 (unsigned int)sbuf
.st_ex_dev
));
648 if (sbuf
.st_ex_dev
== devno
) {
650 name
= talloc_strdup(talloc_tos(),
668 if (strcmp(mnt
.mnt_fstype
, "nfs") == 0) {
670 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n",
672 retval
= nfs_quotas(mnt
.mnt_special
,
673 euser_id
, bsize
, dfree
, dsize
);
678 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name
));
679 if((file
=sys_open(name
, O_RDONLY
,0))<0) {
683 command
.op
= Q_GETQUOTA
;
684 command
.uid
= euser_id
;
685 command
.addr
= (caddr_t
) &D
;
686 ret
= ioctl(file
, Q_QUOTACTL
, &command
);
689 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name
));
690 ret
= quotactl(Q_GETQUOTA
, name
, euser_id
, &D
);
696 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n",
699 #if defined(SUNOS5) && defined(VXFS_QUOTA)
700 /* If normal quotactl() fails, try vxfs private calls */
701 set_effective_uid(euser_id
);
702 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt
.mnt_fstype
));
703 if ( 0 == strcmp ( mnt
.mnt_fstype
, "vxfs" )) {
705 retval
= disk_quotas_vxfs(name
, path
,
706 bsize
, dfree
, dsize
);
714 /* If softlimit is zero, set it equal to hardlimit.
717 if (D
.dqb_bsoftlimit
==0) {
718 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
721 /* Use softlimit to determine disk space. A user exceeding the quota
722 * is told that there's no space left. Writes might actually work for
723 * a bit if the hardlimit is set higher than softlimit. Effectively
724 * the disk becomes made of rubber latex and begins to expand to
725 * accommodate the user :-)
728 if (D
.dqb_bsoftlimit
==0)
731 *dsize
= D
.dqb_bsoftlimit
;
733 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
735 *dsize
= D
.dqb_curblocks
;
737 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
740 DEBUG(5,("disk_quotas for path \"%s\" returning "
741 "bsize %.0f, dfree %.0f, dsize %.0f\n",
742 path
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
749 #include <ufs/quota.h>
751 /****************************************************************************
752 try to get the disk space from disk quotas - OSF1 version
753 ****************************************************************************/
755 bool disk_quotas(const char *path
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
763 * This code presumes that OSF1 will only
764 * give out quota info when the real uid
765 * matches the effective uid. JRA.
767 euser_id
= geteuid();
769 if (set_re_uid() != 0) return False
;
771 r
= quotactl(path
,QCMD(Q_GETQUOTA
, USRQUOTA
),euser_id
,(char *) &D
);
782 if (save_errno
== EDQUOT
) /* disk quota exceeded */
785 *dsize
= D
.dqb_curblocks
;
792 /* If softlimit is zero, set it equal to hardlimit.
795 if (D
.dqb_bsoftlimit
==0)
796 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
798 /* Use softlimit to determine disk space, except when it has been exceeded */
800 if (D
.dqb_bsoftlimit
==0)
803 if ((D
.dqb_curblocks
>D
.dqb_bsoftlimit
)) {
805 *dsize
= D
.dqb_curblocks
;
807 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
808 *dsize
= D
.dqb_bsoftlimit
;
813 #elif defined (IRIX6)
814 /****************************************************************************
815 try to get the disk space from disk quotas (IRIX 6.2 version)
816 ****************************************************************************/
818 #include <sys/quota.h>
821 bool disk_quotas(const char *path
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
826 struct fs_disk_quota F
;
833 /* find the block device file */
835 if ( sys_stat(path
, &S
, false) == -1 ) {
839 devno
= S
.st_ex_dev
;
841 fp
= setmntent(MOUNTED
,"r");
844 while ((mnt
= getmntent(fp
))) {
845 if ( sys_stat(mnt
->mnt_dir
, &S
, false) == -1 )
847 if (S
.st_ex_dev
== devno
) {
861 /* Use softlimit to determine disk space, except when it has been exceeded */
865 if ( 0 == strcmp ( mnt
->mnt_type
, "efs" ))
867 r
=quotactl (Q_GETQUOTA
, mnt
->mnt_fsname
, euser_id
, (caddr_t
) &D
);
874 /* Use softlimit to determine disk space, except when it has been exceeded */
876 (D
.dqb_bsoftlimit
&& D
.dqb_curblocks
>=D
.dqb_bsoftlimit
) ||
877 (D
.dqb_bhardlimit
&& D
.dqb_curblocks
>=D
.dqb_bhardlimit
) ||
878 (D
.dqb_fsoftlimit
&& D
.dqb_curfiles
>=D
.dqb_fsoftlimit
) ||
879 (D
.dqb_fhardlimit
&& D
.dqb_curfiles
>=D
.dqb_fhardlimit
)
883 *dsize
= D
.dqb_curblocks
;
885 else if (D
.dqb_bsoftlimit
==0 && D
.dqb_bhardlimit
==0)
891 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
892 *dsize
= D
.dqb_bsoftlimit
;
896 else if ( 0 == strcmp ( mnt
->mnt_type
, "xfs" ))
898 r
=quotactl (Q_XGETQUOTA
, mnt
->mnt_fsname
, euser_id
, (caddr_t
) &F
);
904 DEBUG(5, ("quotactl for uid=%u: %s", euser_id
, strerror(errno
)));
908 /* No quota for this user. */
909 if (F
.d_blk_softlimit
==0 && F
.d_blk_hardlimit
==0)
914 /* Use softlimit to determine disk space, except when it has been exceeded */
916 (F
.d_blk_softlimit
&& F
.d_bcount
>=F
.d_blk_softlimit
) ||
917 (F
.d_blk_hardlimit
&& F
.d_bcount
>=F
.d_blk_hardlimit
) ||
918 (F
.d_ino_softlimit
&& F
.d_icount
>=F
.d_ino_softlimit
) ||
919 (F
.d_ino_hardlimit
&& F
.d_icount
>=F
.d_ino_hardlimit
)
927 *dfree
= (F
.d_blk_softlimit
- F
.d_bcount
);
928 *dsize
= F
.d_blk_softlimit
? F
.d_blk_softlimit
: F
.d_blk_hardlimit
;
944 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
945 #include <ufs/ufs/quota.h>
946 #include <machine/param.h>
948 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
949 #include <jfs/quota.h>
950 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
951 #define dqb_curfiles dqb_curinodes
952 #define dqb_fhardlimit dqb_ihardlimit
953 #define dqb_fsoftlimit dqb_isoftlimit
954 #ifdef _AIXVERSION_530
955 #include <sys/statfs.h>
956 #include <sys/vmount.h>
958 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
959 #include <sys/quota.h>
963 #if defined(__FreeBSD__) || defined(__DragonFly__)
966 #include <rpc/types.h>
967 #include <rpcsvc/rquota.h>
968 #ifdef HAVE_RPC_NETTYPE_H
969 #include <rpc/nettype.h>
973 static int my_xdr_getquota_args(XDR
*xdrsp
, struct getquota_args
*args
)
975 if (!xdr_string(xdrsp
, &args
->gqa_pathp
, RQ_PATHLEN
))
977 if (!xdr_int(xdrsp
, &args
->gqa_uid
))
982 static int my_xdr_getquota_rslt(XDR
*xdrsp
, struct getquota_rslt
*gqr
)
986 if (!xdr_int(xdrsp
, "astat
)) {
987 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
990 gqr
->status
= quotastat
;
992 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsize
)) {
993 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
996 if (!xdr_bool(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_active
)) {
997 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
1000 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
)) {
1001 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
1004 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
)) {
1005 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
1008 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_curblocks
)) {
1009 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
1015 /* Works on FreeBSD, too. :-) */
1016 static bool nfs_quotas(char *nfspath
, uid_t euser_id
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
1018 uid_t uid
= euser_id
;
1020 char *mnttype
= nfspath
;
1022 struct getquota_rslt gqr
;
1023 struct getquota_args args
;
1024 char *cutstr
, *pathname
, *host
, *testpath
;
1026 static struct timeval timeout
= {2,0};
1027 enum clnt_stat clnt_stat
;
1030 *bsize
= *dfree
= *dsize
= (uint64_t)0;
1032 len
=strcspn(mnttype
, ":");
1033 pathname
=strstr(mnttype
, ":");
1034 cutstr
= (char *) SMB_MALLOC(len
+1);
1038 memset(cutstr
, '\0', len
+1);
1039 host
= strncat(cutstr
,mnttype
, sizeof(char) * len
);
1040 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr
));
1041 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype
));
1042 testpath
=strchr_m(mnttype
, ':');
1043 args
.gqa_pathp
= testpath
+1;
1046 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host
, RQUOTAPROG
, RQUOTAVERS
, "udp"));
1048 if ((clnt
= clnt_create(host
, RQUOTAPROG
, RQUOTAVERS
, "udp")) == NULL
) {
1053 clnt
->cl_auth
= authunix_create_default();
1054 DEBUG(9,("nfs_quotas: auth_success\n"));
1056 clnt_stat
=clnt_call(clnt
, RQUOTAPROC_GETQUOTA
, (const xdrproc_t
) my_xdr_getquota_args
, (caddr_t
)&args
, (const xdrproc_t
) my_xdr_getquota_rslt
, (caddr_t
)&gqr
, timeout
);
1058 if (clnt_stat
!= RPC_SUCCESS
) {
1059 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1065 * gqr->status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1066 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1067 * something sensible.
1070 switch (gqr
.status
) {
1072 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr
.status
));
1077 DEBUG(9,("nfs_quotas: Good quota data\n"));
1078 D
.dqb_bsoftlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
;
1079 D
.dqb_bhardlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
;
1080 D
.dqb_curblocks
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
;
1085 D
.dqb_bsoftlimit
= 1;
1086 D
.dqb_curblocks
= 1;
1087 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr
.status
));
1091 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr
.status
));
1095 DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
1097 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
,
1098 gqr
.getquota_rslt_u
.gqr_rquota
.rq_active
,
1099 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
,
1100 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
,
1101 gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
));
1103 if (D
.dqb_bsoftlimit
== 0)
1104 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
1105 if (D
.dqb_bsoftlimit
== 0)
1108 *bsize
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
;
1109 *dsize
= D
.dqb_bsoftlimit
;
1111 if (D
.dqb_curblocks
== 1)
1114 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
1116 *dsize
= D
.dqb_curblocks
;
1118 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1124 auth_destroy(clnt
->cl_auth
);
1128 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args
.gqa_pathp
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
1131 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1137 /****************************************************************************
1138 try to get the disk space from disk quotas - default version
1139 ****************************************************************************/
1141 bool disk_quotas(const char *path
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
1146 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1150 /* find the block device file */
1153 /* Need to set the cache flag to 1 for HPUX. Seems
1154 * to have a significant performance boost when
1155 * lstat calls on /dev access this function.
1157 if ((sys_stat(path
, &S
, false)<0)
1158 || (devnm(S_IFBLK
, S
.st_ex_dev
, dev_disk
, 256, 1)<0))
1160 if ((sys_stat(path
, &S
, false)<0)
1161 || (devnm(S_IFBLK
, S
.st_ex_dev
, dev_disk
, 256, 0)<0))
1163 #endif /* ifdef HPUX */
1165 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1167 euser_id
= geteuid();
1170 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1172 if (set_re_uid() != 0) return False
;
1174 r
=quotactl(Q_GETQUOTA
, dev_disk
, euser_id
, &D
);
1178 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1180 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1182 #if defined(__FreeBSD__) || defined(__DragonFly__)
1184 struct statfs
*mnts
;
1188 if (sys_stat(path
, &st
, false) < 0)
1190 devno
= st
.st_ex_dev
;
1192 mntsize
= getmntinfo(&mnts
,MNT_NOWAIT
);
1196 for (i
= 0; i
< mntsize
; i
++) {
1197 if (sys_stat(mnts
[i
].f_mntonname
, &st
, false) < 0)
1199 if (st
.st_ex_dev
== devno
)
1208 #if defined(__FreeBSD__) || defined(__DragonFly__)
1209 if (strcmp(mnts
[i
].f_fstypename
,"nfs") == 0) {
1211 retval
= nfs_quotas(mnts
[i
].f_mntfromname
,euser_id
,bsize
,dfree
,dsize
);
1217 egrp_id
= getegid();
1218 r
= quotactl(path
,QCMD(Q_GETQUOTA
,USRQUOTA
),euser_id
,(char *) &D
);
1220 /* As FreeBSD has group quotas, if getting the user
1221 quota fails, try getting the group instead. */
1223 r
= quotactl(path
,QCMD(Q_GETQUOTA
,GRPQUOTA
),egrp_id
,(char *) &D
);
1229 /* AIX has both USER and GROUP quotas:
1230 Get the USER quota (ohnielse@fysik.dtu.dk) */
1231 #ifdef _AIXVERSION_530
1233 struct statfs statbuf
;
1234 quota64_t user_quota
;
1235 if (statfs(path
,&statbuf
) != 0)
1237 if(statbuf
.f_vfstype
== MNT_J2
)
1239 /* For some reason we need to be root for jfs2 */
1241 r
= quotactl(path
,QCMD(Q_J2GETQUOTA
,USRQUOTA
),euser_id
,(char *) &user_quota
);
1243 /* Copy results to old struct to let the following code work as before */
1244 D
.dqb_curblocks
= user_quota
.bused
;
1245 D
.dqb_bsoftlimit
= user_quota
.bsoft
;
1246 D
.dqb_bhardlimit
= user_quota
.bhard
;
1247 D
.dqb_curfiles
= user_quota
.iused
;
1248 D
.dqb_fsoftlimit
= user_quota
.isoft
;
1249 D
.dqb_fhardlimit
= user_quota
.ihard
;
1251 else if(statbuf
.f_vfstype
== MNT_JFS
)
1253 #endif /* AIX 5.3 */
1255 if (set_re_uid() != 0)
1257 r
= quotactl(path
,QCMD(Q_GETQUOTA
,USRQUOTA
),euser_id
,(char *) &D
);
1259 #ifdef _AIXVERSION_530
1262 r
= 1; /* Fail for other FS-types */
1264 #endif /* AIX 5.3 */
1265 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1266 r
=quotactl(Q_GETQUOTA
, dev_disk
, euser_id
, &D
);
1267 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1270 /* Use softlimit to determine disk space, except when it has been exceeded */
1271 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1273 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1275 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1279 if (errno
== EDQUOT
)
1282 *dsize
=D
.dqb_curblocks
;
1288 /* If softlimit is zero, set it equal to hardlimit.
1291 if (D
.dqb_bsoftlimit
==0)
1292 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
1294 if (D
.dqb_bsoftlimit
==0)
1296 /* Use softlimit to determine disk space, except when it has been exceeded */
1297 if ((D
.dqb_curblocks
>D
.dqb_bsoftlimit
)
1298 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1299 ||((D
.dqb_curfiles
>D
.dqb_fsoftlimit
) && (D
.dqb_fsoftlimit
!= 0))
1303 *dsize
= D
.dqb_curblocks
;
1306 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1307 *dsize
= D
.dqb_bsoftlimit
;
1314 #if defined(VXFS_QUOTA)
1316 /****************************************************************************
1317 Try to get the disk space from Veritas disk quotas.
1318 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1320 Background assumptions:
1321 Potentially under many Operating Systems. Initially Solaris 2.
1323 My guess is that Veritas is largely, though not entirely,
1324 independent of OS. So I have separated it out.
1326 There may be some details. For example, OS-specific "include" files.
1328 It is understood that HPUX 10 somehow gets Veritas quotas without
1329 any special effort; if so, this routine need not be compiled in.
1330 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1333 It is understood that Veritas do not publicly support this ioctl interface.
1334 Rather their preference would be for the user (us) to call the native
1335 OS and then for the OS itself to call through to the VxFS filesystem.
1336 Presumably HPUX 10, see above, does this.
1339 Add your OS to "IFLIST" below.
1340 Get it to compile successfully:
1341 Almost certainly "include"s require attention: see SUNOS5.
1342 In the main code above, arrange for it to be called: see SUNOS5.
1345 ****************************************************************************/
1348 * This "if" is a list of ports:
1349 * if defined(OS1) || defined(OS2) || ...
1354 #include <sys/fs/vx_solaris.h>
1356 #include <sys/fs/vx_machdep.h>
1357 #include <sys/fs/vx_layout.h>
1358 #include <sys/fs/vx_quota.h>
1359 #include <sys/fs/vx_aioctl.h>
1360 #include <sys/fs/vx_ioctl.h>
1362 bool disk_quotas_vxfs(const char *name
, char *path
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
1364 uid_t user_id
, euser_id
;
1367 struct vx_quotctl quotabuf
;
1368 struct vx_genioctl genbuf
;
1373 * "name" may or may not include a trailing "/quotas".
1374 * Arranging consistency of calling here in "quotas.c" may not be easy and
1375 * it might be easier to examine and adjust it here.
1376 * Fortunately, VxFS seems not to mind at present.
1378 qfname
= talloc_strdup(talloc_tos(), name
);
1382 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1384 euser_id
= geteuid();
1385 set_effective_uid(0);
1387 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname
));
1388 if((file
=sys_open(qfname
, O_RDONLY
,0))<0) {
1389 set_effective_uid(euser_id
);
1392 genbuf
.ioc_cmd
= VX_QUOTACTL
;
1393 genbuf
.ioc_up
= (void *) "abuf
;
1395 quotabuf
.cmd
= VX_GETQUOTA
;
1396 quotabuf
.uid
= euser_id
;
1397 quotabuf
.addr
= (caddr_t
) &D
;
1398 ret
= ioctl(file
, VX_ADMIN_IOCTL
, &genbuf
);
1401 set_effective_uid(euser_id
);
1404 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno
) ));
1408 /* If softlimit is zero, set it equal to hardlimit.
1411 if (D
.dqb_bsoftlimit
==0)
1412 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
1414 /* Use softlimit to determine disk space. A user exceeding the quota is told
1415 * that there's no space left. Writes might actually work for a bit if the
1416 * hardlimit is set higher than softlimit. Effectively the disk becomes
1417 * made of rubber latex and begins to expand to accommodate the user :-)
1419 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1420 path
, D
.dqb_curblocks
, D
.dqb_bsoftlimit
, D
.dqb_bhardlimit
,
1421 D
.dqb_curfiles
, D
.dqb_fsoftlimit
, D
.dqb_fhardlimit
));
1423 if (D
.dqb_bsoftlimit
==0)
1426 *dsize
= D
.dqb_bsoftlimit
;
1428 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
1430 *dsize
= D
.dqb_curblocks
;
1432 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1434 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1435 path
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
1440 #endif /* SUNOS5 || ... */
1442 #endif /* VXFS_QUOTA */
1444 #else /* WITH_QUOTAS */
1446 bool disk_quotas(const char *path
,uint64_t *bsize
,uint64_t *dfree
,uint64_t *dsize
)
1448 (*bsize
) = 512; /* This value should be ignored */
1450 /* And just to be sure we set some values that hopefully */
1451 /* will be larger that any possible real-world value */
1452 (*dfree
) = (uint64_t)-1;
1453 (*dsize
) = (uint64_t)-1;
1455 /* As we have select not to use quotas, allways fail */
1458 #endif /* WITH_QUOTAS */
1460 #else /* HAVE_SYS_QUOTAS */
1461 /* wrapper to the new sys_quota interface
1462 this file should be removed later
1464 bool disk_quotas(const char *path
,uint64_t *bsize
,uint64_t *dfree
,uint64_t *dsize
)
1473 r
=sys_get_quota(path
, SMB_USER_QUOTA_TYPE
, id
, &D
);
1475 /* Use softlimit to determine disk space, except when it has been exceeded */
1478 if (errno
== EDQUOT
) {
1480 *dsize
=D
.curblocks
;
1483 goto try_group_quota
;
1487 /* Use softlimit to determine disk space, except when it has been exceeded */
1489 (D
.softlimit
&& D
.curblocks
>= D
.softlimit
) ||
1490 (D
.hardlimit
&& D
.curblocks
>= D
.hardlimit
) ||
1491 (D
.isoftlimit
&& D
.curinodes
>= D
.isoftlimit
) ||
1492 (D
.ihardlimit
&& D
.curinodes
>=D
.ihardlimit
)
1495 *dsize
= D
.curblocks
;
1496 } else if (D
.softlimit
==0 && D
.hardlimit
==0) {
1497 goto try_group_quota
;
1499 if (D
.softlimit
== 0)
1500 D
.softlimit
= D
.hardlimit
;
1501 *dfree
= D
.softlimit
- D
.curblocks
;
1502 *dsize
= D
.softlimit
;
1511 r
=sys_get_quota(path
, SMB_GROUP_QUOTA_TYPE
, id
, &D
);
1513 /* Use softlimit to determine disk space, except when it has been exceeded */
1516 if (errno
== EDQUOT
) {
1518 *dsize
=D
.curblocks
;
1525 /* Use softlimit to determine disk space, except when it has been exceeded */
1527 (D
.softlimit
&& D
.curblocks
>= D
.softlimit
) ||
1528 (D
.hardlimit
&& D
.curblocks
>= D
.hardlimit
) ||
1529 (D
.isoftlimit
&& D
.curinodes
>= D
.isoftlimit
) ||
1530 (D
.ihardlimit
&& D
.curinodes
>=D
.ihardlimit
)
1533 *dsize
= D
.curblocks
;
1534 } else if (D
.softlimit
==0 && D
.hardlimit
==0) {
1537 if (D
.softlimit
== 0)
1538 D
.softlimit
= D
.hardlimit
;
1539 *dfree
= D
.softlimit
- D
.curblocks
;
1540 *dsize
= D
.softlimit
;
1545 #endif /* HAVE_SYS_QUOTAS */