2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1992-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * This is one of the most system dependent parts of Samba, and its
25 * done a litle differently. Each system has its own way of doing
31 extern int DEBUGLEVEL
;
33 #if defined(VXFS_QUOTA)
36 * In addition to their native filesystems, some systems have Veritas VxFS.
37 * Declare here, define at end: reduces likely "include" interaction problems.
38 * David Lee <T.D.Lee@durham.ac.uk>
40 BOOL
disk_quotas_vxfs(const pstring name
, char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
);
42 #endif /* VXFS_QUOTA */
46 #include <sys/types.h>
47 #include <asm/types.h>
48 #include <sys/quota.h>
51 #include <linux/unistd.h>
53 _syscall4(int, quotactl
, int, cmd
, const char *, special
, int, id
, caddr_t
, addr
);
55 /****************************************************************************
56 try to get the disk space from disk quotas (LINUX version)
57 ****************************************************************************/
59 BOOL
disk_quotas(char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
72 /* find the block device file */
74 if ( sys_stat(path
, &S
) == -1 ) {
80 fp
= setmntent(MOUNTED
,"r");
83 while ((mnt
= getmntent(fp
))) {
84 if ( sys_stat(mnt
->mnt_dir
,&S
) == -1 )
86 if (S
.st_dev
== devno
) {
99 r
=quotactl(QCMD(Q_GETQUOTA
,USRQUOTA
), mnt
->mnt_fsname
, euser_id
, (caddr_t
)&D
);
102 /* Use softlimit to determine disk space, except when it has been exceeded */
109 *dsize
=D
.dqb_curblocks
;
114 /* Use softlimit to determine disk space, except when it has been exceeded */
116 (D
.dqb_bsoftlimit
&& D
.dqb_curblocks
>=D
.dqb_bsoftlimit
) ||
117 (D
.dqb_bhardlimit
&& D
.dqb_curblocks
>=D
.dqb_bhardlimit
) ||
118 (D
.dqb_isoftlimit
&& D
.dqb_curinodes
>=D
.dqb_isoftlimit
) ||
119 (D
.dqb_ihardlimit
&& D
.dqb_curinodes
>=D
.dqb_ihardlimit
)
123 *dsize
= D
.dqb_curblocks
;
125 else if (D
.dqb_bsoftlimit
==0 && D
.dqb_bhardlimit
==0)
130 if (D
.dqb_bsoftlimit
== 0)
131 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
132 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
133 *dsize
= D
.dqb_bsoftlimit
;
140 #include <sys/quota.h>
143 /****************************************************************************
144 try to get the disk space from disk quotas (CRAY VERSION)
145 ****************************************************************************/
147 BOOL
disk_quotas(char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
151 SMB_STRUCT_STAT sbuf
;
153 static SMB_DEV_T devno_cached
= 0 ;
155 struct q_request request
;
156 struct qf_header header
;
157 static int quota_default
= 0 ;
160 if ( sys_stat(path
,&sbuf
) == -1 )
163 devno
= sbuf
.st_dev
;
165 if ( devno
!= devno_cached
) {
167 devno_cached
= devno
;
169 if ((fd
= setmntent(KMTAB
)) == NULL
)
174 while ((mnt
= getmntent(fd
)) != NULL
) {
176 if ( sys_stat(mnt
->mnt_dir
,&sbuf
) == -1 )
179 if (sbuf
.st_dev
== devno
) {
188 pstrcpy(name
,mnt
->mnt_dir
) ;
195 request
.qf_magic
= QF_MAGIC
;
196 request
.qf_entry
.id
= geteuid() ;
198 if (quotactl(name
, Q_GETQUOTA
, &request
) == -1)
201 if ( ! request
.user
)
204 if ( request
.qf_entry
.user_q
.f_quota
== QFV_DEFAULT
) {
206 if ( ! quota_default
) {
208 if ( quotactl(name
, Q_GETHEADER
, &header
) == -1 )
211 quota_default
= header
.user_h
.def_fq
;
214 *dfree
= quota_default
;
216 }else if ( request
.qf_entry
.user_q
.f_quota
== QFV_PREVENT
) {
222 *dfree
= request
.qf_entry
.user_q
.f_quota
;
226 *dsize
= request
.qf_entry
.user_q
.f_use
;
228 if ( *dfree
< *dsize
)
233 *bsize
= 4096 ; /* Cray blocksize */
240 #elif defined(SUNOS5) || defined(SUNOS4)
243 #include <sys/param.h>
245 #include <sys/fs/ufs_quota.h>
246 #include <sys/mnttab.h>
247 #else /* defined(SUNOS4) */
248 #include <ufs/quota.h>
252 /****************************************************************************
253 try to get the disk space from disk quotas (SunOS & Solaris2 version)
254 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
255 ****************************************************************************/
257 BOOL
disk_quotas(char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
263 struct quotctl command
;
265 static struct mnttab mnt
;
272 SMB_STRUCT_STAT sbuf
;
274 static SMB_DEV_T devno_cached
= 0 ;
277 euser_id
= geteuid();
279 if ( sys_stat(path
,&sbuf
) == -1 )
282 devno
= sbuf
.st_dev
;
283 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%o\n", path
,devno
));
284 if ( devno
!= devno_cached
) {
285 devno_cached
= devno
;
287 if ((fd
= sys_fopen(MNTTAB
, "r")) == NULL
)
291 while (getmntent(fd
, &mnt
) == 0) {
292 if ( sys_stat(mnt
.mnt_mountp
,&sbuf
) == -1 )
294 DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n",
295 mnt
.mnt_mountp
,sbuf
.st_dev
));
296 if (sbuf
.st_dev
== devno
) {
302 pstrcpy(name
,mnt
.mnt_mountp
) ;
303 pstrcat(name
,"/quotas") ;
306 if ((fd
= setmntent(MOUNTED
, "r")) == NULL
)
310 while ((mnt
= getmntent(fd
)) != NULL
) {
311 if ( sys_stat(mnt
->mnt_dir
,&sbuf
) == -1 )
313 DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n",
314 mnt
->mnt_dir
,sbuf
.st_dev
));
315 if (sbuf
.st_dev
== devno
) {
321 pstrcpy(name
,mnt
->mnt_fsname
) ;
330 set_effective_uid(0);
333 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name
));
334 if((file
=sys_open(name
, O_RDONLY
,0))<0) {
338 command
.op
= Q_GETQUOTA
;
339 command
.uid
= euser_id
;
340 command
.addr
= (caddr_t
) &D
;
341 ret
= ioctl(file
, Q_QUOTACTL
, &command
);
344 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name
));
345 ret
= quotactl(Q_GETQUOTA
, name
, euser_id
, &D
);
351 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno
) ));
353 #if defined(SUNOS5) && defined(VXFS_QUOTA)
354 /* If normal quotactl() fails, try vxfs private calls */
355 set_effective_uid(euser_id
);
356 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt
.mnt_fstype
));
357 if ( 0 == strcmp ( mnt
.mnt_fstype
, "vxfs" )) {
358 ret
= disk_quotas_vxfs(name
, path
, bsize
, dfree
, dsize
);
366 /* If softlimit is zero, set it equal to hardlimit.
369 if (D
.dqb_bsoftlimit
==0)
370 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
372 /* Use softlimit to determine disk space. A user exceeding the quota is told
373 * that there's no space left. Writes might actually work for a bit if the
374 * hardlimit is set higher than softlimit. Effectively the disk becomes
375 * made of rubber latex and begins to expand to accommodate the user :-)
378 if (D
.dqb_bsoftlimit
==0)
381 *dsize
= D
.dqb_bsoftlimit
;
383 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
385 *dsize
= D
.dqb_curblocks
;
387 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
389 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
390 path
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
397 #include <ufs/quota.h>
399 /****************************************************************************
400 try to get the disk space from disk quotas - OSF1 version
401 ****************************************************************************/
403 BOOL
disk_quotas(char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
411 * This code presumes that OSF1 will only
412 * give out quota info when the real uid
413 * matches the effective uid. JRA.
415 euser_id
= geteuid();
417 if (set_re_uid() != 0) return False
;
419 r
= quotactl(path
,QCMD(Q_GETQUOTA
, USRQUOTA
),euser_id
,(char *) &D
);
430 if (save_errno
== EDQUOT
) // disk quota exceeded
433 *dsize
= D
.dqb_curblocks
;
440 /* If softlimit is zero, set it equal to hardlimit.
443 if (D
.dqb_bsoftlimit
==0)
444 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
446 /* Use softlimit to determine disk space, except when it has been exceeded */
448 if (D
.dqb_bsoftlimit
==0)
451 if ((D
.dqb_curblocks
>D
.dqb_bsoftlimit
)) {
453 *dsize
= D
.dqb_curblocks
;
455 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
456 *dsize
= D
.dqb_bsoftlimit
;
461 #elif defined (IRIX6)
462 /****************************************************************************
463 try to get the disk space from disk quotas (IRIX 6.2 version)
464 ****************************************************************************/
466 #include <sys/quota.h>
469 BOOL
disk_quotas(char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
474 struct fs_disk_quota F
;
481 /* find the block device file */
483 if ( sys_stat(path
, &S
) == -1 ) {
489 fp
= setmntent(MOUNTED
,"r");
492 while ((mnt
= getmntent(fp
))) {
493 if ( sys_stat(mnt
->mnt_dir
,&S
) == -1 )
495 if (S
.st_dev
== devno
) {
508 set_effective_uid(0);
510 /* Use softlimit to determine disk space, except when it has been exceeded */
514 if ( 0 == strcmp ( mnt
->mnt_type
, "efs" ))
516 r
=quotactl (Q_GETQUOTA
, mnt
->mnt_fsname
, euser_id
, (caddr_t
) &D
);
523 /* Use softlimit to determine disk space, except when it has been exceeded */
525 (D
.dqb_bsoftlimit
&& D
.dqb_curblocks
>=D
.dqb_bsoftlimit
) ||
526 (D
.dqb_bhardlimit
&& D
.dqb_curblocks
>=D
.dqb_bhardlimit
) ||
527 (D
.dqb_fsoftlimit
&& D
.dqb_curfiles
>=D
.dqb_fsoftlimit
) ||
528 (D
.dqb_fhardlimit
&& D
.dqb_curfiles
>=D
.dqb_fhardlimit
)
532 *dsize
= D
.dqb_curblocks
;
534 else if (D
.dqb_bsoftlimit
==0 && D
.dqb_bhardlimit
==0)
540 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
541 *dsize
= D
.dqb_bsoftlimit
;
545 else if ( 0 == strcmp ( mnt
->mnt_type
, "xfs" ))
547 r
=quotactl (Q_XGETQUOTA
, mnt
->mnt_fsname
, euser_id
, (caddr_t
) &F
);
554 /* Use softlimit to determine disk space, except when it has been exceeded */
556 (F
.d_blk_softlimit
&& F
.d_bcount
>=F
.d_blk_softlimit
) ||
557 (F
.d_blk_hardlimit
&& F
.d_bcount
>=F
.d_blk_hardlimit
) ||
558 (F
.d_ino_softlimit
&& F
.d_icount
>=F
.d_ino_softlimit
) ||
559 (F
.d_ino_hardlimit
&& F
.d_icount
>=F
.d_ino_hardlimit
)
565 else if (F
.d_blk_softlimit
==0 && F
.d_blk_hardlimit
==0)
571 *dfree
= (F
.d_blk_softlimit
- F
.d_bcount
);
572 *dsize
= F
.d_blk_softlimit
;
588 #if defined(__FreeBSD__) || defined(__OpenBSD__)
589 #include <ufs/ufs/quota.h>
590 #include <machine/param.h>
592 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
593 #include <jfs/quota.h>
594 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
595 #define dqb_curfiles dqb_curinodes
596 #define dqb_fhardlimit dqb_ihardlimit
597 #define dqb_fsoftlimit dqb_isoftlimit
598 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
599 #include <sys/quota.h>
603 /****************************************************************************
604 try to get the disk space from disk quotas - default version
605 ****************************************************************************/
607 BOOL
disk_quotas(char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
612 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
615 /* find the block device file */
616 if ((sys_stat(path
, &S
)<0) ||
617 (devnm(S_IFBLK
, S
.st_dev
, dev_disk
, 256, 0)<0)) return (False
);
620 euser_id
= geteuid();
623 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
625 if (set_re_uid() != 0) return False
;
627 r
=quotactl(Q_GETQUOTA
, dev_disk
, euser_id
, &D
);
631 #if defined(__FreeBSD__) || defined(__OpenBSD__)
633 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
637 set_effective_uid(0);
640 r
= quotactl(path
,QCMD(Q_GETQUOTA
,USRQUOTA
),euser_id
,(char *) &D
);
642 /* As FreeBSD has group quotas, if getting the user
643 quota fails, try getting the group instead. */
645 r
= quotactl(path
,QCMD(Q_GETQUOTA
,GRPQUOTA
),egrp_id
,(char *) &D
);
651 /* AIX has both USER and GROUP quotas:
652 Get the USER quota (ohnielse@fysik.dtu.dk) */
653 r
= quotactl(path
,QCMD(Q_GETQUOTA
,USRQUOTA
),euser_id
,(char *) &D
);
654 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
655 r
=quotactl(Q_GETQUOTA
, dev_disk
, euser_id
, &D
);
656 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
659 /* Use softlimit to determine disk space, except when it has been exceeded */
660 #if defined(__FreeBSD__) || defined(__OpenBSD__)
662 #else /* !__FreeBSD__ && !__OpenBSD__ */
664 #endif /*!__FreeBSD__ && !__OpenBSD__ */
671 *dsize
=D
.dqb_curblocks
;
677 /* If softlimit is zero, set it equal to hardlimit.
680 if (D
.dqb_bsoftlimit
==0)
681 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
683 if (D
.dqb_bsoftlimit
==0)
685 /* Use softlimit to determine disk space, except when it has been exceeded */
686 if ((D
.dqb_curblocks
>D
.dqb_bsoftlimit
)
687 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
688 ||((D
.dqb_curfiles
>D
.dqb_fsoftlimit
) && (D
.dqb_fsoftlimit
!= 0))
692 *dsize
= D
.dqb_curblocks
;
695 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
696 *dsize
= D
.dqb_bsoftlimit
;
703 #if defined(VXFS_QUOTA)
705 /****************************************************************************
706 Try to get the disk space from Veritas disk quotas.
707 David Lee <T.D.Lee@durham.ac.uk> August 1999.
709 Background assumptions:
710 Potentially under many Operating Systems. Initially Solaris 2.
712 My guess is that Veritas is largely, though not entirely,
713 independent of OS. So I have separated it out.
715 There may be some details. For example, OS-specific "include" files.
717 It is understood that HPUX 10 somehow gets Veritas quotas without
718 any special effort; if so, this routine need not be compiled in.
719 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
722 It is understood that Veritas do not publicly support this ioctl interface.
723 Rather their preference would be for the user (us) to call the native
724 OS and then for the OS itself to call through to the VxFS filesystem.
725 Presumably HPUX 10, see above, does this.
728 Add your OS to "IFLIST" below.
729 Get it to compile successfully:
730 Almost certainly "include"s require attention: see SUNOS5.
731 In the main code above, arrange for it to be called: see SUNOS5.
734 ****************************************************************************/
737 * This "if" is a list of ports:
738 * if defined(OS1) || defined(OS2) || ...
743 #include <sys/fs/vx_solaris.h>
745 #include <sys/fs/vx_machdep.h>
746 #include <sys/fs/vx_layout.h>
747 #include <sys/fs/vx_quota.h>
748 #include <sys/fs/vx_aioctl.h>
749 #include <sys/fs/vx_ioctl.h>
751 BOOL
disk_quotas_vxfs(const pstring name
, char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
753 uid_t user_id
, euser_id
;
756 struct vx_quotctl quotabuf
;
757 struct vx_genioctl genbuf
;
762 * "name" may or may not include a trailing "/quotas".
763 * Arranging consistency of calling here in "quotas.c" may not be easy and
764 * it might be easier to examine and adjust it here.
765 * Fortunately, VxFS seems not to mind at present.
767 pstrcpy(qfname
, name
) ;
768 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
770 euser_id
= geteuid();
771 set_effective_uid(0);
773 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname
));
774 if((file
=sys_open(qfname
, O_RDONLY
,0))<0) {
775 set_effective_uid(euser_id
);
778 genbuf
.ioc_cmd
= VX_QUOTACTL
;
779 genbuf
.ioc_up
= (void *) "abuf
;
781 quotabuf
.cmd
= VX_GETQUOTA
;
782 quotabuf
.uid
= euser_id
;
783 quotabuf
.addr
= (caddr_t
) &D
;
784 ret
= ioctl(file
, VX_ADMIN_IOCTL
, &genbuf
);
787 set_effective_uid(euser_id
);
790 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno
) ));
794 /* If softlimit is zero, set it equal to hardlimit.
797 if (D
.dqb_bsoftlimit
==0)
798 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
800 /* Use softlimit to determine disk space. A user exceeding the quota is told
801 * that there's no space left. Writes might actually work for a bit if the
802 * hardlimit is set higher than softlimit. Effectively the disk becomes
803 * made of rubber latex and begins to expand to accommodate the user :-)
805 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
806 path
, D
.dqb_curblocks
, D
.dqb_bsoftlimit
, D
.dqb_bhardlimit
,
807 D
.dqb_curfiles
, D
.dqb_fsoftlimit
, D
.dqb_fhardlimit
));
809 if (D
.dqb_bsoftlimit
==0)
812 *dsize
= D
.dqb_bsoftlimit
;
814 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
816 *dsize
= D
.dqb_curblocks
;
818 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
820 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
821 path
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
826 #endif /* SUNOS5 || ... */
828 #endif /* VXFS_QUOTA */