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 #include <sys/mntent.h>
248 #else /* defined(SUNOS4) */
249 #include <ufs/quota.h>
253 /****************************************************************************
254 try to get the disk space from disk quotas (SunOS & Solaris2 version)
255 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
256 ****************************************************************************/
258 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
264 struct quotctl command;
266 static struct mnttab mnt;
274 SMB_STRUCT_STAT sbuf;
276 static SMB_DEV_T devno_cached = 0 ;
279 euser_id = geteuid();
281 if ( sys_stat(path,&sbuf) == -1 )
284 devno = sbuf.st_dev ;
285 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,devno));
286 if ( devno != devno_cached ) {
287 devno_cached = devno ;
289 if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
293 slprintf(devopt, sizeof(devopt) - 1, "dev=%x", devno);
294 while (getmntent(fd, &mnt) == 0) {
295 if( !hasmntopt(&mnt, devopt) )
298 DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt));
300 /* quotas are only on vxfs, UFS or NFS, but nfs is not supported here */
301 if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
302 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )
309 pstrcpy(name,mnt.mnt_mountp) ;
310 pstrcat(name,"/quotas") ;
313 if ((fd = setmntent(MOUNTED, "r")) == NULL)
317 while ((mnt = getmntent(fd)) != NULL) {
318 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
320 DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n",
321 mnt->mnt_dir,sbuf.st_dev));
322 if (sbuf.st_dev == devno) {
328 pstrcpy(name,mnt->mnt_fsname) ;
338 set_effective_uid(0);
341 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
342 if((file=sys_open(name, O_RDONLY,0))<0) {
346 command.op = Q_GETQUOTA;
347 command.uid = euser_id;
348 command.addr = (caddr_t) &D;
349 ret = ioctl(file, Q_QUOTACTL, &command);
352 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
353 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
359 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
361 #if defined(SUNOS5) && defined(VXFS_QUOTA)
362 /* If normal quotactl() fails, try vxfs private calls */
363 set_effective_uid(euser_id);
364 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
365 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
366 ret = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
374 /* If softlimit is zero, set it equal to hardlimit.
377 if (D.dqb_bsoftlimit==0)
378 D.dqb_bsoftlimit = D.dqb_bhardlimit;
380 /* Use softlimit to determine disk space. A user exceeding the quota is told
381 * that there's no space left. Writes might actually work for a bit if the
382 * hardlimit is set higher than softlimit. Effectively the disk becomes
383 * made of rubber latex and begins to expand to accommodate the user :-)
386 if (D.dqb_bsoftlimit==0)
389 *dsize = D.dqb_bsoftlimit;
391 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
393 *dsize = D.dqb_curblocks;
395 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
397 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
398 path,(double)*bsize,(double)*dfree,(double)*dsize));
405 #include <ufs/quota.h>
407 /****************************************************************************
408 try to get the disk space from disk quotas - OSF1 version
409 ****************************************************************************/
411 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
419 * This code presumes that OSF1 will only
420 * give out quota info when the real uid
421 * matches the effective uid. JRA.
423 euser_id = geteuid();
425 if (set_re_uid() != 0) return False;
427 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
438 if (save_errno == EDQUOT) /* disk quota exceeded */
441 *dsize = D.dqb_curblocks;
448 /* If softlimit is zero, set it equal to hardlimit.
451 if (D.dqb_bsoftlimit==0)
452 D.dqb_bsoftlimit = D.dqb_bhardlimit;
454 /* Use softlimit to determine disk space, except when it has been exceeded */
456 if (D.dqb_bsoftlimit==0)
459 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
461 *dsize = D.dqb_curblocks;
463 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
464 *dsize = D.dqb_bsoftlimit;
469 #elif defined (IRIX6)
470 /****************************************************************************
471 try to get the disk space from disk quotas (IRIX 6.2 version)
472 ****************************************************************************/
474 #include <sys/quota.h>
477 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
482 struct fs_disk_quota F;
489 /* find the block device file */
491 if ( sys_stat(path, &S) == -1 ) {
497 fp = setmntent(MOUNTED,"r");
500 while ((mnt = getmntent(fp))) {
501 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
503 if (S.st_dev == devno) {
516 set_effective_uid(0);
518 /* Use softlimit to determine disk space, except when it has been exceeded */
522 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
524 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
531 /* Use softlimit to determine disk space, except when it has been exceeded */
533 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
534 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
535 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
536 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
540 *dsize = D.dqb_curblocks;
542 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
548 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
549 *dsize = D.dqb_bsoftlimit;
553 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
555 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
562 /* Use softlimit to determine disk space, except when it has been exceeded */
564 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
565 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
566 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
567 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
573 else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
579 *dfree = (F.d_blk_softlimit - F.d_bcount);
580 *dsize = F.d_blk_softlimit;
596 #if defined(__FreeBSD__) || defined(__OpenBSD__)
597 #include <ufs/ufs/quota.h>
598 #include <machine/param.h>
600 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
601 #include <jfs/quota.h>
602 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
603 #define dqb_curfiles dqb_curinodes
604 #define dqb_fhardlimit dqb_ihardlimit
605 #define dqb_fsoftlimit dqb_isoftlimit
606 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
607 #include <sys/quota.h>
611 /****************************************************************************
612 try to get the disk space from disk quotas - default version
613 ****************************************************************************/
615 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
620 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
623 /* find the block device file */
624 if ((sys_stat(path, &S)<0) ||
625 (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
628 euser_id = geteuid();
631 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
633 if (set_re_uid() != 0) return False;
635 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
639 #if defined(__FreeBSD__) || defined(__OpenBSD__)
641 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
645 set_effective_uid(0);
648 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
650 /* As FreeBSD has group quotas, if getting the user
651 quota fails, try getting the group instead. */
653 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
659 /* AIX has both USER and GROUP quotas:
660 Get the USER quota (ohnielse@fysik.dtu.dk) */
661 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
662 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
663 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
664 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
667 /* Use softlimit to determine disk space, except when it has been exceeded */
668 #if defined(__FreeBSD__) || defined(__OpenBSD__)
670 #else /* !__FreeBSD__ && !__OpenBSD__ */
672 #endif /*!__FreeBSD__ && !__OpenBSD__ */
679 *dsize =D.dqb_curblocks;
685 /* If softlimit is zero, set it equal to hardlimit.
688 if (D.dqb_bsoftlimit==0)
689 D.dqb_bsoftlimit = D.dqb_bhardlimit;
691 if (D.dqb_bsoftlimit==0)
693 /* Use softlimit to determine disk space, except when it has been exceeded */
694 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
695 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
696 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
700 *dsize = D.dqb_curblocks;
703 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
704 *dsize = D.dqb_bsoftlimit;
711 #if defined(VXFS_QUOTA)
713 /****************************************************************************
714 Try to get the disk space from Veritas disk quotas.
715 David Lee <T.D.Lee@durham.ac.uk> August 1999.
717 Background assumptions:
718 Potentially under many Operating Systems. Initially Solaris 2.
720 My guess is that Veritas is largely, though not entirely,
721 independent of OS. So I have separated it out.
723 There may be some details. For example, OS-specific "include" files.
725 It is understood that HPUX 10 somehow gets Veritas quotas without
726 any special effort; if so, this routine need not be compiled in.
727 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
730 It is understood that Veritas do not publicly support this ioctl interface.
731 Rather their preference would be for the user (us) to call the native
732 OS and then for the OS itself to call through to the VxFS filesystem.
733 Presumably HPUX 10, see above, does this.
736 Add your OS to "IFLIST" below.
737 Get it to compile successfully:
738 Almost certainly "include"s require attention: see SUNOS5.
739 In the main code above, arrange for it to be called: see SUNOS5.
742 ****************************************************************************/
745 * This "if" is a list of ports:
746 * if defined(OS1) || defined(OS2) || ...
751 #include <sys/fs/vx_solaris.h>
753 #include <sys/fs/vx_machdep.h>
754 #include <sys/fs/vx_layout.h>
755 #include <sys/fs/vx_quota.h>
756 #include <sys/fs/vx_aioctl.h>
757 #include <sys/fs/vx_ioctl.h>
759 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
761 uid_t user_id, euser_id;
764 struct vx_quotctl quotabuf;
765 struct vx_genioctl genbuf;
770 * "name" may or may not include a trailing "/quotas".
771 * Arranging consistency of calling here in "quotas.c" may not be easy and
772 * it might be easier to examine and adjust it here.
773 * Fortunately, VxFS seems not to mind at present.
775 pstrcpy(qfname, name) ;
776 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
778 euser_id = geteuid();
779 set_effective_uid(0);
781 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
782 if((file=sys_open(qfname, O_RDONLY,0))<0) {
783 set_effective_uid(euser_id);
786 genbuf.ioc_cmd = VX_QUOTACTL;
787 genbuf.ioc_up = (void *) "abuf;
789 quotabuf.cmd = VX_GETQUOTA;
790 quotabuf.uid = euser_id;
791 quotabuf.addr = (caddr_t) &D;
792 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
795 set_effective_uid(euser_id);
798 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
802 /* If softlimit is zero, set it equal to hardlimit.
805 if (D.dqb_bsoftlimit==0)
806 D.dqb_bsoftlimit = D.dqb_bhardlimit;
808 /* Use softlimit to determine disk space. A user exceeding the quota is told
809 * that there's no space left. Writes might actually work for a bit if the
810 * hardlimit is set higher than softlimit. Effectively the disk becomes
811 * made of rubber latex and begins to expand to accommodate the user :-)
813 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
814 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
815 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
817 if (D.dqb_bsoftlimit==0)
820 *dsize = D.dqb_bsoftlimit;
822 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
824 *dsize = D.dqb_curblocks;
826 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
828 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
829 path,(double)*bsize,(double)*dfree,(double)*dsize));
834 #endif /* SUNOS5 || ... */
836 #endif /* VXFS_QUOTA */