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
28 #include "smbd/smbd.h"
29 #include "system/filesys.h"
32 #define DBGC_CLASS DBGC_QUOTA
34 #ifndef HAVE_SYS_QUOTAS
36 /* just a quick hack because sysquotas.h is included before linux/quota.h */
37 #ifdef QUOTABLOCK_SIZE
38 #undef QUOTABLOCK_SIZE
43 #if defined(VXFS_QUOTA)
46 * In addition to their native filesystems, some systems have Veritas VxFS.
47 * Declare here, define at end: reduces likely "include" interaction problems.
48 * David Lee <T.D.Lee@durham.ac.uk>
50 bool disk_quotas_vxfs(const char *name
, char *path
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
);
52 #endif /* VXFS_QUOTA */
57 #include <sys/types.h>
61 * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
62 * So we include all the files has *should* be in the system into a large,
63 * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA.
66 #include "samba_linux_quota.h"
68 typedef struct _LINUX_SMB_DISK_QUOTA
{
70 uint64_t hardlimit
; /* In bsize units. */
71 uint64_t softlimit
; /* In bsize units. */
72 uint64_t curblocks
; /* In bsize units. */
73 uint64_t ihardlimit
; /* inode hard limit. */
74 uint64_t isoftlimit
; /* inode soft limit. */
75 uint64_t curinodes
; /* Current used inodes. */
76 } LINUX_SMB_DISK_QUOTA
;
81 * (essentially taken from FreeBSD / SUNOS5 section)
84 #include <rpc/types.h>
85 #include <rpcsvc/rquota.h>
86 #ifdef HAVE_RPC_NETTYPE_H
87 #include <rpc/nettype.h>
91 static int my_xdr_getquota_rslt(XDR
*xdrsp
, struct getquota_rslt
*gqr
)
95 if (!xdr_int(xdrsp
, "astat
)) {
96 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
99 gqr
->status
= quotastat
;
101 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsize
)) {
102 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
105 if (!xdr_bool(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_active
)) {
106 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
109 if (!xdr_int(xdrsp
, (int *)&gqr
->getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
)) {
110 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
113 if (!xdr_int(xdrsp
, (int *)&gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
)) {
114 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
117 if (!xdr_int(xdrsp
, (int *)&gqr
->getquota_rslt_u
.gqr_rquota
.rq_curblocks
)) {
118 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
124 static bool nfs_quotas(char *nfspath
, uid_t euser_id
, uint64_t *bsize
,
125 uint64_t *dfree
, uint64_t *dsize
)
127 uid_t uid
= euser_id
;
128 LINUX_SMB_DISK_QUOTA D
;
129 char *mnttype
= nfspath
;
131 struct getquota_rslt gqr
;
132 struct getquota_args args
;
133 char *cutstr
, *pathname
, *host
, *testpath
;
135 static struct timeval timeout
= {2,0};
136 enum clnt_stat clnt_stat
;
139 *bsize
= *dfree
= *dsize
= (uint64_t)0;
141 len
=strcspn(mnttype
, ":");
142 pathname
=strstr(mnttype
, ":");
143 cutstr
= (char *) SMB_MALLOC(len
+1);
147 memset(cutstr
, '\0', len
+1);
148 host
= strncat(cutstr
,mnttype
, sizeof(char) * len
);
149 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr
));
150 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype
));
151 testpath
=strchr_m(mnttype
, ':');
152 args
.gqa_pathp
= testpath
+1;
155 DEBUG(5, ("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers "
156 "\"%i\" network \"%s\"\n", host
, RQUOTAPROG
, RQUOTAVERS
,
159 if ((clnt
= clnt_create(host
, RQUOTAPROG
, RQUOTAVERS
, "udp")) == NULL
) {
164 clnt
->cl_auth
= authunix_create_default();
165 DEBUG(9,("nfs_quotas: auth_success\n"));
167 clnt_stat
=clnt_call(clnt
,
169 (const xdrproc_t
)my_xdr_getquota_args
,
171 (const xdrproc_t
)my_xdr_getquota_rslt
,
172 (caddr_t
)&gqr
, timeout
);
174 if (clnt_stat
!= RPC_SUCCESS
) {
175 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
181 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
182 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
183 * something sensible.
186 switch (gqr
.status
) {
188 DEBUG(9, ("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n",
194 DEBUG(9,("nfs_quotas: Good quota data\n"));
195 D
.softlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
;
196 D
.hardlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
;
197 D
.curblocks
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
;
204 DEBUG(9, ("nfs_quotas: Remote Quotas returned \"%i\" \n",
209 DEBUG(9, ("nfs_quotas: Remote Quotas Questionable! "
210 "Error \"%i\" \n", gqr
.status
));
214 DEBUG(10, ("nfs_quotas: Let`s look at D a bit closer... "
215 "status \"%i\" bsize \"%i\" active? \"%i\" bhard "
216 "\"%i\" bsoft \"%i\" curb \"%i\" \n",
218 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
,
219 gqr
.getquota_rslt_u
.gqr_rquota
.rq_active
,
220 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
,
221 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
,
222 gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
));
224 if (D
.softlimit
== 0)
225 D
.softlimit
= D
.hardlimit
;
226 if (D
.softlimit
== 0)
229 *bsize
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
;
230 *dsize
= D
.softlimit
;
232 if (D
.curblocks
== 1)
235 if (D
.curblocks
> D
.softlimit
) {
237 *dsize
= D
.curblocks
;
239 *dfree
= D
.softlimit
- D
.curblocks
;
245 auth_destroy(clnt
->cl_auth
);
249 DEBUG(5, ("nfs_quotas: For path \"%s\" returning "
250 "bsize %.0f, dfree %.0f, dsize %.0f\n",
251 args
.gqa_pathp
, (double)*bsize
, (double)*dfree
,
255 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
259 /* end of nfs quota section */
261 #ifdef HAVE_LINUX_DQBLK_XFS_H
262 #include <linux/dqblk_xfs.h>
264 /****************************************************************************
265 Abstract out the XFS Quota Manager quota get call.
266 ****************************************************************************/
268 static int get_smb_linux_xfs_quota(char *path
, uid_t euser_id
, gid_t egrp_id
, LINUX_SMB_DISK_QUOTA
*dp
)
270 struct fs_disk_quota D
;
275 ret
= quotactl(QCMD(Q_XGETQUOTA
,USRQUOTA
), path
, euser_id
, (caddr_t
)&D
);
278 ret
= quotactl(QCMD(Q_XGETQUOTA
,GRPQUOTA
), path
, egrp_id
, (caddr_t
)&D
);
283 dp
->bsize
= (uint64_t)512;
284 dp
->softlimit
= (uint64_t)D
.d_blk_softlimit
;
285 dp
->hardlimit
= (uint64_t)D
.d_blk_hardlimit
;
286 dp
->ihardlimit
= (uint64_t)D
.d_ino_hardlimit
;
287 dp
->isoftlimit
= (uint64_t)D
.d_ino_softlimit
;
288 dp
->curinodes
= (uint64_t)D
.d_icount
;
289 dp
->curblocks
= (uint64_t)D
.d_bcount
;
294 static int get_smb_linux_xfs_quota(char *path
, uid_t euser_id
, gid_t egrp_id
, LINUX_SMB_DISK_QUOTA
*dp
)
296 DEBUG(0,("XFS quota support not available\n"));
303 /****************************************************************************
304 Abstract out the old and new Linux quota get calls.
305 ****************************************************************************/
307 static int get_smb_linux_v1_quota(char *path
, uid_t euser_id
, gid_t egrp_id
, LINUX_SMB_DISK_QUOTA
*dp
)
309 struct v1_kern_dqblk D
;
314 ret
= quotactl(QCMD(Q_V1_GETQUOTA
,USRQUOTA
), path
, euser_id
, (caddr_t
)&D
);
316 if (ret
&& errno
!= EDQUOT
)
317 ret
= quotactl(QCMD(Q_V1_GETQUOTA
,GRPQUOTA
), path
, egrp_id
, (caddr_t
)&D
);
319 if (ret
&& errno
!= EDQUOT
)
322 dp
->bsize
= (uint64_t)QUOTABLOCK_SIZE
;
323 dp
->softlimit
= (uint64_t)D
.dqb_bsoftlimit
;
324 dp
->hardlimit
= (uint64_t)D
.dqb_bhardlimit
;
325 dp
->ihardlimit
= (uint64_t)D
.dqb_ihardlimit
;
326 dp
->isoftlimit
= (uint64_t)D
.dqb_isoftlimit
;
327 dp
->curinodes
= (uint64_t)D
.dqb_curinodes
;
328 dp
->curblocks
= (uint64_t)D
.dqb_curblocks
;
333 static int get_smb_linux_v2_quota(char *path
, uid_t euser_id
, gid_t egrp_id
, LINUX_SMB_DISK_QUOTA
*dp
)
335 struct v2_kern_dqblk D
;
340 ret
= quotactl(QCMD(Q_V2_GETQUOTA
,USRQUOTA
), path
, euser_id
, (caddr_t
)&D
);
342 if (ret
&& errno
!= EDQUOT
)
343 ret
= quotactl(QCMD(Q_V2_GETQUOTA
,GRPQUOTA
), path
, egrp_id
, (caddr_t
)&D
);
345 if (ret
&& errno
!= EDQUOT
)
348 dp
->bsize
= (uint64_t)QUOTABLOCK_SIZE
;
349 dp
->softlimit
= (uint64_t)D
.dqb_bsoftlimit
;
350 dp
->hardlimit
= (uint64_t)D
.dqb_bhardlimit
;
351 dp
->ihardlimit
= (uint64_t)D
.dqb_ihardlimit
;
352 dp
->isoftlimit
= (uint64_t)D
.dqb_isoftlimit
;
353 dp
->curinodes
= (uint64_t)D
.dqb_curinodes
;
354 dp
->curblocks
= ((uint64_t)D
.dqb_curspace
) / dp
->bsize
;
359 /****************************************************************************
360 Brand-new generic quota interface.
361 ****************************************************************************/
363 static int get_smb_linux_gen_quota(char *path
, uid_t euser_id
, gid_t egrp_id
, LINUX_SMB_DISK_QUOTA
*dp
)
370 ret
= quotactl(QCMD(Q_GETQUOTA
,USRQUOTA
), path
, euser_id
, (caddr_t
)&D
);
372 if (ret
&& errno
!= EDQUOT
)
373 ret
= quotactl(QCMD(Q_GETQUOTA
,GRPQUOTA
), path
, egrp_id
, (caddr_t
)&D
);
375 if (ret
&& errno
!= EDQUOT
)
378 dp
->bsize
= (uint64_t)QUOTABLOCK_SIZE
;
379 dp
->softlimit
= (uint64_t)D
.dqb_bsoftlimit
;
380 dp
->hardlimit
= (uint64_t)D
.dqb_bhardlimit
;
381 dp
->ihardlimit
= (uint64_t)D
.dqb_ihardlimit
;
382 dp
->isoftlimit
= (uint64_t)D
.dqb_isoftlimit
;
383 dp
->curinodes
= (uint64_t)D
.dqb_curinodes
;
384 dp
->curblocks
= ((uint64_t)D
.dqb_curspace
) / dp
->bsize
;
389 /****************************************************************************
390 Try to get the disk space from disk quotas (LINUX version).
391 ****************************************************************************/
393 bool disk_quotas(const char *path
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
398 LINUX_SMB_DISK_QUOTA D
;
407 euser_id
= geteuid();
410 /* find the block device file */
412 if (sys_stat(path
, &S
, false) == -1 )
415 devno
= S
.st_ex_dev
;
417 if ((fp
= setmntent(MOUNTED
,"r")) == NULL
)
422 while ((mnt
= getmntent(fp
))) {
423 if (sys_stat(mnt
->mnt_dir
, &S
, false) == -1)
426 if (S
.st_ex_dev
== devno
) {
439 if (strcmp(mnt
->mnt_type
, "nfs") == 0) {
441 retval
= nfs_quotas(mnt
->mnt_fsname
, euser_id
, bsize
, dfree
, dsize
);
446 if (strcmp(mnt
->mnt_type
, "xfs")==0) {
447 r
=get_smb_linux_xfs_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
449 r
=get_smb_linux_gen_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
450 if (r
== -1 && errno
!= EDQUOT
) {
451 r
=get_smb_linux_v2_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
452 if (r
== -1 && errno
!= EDQUOT
)
453 r
=get_smb_linux_v1_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
459 /* Use softlimit to determine disk space, except when it has been exceeded */
462 if (errno
== EDQUOT
) {
471 /* Use softlimit to determine disk space, except when it has been exceeded */
473 (D
.softlimit
&& D
.curblocks
>= D
.softlimit
) ||
474 (D
.hardlimit
&& D
.curblocks
>= D
.hardlimit
) ||
475 (D
.isoftlimit
&& D
.curinodes
>= D
.isoftlimit
) ||
476 (D
.ihardlimit
&& D
.curinodes
>=D
.ihardlimit
)
479 *dsize
= D
.curblocks
;
480 } else if (D
.softlimit
==0 && D
.hardlimit
==0) {
483 if (D
.softlimit
== 0)
484 D
.softlimit
= D
.hardlimit
;
485 *dfree
= D
.softlimit
- D
.curblocks
;
486 *dsize
= D
.softlimit
;
494 #include <sys/quota.h>
497 /****************************************************************************
498 try to get the disk space from disk quotas (CRAY VERSION)
499 ****************************************************************************/
501 bool disk_quotas(const char *path
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
505 SMB_STRUCT_STAT sbuf
;
507 struct q_request request
;
508 struct qf_header header
;
509 int quota_default
= 0 ;
512 if (sys_stat(path
, &sbuf
, false) == -1) {
516 devno
= sbuf
.st_ex_dev
;
518 if ((fd
= setmntent(KMTAB
)) == NULL
) {
522 while ((mnt
= getmntent(fd
)) != NULL
) {
523 if (sys_stat(mnt
->mnt_dir
, &sbuf
, false) == -1) {
526 if (sbuf
.st_ex_dev
== devno
) {
532 name
= talloc_strdup(talloc_tos(), mnt
->mnt_dir
);
542 request
.qf_magic
= QF_MAGIC
;
543 request
.qf_entry
.id
= geteuid() ;
545 if (quotactl(name
, Q_GETQUOTA
, &request
) == -1) {
553 if (request
.qf_entry
.user_q
.f_quota
== QFV_DEFAULT
) {
554 if (!quota_default
) {
555 if (quotactl(name
, Q_GETHEADER
, &header
) == -1) {
558 quota_default
= header
.user_h
.def_fq
;
561 *dfree
= quota_default
;
562 } else if (request
.qf_entry
.user_q
.f_quota
== QFV_PREVENT
) {
565 *dfree
= request
.qf_entry
.user_q
.f_quota
;
568 *dsize
= request
.qf_entry
.user_q
.f_use
;
570 if (*dfree
< *dsize
) {
576 *bsize
= 4096 ; /* Cray blocksize */
581 #elif defined(SUNOS5) || defined(SUNOS4)
584 #include <sys/param.h>
586 #include <sys/fs/ufs_quota.h>
587 #include <sys/mnttab.h>
588 #include <sys/mntent.h>
589 #else /* defined(SUNOS4) */
590 #include <ufs/quota.h>
596 /****************************************************************************
597 Allows querying of remote hosts for quotas on NFS mounted shares.
598 Supports normal NFS and AMD mounts.
599 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
600 ****************************************************************************/
603 #include <rpc/types.h>
604 #include <rpcsvc/rquota.h>
605 #include <rpc/nettype.h>
608 static int my_xdr_getquota_rslt(XDR
*xdrsp
, struct getquota_rslt
*gqr
)
612 if (!xdr_int(xdrsp
, "astat
)) {
613 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
616 gqr
->status
= quotastat
;
618 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsize
)) {
619 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
622 if (!xdr_bool(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_active
)) {
623 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
626 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
)) {
627 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
630 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
)) {
631 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
634 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_curblocks
)) {
635 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
641 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
642 static bool nfs_quotas(char *nfspath
, uid_t euser_id
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
644 uid_t uid
= euser_id
;
646 char *mnttype
= nfspath
;
648 struct getquota_rslt gqr
;
649 struct getquota_args args
;
650 char *cutstr
, *pathname
, *host
, *testpath
;
652 static struct timeval timeout
= {2,0};
653 enum clnt_stat clnt_stat
;
656 *bsize
= *dfree
= *dsize
= (uint64_t)0;
658 len
=strcspn(mnttype
, ":");
659 pathname
=strstr(mnttype
, ":");
660 cutstr
= (char *) SMB_MALLOC(len
+1);
664 memset(cutstr
, '\0', len
+1);
665 host
= strncat(cutstr
,mnttype
, sizeof(char) * len
);
666 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr
));
667 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype
));
668 testpath
=strchr_m(mnttype
, ':');
669 args
.gqa_pathp
= testpath
+1;
672 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host
, RQUOTAPROG
, RQUOTAVERS
, "udp"));
674 if ((clnt
= clnt_create(host
, RQUOTAPROG
, RQUOTAVERS
, "udp")) == NULL
) {
679 clnt
->cl_auth
= authunix_create_default();
680 DEBUG(9,("nfs_quotas: auth_success\n"));
682 clnt_stat
=clnt_call(clnt
, RQUOTAPROC_GETQUOTA
, my_xdr_getquota_args
, (caddr_t
)&args
, my_xdr_getquota_rslt
, (caddr_t
)&gqr
, timeout
);
684 if (clnt_stat
!= RPC_SUCCESS
) {
685 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
691 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
692 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
693 * something sensible.
696 switch (gqr
.status
) {
698 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr
.status
));
703 DEBUG(9,("nfs_quotas: Good quota data\n"));
704 D
.dqb_bsoftlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
;
705 D
.dqb_bhardlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
;
706 D
.dqb_curblocks
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
;
711 D
.dqb_bsoftlimit
= 1;
713 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr
.status
));
717 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr
.status
));
721 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",
723 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
,
724 gqr
.getquota_rslt_u
.gqr_rquota
.rq_active
,
725 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
,
726 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
,
727 gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
));
729 *bsize
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
;
730 *dsize
= D
.dqb_bsoftlimit
;
732 if (D
.dqb_curblocks
== 1)
735 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
737 *dsize
= D
.dqb_curblocks
;
739 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
745 auth_destroy(clnt
->cl_auth
);
749 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args
.gqa_pathp
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
752 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
757 /****************************************************************************
758 try to get the disk space from disk quotas (SunOS & Solaris2 version)
759 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
760 ****************************************************************************/
762 bool disk_quotas(const char *path
,
771 struct quotctl command
;
779 SMB_STRUCT_STAT sbuf
;
783 euser_id
= geteuid();
785 if (sys_stat(path
, &sbuf
, false) == -1) {
789 devno
= sbuf
.st_ex_dev
;
790 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
791 path
, (unsigned int)devno
));
793 if ((fd
= fopen(MNTTAB
, "r")) == NULL
) {
797 while (getmntent(fd
, &mnt
) == 0) {
798 if (sys_stat(mnt
.mnt_mountp
, &sbuf
, false) == -1) {
802 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
803 mnt
.mnt_mountp
, (unsigned int)devno
));
805 /* quotas are only on vxfs, UFS or NFS */
806 if ((sbuf
.st_ex_dev
== devno
) && (
807 strcmp( mnt
.mnt_fstype
, MNTTYPE_UFS
) == 0 ||
808 strcmp( mnt
.mnt_fstype
, "nfs" ) == 0 ||
809 strcmp( mnt
.mnt_fstype
, "vxfs" ) == 0 )) {
811 name
= talloc_asprintf(talloc_tos(),
820 if ((fd
= setmntent(MOUNTED
, "r")) == NULL
) {
824 while ((mnt
= getmntent(fd
)) != NULL
) {
825 if (sys_stat(mnt
->mnt_dir
, &sbuf
, false) == -1) {
828 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
830 (unsigned int)sbuf
.st_ex_dev
));
831 if (sbuf
.st_ex_dev
== devno
) {
833 name
= talloc_strdup(talloc_tos(),
851 if (strcmp(mnt
.mnt_fstype
, "nfs") == 0) {
853 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n",
855 retval
= nfs_quotas(mnt
.mnt_special
,
856 euser_id
, bsize
, dfree
, dsize
);
861 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name
));
862 if((file
=open(name
, O_RDONLY
,0))<0) {
866 command
.op
= Q_GETQUOTA
;
867 command
.uid
= euser_id
;
868 command
.addr
= (caddr_t
) &D
;
869 ret
= ioctl(file
, Q_QUOTACTL
, &command
);
872 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name
));
873 ret
= quotactl(Q_GETQUOTA
, name
, euser_id
, &D
);
879 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n",
882 #if defined(SUNOS5) && defined(VXFS_QUOTA)
883 /* If normal quotactl() fails, try vxfs private calls */
884 set_effective_uid(euser_id
);
885 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt
.mnt_fstype
));
886 if ( 0 == strcmp ( mnt
.mnt_fstype
, "vxfs" )) {
888 retval
= disk_quotas_vxfs(name
, path
,
889 bsize
, dfree
, dsize
);
897 /* If softlimit is zero, set it equal to hardlimit.
900 if (D
.dqb_bsoftlimit
==0) {
901 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
904 /* Use softlimit to determine disk space. A user exceeding the quota
905 * is told that there's no space left. Writes might actually work for
906 * a bit if the hardlimit is set higher than softlimit. Effectively
907 * the disk becomes made of rubber latex and begins to expand to
908 * accommodate the user :-)
911 if (D
.dqb_bsoftlimit
==0)
914 *dsize
= D
.dqb_bsoftlimit
;
916 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
918 *dsize
= D
.dqb_curblocks
;
920 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
923 DEBUG(5,("disk_quotas for path \"%s\" returning "
924 "bsize %.0f, dfree %.0f, dsize %.0f\n",
925 path
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
932 #include <ufs/quota.h>
934 /****************************************************************************
935 try to get the disk space from disk quotas - OSF1 version
936 ****************************************************************************/
938 bool disk_quotas(const char *path
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
946 * This code presumes that OSF1 will only
947 * give out quota info when the real uid
948 * matches the effective uid. JRA.
950 euser_id
= geteuid();
952 if (set_re_uid() != 0) return False
;
954 r
= quotactl(path
,QCMD(Q_GETQUOTA
, USRQUOTA
),euser_id
,(char *) &D
);
965 if (save_errno
== EDQUOT
) /* disk quota exceeded */
968 *dsize
= D
.dqb_curblocks
;
975 /* If softlimit is zero, set it equal to hardlimit.
978 if (D
.dqb_bsoftlimit
==0)
979 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
981 /* Use softlimit to determine disk space, except when it has been exceeded */
983 if (D
.dqb_bsoftlimit
==0)
986 if ((D
.dqb_curblocks
>D
.dqb_bsoftlimit
)) {
988 *dsize
= D
.dqb_curblocks
;
990 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
991 *dsize
= D
.dqb_bsoftlimit
;
996 #elif defined (IRIX6)
997 /****************************************************************************
998 try to get the disk space from disk quotas (IRIX 6.2 version)
999 ****************************************************************************/
1001 #include <sys/quota.h>
1004 bool disk_quotas(const char *path
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
1009 struct fs_disk_quota F
;
1016 /* find the block device file */
1018 if ( sys_stat(path
, &S
, false) == -1 ) {
1022 devno
= S
.st_ex_dev
;
1024 fp
= setmntent(MOUNTED
,"r");
1027 while ((mnt
= getmntent(fp
))) {
1028 if ( sys_stat(mnt
->mnt_dir
, &S
, false) == -1 )
1030 if (S
.st_ex_dev
== devno
) {
1044 /* Use softlimit to determine disk space, except when it has been exceeded */
1048 if ( 0 == strcmp ( mnt
->mnt_type
, "efs" ))
1050 r
=quotactl (Q_GETQUOTA
, mnt
->mnt_fsname
, euser_id
, (caddr_t
) &D
);
1057 /* Use softlimit to determine disk space, except when it has been exceeded */
1059 (D
.dqb_bsoftlimit
&& D
.dqb_curblocks
>=D
.dqb_bsoftlimit
) ||
1060 (D
.dqb_bhardlimit
&& D
.dqb_curblocks
>=D
.dqb_bhardlimit
) ||
1061 (D
.dqb_fsoftlimit
&& D
.dqb_curfiles
>=D
.dqb_fsoftlimit
) ||
1062 (D
.dqb_fhardlimit
&& D
.dqb_curfiles
>=D
.dqb_fhardlimit
)
1066 *dsize
= D
.dqb_curblocks
;
1068 else if (D
.dqb_bsoftlimit
==0 && D
.dqb_bhardlimit
==0)
1074 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1075 *dsize
= D
.dqb_bsoftlimit
;
1079 else if ( 0 == strcmp ( mnt
->mnt_type
, "xfs" ))
1081 r
=quotactl (Q_XGETQUOTA
, mnt
->mnt_fsname
, euser_id
, (caddr_t
) &F
);
1087 DEBUG(5, ("quotactl for uid=%u: %s", euser_id
, strerror(errno
)));
1091 /* No quota for this user. */
1092 if (F
.d_blk_softlimit
==0 && F
.d_blk_hardlimit
==0)
1097 /* Use softlimit to determine disk space, except when it has been exceeded */
1099 (F
.d_blk_softlimit
&& F
.d_bcount
>=F
.d_blk_softlimit
) ||
1100 (F
.d_blk_hardlimit
&& F
.d_bcount
>=F
.d_blk_hardlimit
) ||
1101 (F
.d_ino_softlimit
&& F
.d_icount
>=F
.d_ino_softlimit
) ||
1102 (F
.d_ino_hardlimit
&& F
.d_icount
>=F
.d_ino_hardlimit
)
1106 *dsize
= F
.d_bcount
;
1110 *dfree
= (F
.d_blk_softlimit
- F
.d_bcount
);
1111 *dsize
= F
.d_blk_softlimit
? F
.d_blk_softlimit
: F
.d_blk_hardlimit
;
1127 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1128 #include <ufs/ufs/quota.h>
1129 #include <machine/param.h>
1131 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
1132 #include <jfs/quota.h>
1133 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
1134 #define dqb_curfiles dqb_curinodes
1135 #define dqb_fhardlimit dqb_ihardlimit
1136 #define dqb_fsoftlimit dqb_isoftlimit
1137 #ifdef _AIXVERSION_530
1138 #include <sys/statfs.h>
1139 #include <sys/vmount.h>
1140 #endif /* AIX 5.3 */
1141 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1142 #include <sys/quota.h>
1146 #if defined(__FreeBSD__) || defined(__DragonFly__)
1148 #include <rpc/rpc.h>
1149 #include <rpc/types.h>
1150 #include <rpcsvc/rquota.h>
1151 #ifdef HAVE_RPC_NETTYPE_H
1152 #include <rpc/nettype.h>
1154 #include <rpc/xdr.h>
1156 static int my_xdr_getquota_rslt(XDR
*xdrsp
, struct getquota_rslt
*gqr
)
1160 if (!xdr_int(xdrsp
, "astat
)) {
1161 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
1164 gqr
->status
= quotastat
;
1166 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsize
)) {
1167 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
1170 if (!xdr_bool(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_active
)) {
1171 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
1174 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
)) {
1175 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
1178 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
)) {
1179 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
1182 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_curblocks
)) {
1183 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
1189 /* Works on FreeBSD, too. :-) */
1190 static bool nfs_quotas(char *nfspath
, uid_t euser_id
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
1192 uid_t uid
= euser_id
;
1194 char *mnttype
= nfspath
;
1196 struct getquota_rslt gqr
;
1197 struct getquota_args args
;
1198 char *cutstr
, *pathname
, *host
, *testpath
;
1200 static struct timeval timeout
= {2,0};
1201 enum clnt_stat clnt_stat
;
1204 *bsize
= *dfree
= *dsize
= (uint64_t)0;
1206 len
=strcspn(mnttype
, ":");
1207 pathname
=strstr(mnttype
, ":");
1208 cutstr
= (char *) SMB_MALLOC(len
+1);
1212 memset(cutstr
, '\0', len
+1);
1213 host
= strncat(cutstr
,mnttype
, sizeof(char) * len
);
1214 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr
));
1215 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype
));
1216 testpath
=strchr_m(mnttype
, ':');
1217 args
.gqa_pathp
= testpath
+1;
1220 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host
, RQUOTAPROG
, RQUOTAVERS
, "udp"));
1222 if ((clnt
= clnt_create(host
, RQUOTAPROG
, RQUOTAVERS
, "udp")) == NULL
) {
1227 clnt
->cl_auth
= authunix_create_default();
1228 DEBUG(9,("nfs_quotas: auth_success\n"));
1230 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
);
1232 if (clnt_stat
!= RPC_SUCCESS
) {
1233 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1239 * gqr->status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1240 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1241 * something sensible.
1244 switch (gqr
.status
) {
1246 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr
.status
));
1251 DEBUG(9,("nfs_quotas: Good quota data\n"));
1252 D
.dqb_bsoftlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
;
1253 D
.dqb_bhardlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
;
1254 D
.dqb_curblocks
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
;
1259 D
.dqb_bsoftlimit
= 1;
1260 D
.dqb_curblocks
= 1;
1261 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr
.status
));
1265 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr
.status
));
1269 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",
1271 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
,
1272 gqr
.getquota_rslt_u
.gqr_rquota
.rq_active
,
1273 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
,
1274 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
,
1275 gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
));
1277 if (D
.dqb_bsoftlimit
== 0)
1278 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
1279 if (D
.dqb_bsoftlimit
== 0)
1282 *bsize
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
;
1283 *dsize
= D
.dqb_bsoftlimit
;
1285 if (D
.dqb_curblocks
== 1)
1288 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
1290 *dsize
= D
.dqb_curblocks
;
1292 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1298 auth_destroy(clnt
->cl_auth
);
1302 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args
.gqa_pathp
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
1305 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1311 /****************************************************************************
1312 try to get the disk space from disk quotas - default version
1313 ****************************************************************************/
1315 bool disk_quotas(const char *path
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
1320 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1324 /* find the block device file */
1327 /* Need to set the cache flag to 1 for HPUX. Seems
1328 * to have a significant performance boost when
1329 * lstat calls on /dev access this function.
1331 if ((sys_stat(path
, &S
, false)<0)
1332 || (devnm(S_IFBLK
, S
.st_ex_dev
, dev_disk
, 256, 1)<0))
1334 if ((sys_stat(path
, &S
, false)<0)
1335 || (devnm(S_IFBLK
, S
.st_ex_dev
, dev_disk
, 256, 0)<0))
1337 #endif /* ifdef HPUX */
1339 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1341 euser_id
= geteuid();
1344 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1346 if (set_re_uid() != 0) return False
;
1348 r
=quotactl(Q_GETQUOTA
, dev_disk
, euser_id
, &D
);
1352 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1354 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1356 #if defined(__FreeBSD__) || defined(__DragonFly__)
1358 struct statfs
*mnts
;
1362 if (sys_stat(path
, &st
, false) < 0)
1364 devno
= st
.st_ex_dev
;
1366 mntsize
= getmntinfo(&mnts
,MNT_NOWAIT
);
1370 for (i
= 0; i
< mntsize
; i
++) {
1371 if (sys_stat(mnts
[i
].f_mntonname
, &st
, false) < 0)
1373 if (st
.st_ex_dev
== devno
)
1382 #if defined(__FreeBSD__) || defined(__DragonFly__)
1383 if (strcmp(mnts
[i
].f_fstypename
,"nfs") == 0) {
1385 retval
= nfs_quotas(mnts
[i
].f_mntfromname
,euser_id
,bsize
,dfree
,dsize
);
1391 egrp_id
= getegid();
1392 r
= quotactl(path
,QCMD(Q_GETQUOTA
,USRQUOTA
),euser_id
,(char *) &D
);
1394 /* As FreeBSD has group quotas, if getting the user
1395 quota fails, try getting the group instead. */
1397 r
= quotactl(path
,QCMD(Q_GETQUOTA
,GRPQUOTA
),egrp_id
,(char *) &D
);
1403 /* AIX has both USER and GROUP quotas:
1404 Get the USER quota (ohnielse@fysik.dtu.dk) */
1405 #ifdef _AIXVERSION_530
1407 struct statfs statbuf
;
1408 quota64_t user_quota
;
1409 if (statfs(path
,&statbuf
) != 0)
1411 if(statbuf
.f_vfstype
== MNT_J2
)
1413 /* For some reason we need to be root for jfs2 */
1415 r
= quotactl(path
,QCMD(Q_J2GETQUOTA
,USRQUOTA
),euser_id
,(char *) &user_quota
);
1417 /* Copy results to old struct to let the following code work as before */
1418 D
.dqb_curblocks
= user_quota
.bused
;
1419 D
.dqb_bsoftlimit
= user_quota
.bsoft
;
1420 D
.dqb_bhardlimit
= user_quota
.bhard
;
1421 D
.dqb_curfiles
= user_quota
.iused
;
1422 D
.dqb_fsoftlimit
= user_quota
.isoft
;
1423 D
.dqb_fhardlimit
= user_quota
.ihard
;
1425 else if(statbuf
.f_vfstype
== MNT_JFS
)
1427 #endif /* AIX 5.3 */
1429 if (set_re_uid() != 0)
1431 r
= quotactl(path
,QCMD(Q_GETQUOTA
,USRQUOTA
),euser_id
,(char *) &D
);
1433 #ifdef _AIXVERSION_530
1436 r
= 1; /* Fail for other FS-types */
1438 #endif /* AIX 5.3 */
1439 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1440 r
=quotactl(Q_GETQUOTA
, dev_disk
, euser_id
, &D
);
1441 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1444 /* Use softlimit to determine disk space, except when it has been exceeded */
1445 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1447 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1449 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1453 if (errno
== EDQUOT
)
1456 *dsize
=D
.dqb_curblocks
;
1462 /* If softlimit is zero, set it equal to hardlimit.
1465 if (D
.dqb_bsoftlimit
==0)
1466 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
1468 if (D
.dqb_bsoftlimit
==0)
1470 /* Use softlimit to determine disk space, except when it has been exceeded */
1471 if ((D
.dqb_curblocks
>D
.dqb_bsoftlimit
)
1472 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1473 ||((D
.dqb_curfiles
>D
.dqb_fsoftlimit
) && (D
.dqb_fsoftlimit
!= 0))
1477 *dsize
= D
.dqb_curblocks
;
1480 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1481 *dsize
= D
.dqb_bsoftlimit
;
1488 #if definedr(LINUX) || defined(SUNOS) || defined (__FreeBSD__) || defined(__DragonFly__)
1489 static int my_xdr_getquota_args(XDR
*xdrsp
, struct getquota_args
*args
)
1491 if (!xdr_string(xdrsp
, &args
->gqa_pathp
, RQ_PATHLEN
))
1493 if (!xdr_int(xdrsp
, &args
->gqa_uid
))
1499 #if defined(VXFS_QUOTA)
1501 /****************************************************************************
1502 Try to get the disk space from Veritas disk quotas.
1503 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1505 Background assumptions:
1506 Potentially under many Operating Systems. Initially Solaris 2.
1508 My guess is that Veritas is largely, though not entirely,
1509 independent of OS. So I have separated it out.
1511 There may be some details. For example, OS-specific "include" files.
1513 It is understood that HPUX 10 somehow gets Veritas quotas without
1514 any special effort; if so, this routine need not be compiled in.
1515 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1518 It is understood that Veritas do not publicly support this ioctl interface.
1519 Rather their preference would be for the user (us) to call the native
1520 OS and then for the OS itself to call through to the VxFS filesystem.
1521 Presumably HPUX 10, see above, does this.
1524 Add your OS to "IFLIST" below.
1525 Get it to compile successfully:
1526 Almost certainly "include"s require attention: see SUNOS5.
1527 In the main code above, arrange for it to be called: see SUNOS5.
1530 ****************************************************************************/
1533 * This "if" is a list of ports:
1534 * if defined(OS1) || defined(OS2) || ...
1539 #include <sys/fs/vx_solaris.h>
1541 #include <sys/fs/vx_machdep.h>
1542 #include <sys/fs/vx_layout.h>
1543 #include <sys/fs/vx_quota.h>
1544 #include <sys/fs/vx_aioctl.h>
1545 #include <sys/fs/vx_ioctl.h>
1547 bool disk_quotas_vxfs(const char *name
, char *path
, uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
1549 uid_t user_id
, euser_id
;
1552 struct vx_quotctl quotabuf
;
1553 struct vx_genioctl genbuf
;
1558 * "name" may or may not include a trailing "/quotas".
1559 * Arranging consistency of calling here in "quotas.c" may not be easy and
1560 * it might be easier to examine and adjust it here.
1561 * Fortunately, VxFS seems not to mind at present.
1563 qfname
= talloc_strdup(talloc_tos(), name
);
1567 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1569 euser_id
= geteuid();
1570 set_effective_uid(0);
1572 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname
));
1573 if((file
=open(qfname
, O_RDONLY
,0))<0) {
1574 set_effective_uid(euser_id
);
1577 genbuf
.ioc_cmd
= VX_QUOTACTL
;
1578 genbuf
.ioc_up
= (void *) "abuf
;
1580 quotabuf
.cmd
= VX_GETQUOTA
;
1581 quotabuf
.uid
= euser_id
;
1582 quotabuf
.addr
= (caddr_t
) &D
;
1583 ret
= ioctl(file
, VX_ADMIN_IOCTL
, &genbuf
);
1586 set_effective_uid(euser_id
);
1589 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno
) ));
1593 /* If softlimit is zero, set it equal to hardlimit.
1596 if (D
.dqb_bsoftlimit
==0)
1597 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
1599 /* Use softlimit to determine disk space. A user exceeding the quota is told
1600 * that there's no space left. Writes might actually work for a bit if the
1601 * hardlimit is set higher than softlimit. Effectively the disk becomes
1602 * made of rubber latex and begins to expand to accommodate the user :-)
1604 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1605 path
, D
.dqb_curblocks
, D
.dqb_bsoftlimit
, D
.dqb_bhardlimit
,
1606 D
.dqb_curfiles
, D
.dqb_fsoftlimit
, D
.dqb_fhardlimit
));
1608 if (D
.dqb_bsoftlimit
==0)
1611 *dsize
= D
.dqb_bsoftlimit
;
1613 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
1615 *dsize
= D
.dqb_curblocks
;
1617 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1619 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1620 path
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
1625 #endif /* SUNOS5 || ... */
1627 #endif /* VXFS_QUOTA */
1629 #else /* WITH_QUOTAS */
1631 bool disk_quotas(const char *path
,uint64_t *bsize
,uint64_t *dfree
,uint64_t *dsize
)
1633 (*bsize
) = 512; /* This value should be ignored */
1635 /* And just to be sure we set some values that hopefully */
1636 /* will be larger that any possible real-world value */
1637 (*dfree
) = (uint64_t)-1;
1638 (*dsize
) = (uint64_t)-1;
1640 /* As we have select not to use quotas, allways fail */
1643 #endif /* WITH_QUOTAS */
1645 #else /* HAVE_SYS_QUOTAS */
1646 /* wrapper to the new sys_quota interface
1647 this file should be removed later
1649 bool disk_quotas(const char *path
,uint64_t *bsize
,uint64_t *dfree
,uint64_t *dsize
)
1658 r
=sys_get_quota(path
, SMB_USER_QUOTA_TYPE
, id
, &D
);
1660 /* Use softlimit to determine disk space, except when it has been exceeded */
1663 if (errno
== EDQUOT
) {
1665 *dsize
=D
.curblocks
;
1668 goto try_group_quota
;
1672 /* Use softlimit to determine disk space, except when it has been exceeded */
1674 (D
.softlimit
&& D
.curblocks
>= D
.softlimit
) ||
1675 (D
.hardlimit
&& D
.curblocks
>= D
.hardlimit
) ||
1676 (D
.isoftlimit
&& D
.curinodes
>= D
.isoftlimit
) ||
1677 (D
.ihardlimit
&& D
.curinodes
>=D
.ihardlimit
)
1680 *dsize
= D
.curblocks
;
1681 } else if (D
.softlimit
==0 && D
.hardlimit
==0) {
1682 goto try_group_quota
;
1684 if (D
.softlimit
== 0)
1685 D
.softlimit
= D
.hardlimit
;
1686 *dfree
= D
.softlimit
- D
.curblocks
;
1687 *dsize
= D
.softlimit
;
1696 r
=sys_get_quota(path
, SMB_GROUP_QUOTA_TYPE
, id
, &D
);
1698 /* Use softlimit to determine disk space, except when it has been exceeded */
1701 if (errno
== EDQUOT
) {
1703 *dsize
=D
.curblocks
;
1710 /* Use softlimit to determine disk space, except when it has been exceeded */
1712 (D
.softlimit
&& D
.curblocks
>= D
.softlimit
) ||
1713 (D
.hardlimit
&& D
.curblocks
>= D
.hardlimit
) ||
1714 (D
.isoftlimit
&& D
.curinodes
>= D
.isoftlimit
) ||
1715 (D
.ihardlimit
&& D
.curinodes
>=D
.ihardlimit
)
1718 *dsize
= D
.curblocks
;
1719 } else if (D
.softlimit
==0 && D
.hardlimit
==0) {
1722 if (D
.softlimit
== 0)
1723 D
.softlimit
= D
.hardlimit
;
1724 *dfree
= D
.softlimit
- D
.curblocks
;
1725 *dsize
= D
.softlimit
;
1730 #endif /* HAVE_SYS_QUOTAS */