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);
367 /* Use softlimit to determine disk space. A user exceeding the quota is told
368 * that there's no space left. Writes might actually work for a bit if the
369 * hardlimit is set higher than softlimit. Effectively the disk becomes
370 * made of rubber latex and begins to expand to accommodate the user :-)
373 if (D.dqb_bsoftlimit==0)
376 *dsize = D.dqb_bsoftlimit;
378 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
380 *dsize = D.dqb_curblocks;
382 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
384 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
385 path,(double)*bsize,(double)*dfree,(double)*dsize));
392 #include <ufs/quota.h>
394 /****************************************************************************
395 try to get the disk space from disk quotas - OSF1 version
396 ****************************************************************************/
398 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
406 * This code presumes that OSF1 will only
407 * give out quota info when the real uid
408 * matches the effective uid. JRA.
410 euser_id = geteuid();
412 if (set_re_uid() != 0) return False;
414 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
425 if (save_errno == EDQUOT) // disk quota exceeded
428 *dsize = D.dqb_curblocks;
435 /* Use softlimit to determine disk space, except when it has been exceeded */
437 if (D.dqb_bsoftlimit==0)
440 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
442 *dsize = D.dqb_curblocks;
444 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
445 *dsize = D.dqb_bsoftlimit;
450 #elif defined (IRIX6)
451 /****************************************************************************
452 try to get the disk space from disk quotas (IRIX 6.2 version)
453 ****************************************************************************/
455 #include <sys/quota.h>
458 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
463 struct fs_disk_quota F;
470 /* find the block device file */
472 if ( sys_stat(path, &S) == -1 ) {
478 fp = setmntent(MOUNTED,"r");
481 while ((mnt = getmntent(fp))) {
482 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
484 if (S.st_dev == devno) {
497 set_effective_uid(0);
499 /* Use softlimit to determine disk space, except when it has been exceeded */
503 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
505 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
512 /* Use softlimit to determine disk space, except when it has been exceeded */
514 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
515 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
516 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
517 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
521 *dsize = D.dqb_curblocks;
523 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
529 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
530 *dsize = D.dqb_bsoftlimit;
534 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
536 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
543 /* Use softlimit to determine disk space, except when it has been exceeded */
545 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
546 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
547 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
548 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
554 else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
560 *dfree = (F.d_blk_softlimit - F.d_bcount);
561 *dsize = F.d_blk_softlimit;
577 #if defined(__FreeBSD__) || defined(__OpenBSD__)
578 #include <ufs/ufs/quota.h>
579 #include <machine/param.h>
581 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
582 #include <jfs/quota.h>
583 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
584 #define dqb_curfiles dqb_curinodes
585 #define dqb_fhardlimit dqb_ihardlimit
586 #define dqb_fsoftlimit dqb_isoftlimit
587 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
588 #include <sys/quota.h>
592 /****************************************************************************
593 try to get the disk space from disk quotas - default version
594 ****************************************************************************/
596 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
601 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
604 /* find the block device file */
605 if ((sys_stat(path, &S)<0) ||
606 (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
609 euser_id = geteuid();
612 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
614 if (set_re_uid() != 0) return False;
616 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
620 #if defined(__FreeBSD__) || defined(__OpenBSD__)
622 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
626 set_effective_uid(0);
629 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
631 /* As FreeBSD has group quotas, if getting the user
632 quota fails, try getting the group instead. */
634 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
640 /* AIX has both USER and GROUP quotas:
641 Get the USER quota (ohnielse@fysik.dtu.dk) */
642 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
643 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
644 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
645 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
648 /* Use softlimit to determine disk space, except when it has been exceeded */
649 #if defined(__FreeBSD__) || defined(__OpenBSD__)
651 #else /* !__FreeBSD__ && !__OpenBSD__ */
653 #endif /*!__FreeBSD__ && !__OpenBSD__ */
660 *dsize =D.dqb_curblocks;
665 if (D.dqb_bsoftlimit==0)
667 /* Use softlimit to determine disk space, except when it has been exceeded */
668 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
669 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
670 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
674 *dsize = D.dqb_curblocks;
677 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
678 *dsize = D.dqb_bsoftlimit;
685 #if defined(VXFS_QUOTA)
687 /****************************************************************************
688 Try to get the disk space from Veritas disk quotas.
689 David Lee <T.D.Lee@durham.ac.uk> August 1999.
691 Background assumptions:
692 Potentially under many Operating Systems. Initially Solaris 2.
694 My guess is that Veritas is largely, though not entirely,
695 independent of OS. So I have separated it out.
697 There may be some details. For example, OS-specific "include" files.
699 It is understood that HPUX 10 somehow gets Veritas quotas without
700 any special effort; if so, this routine need not be compiled in.
701 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
704 It is understood that Veritas do not publicly support this ioctl interface.
705 Rather their preference would be for the user (us) to call the native
706 OS and then for the OS itself to call through to the VxFS filesystem.
707 Presumably HPUX 10, see above, does this.
710 Add your OS to "IFLIST" below.
711 Get it to compile successfully:
712 Almost certainly "include"s require attention: see SUNOS5.
713 In the main code above, arrange for it to be called: see SUNOS5.
716 ****************************************************************************/
719 * This "if" is a list of ports:
720 * if defined(OS1) || defined(OS2) || ...
725 #include <sys/fs/vx_solaris.h>
727 #include <sys/fs/vx_machdep.h>
728 #include <sys/fs/vx_layout.h>
729 #include <sys/fs/vx_quota.h>
730 #include <sys/fs/vx_aioctl.h>
731 #include <sys/fs/vx_ioctl.h>
733 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
735 uid_t user_id, euser_id;
738 struct vx_quotctl quotabuf;
739 struct vx_genioctl genbuf;
744 * "name" may or may not include a trailing "/quotas".
745 * Arranging consistency of calling here in "quotas.c" may not be easy and
746 * it might be easier to examine and adjust it here.
747 * Fortunately, VxFS seems not to mind at present.
749 pstrcpy(qfname, name) ;
750 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
752 euser_id = geteuid();
753 set_effective_uid(0);
755 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
756 if((file=sys_open(qfname, O_RDONLY,0))<0) {
757 set_effective_uid(euser_id);
760 genbuf.ioc_cmd = VX_QUOTACTL;
761 genbuf.ioc_up = (void *) "abuf;
763 quotabuf.cmd = VX_GETQUOTA;
764 quotabuf.uid = euser_id;
765 quotabuf.addr = (caddr_t) &D;
766 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
769 set_effective_uid(euser_id);
772 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
776 /* Use softlimit to determine disk space. A user exceeding the quota is told
777 * that there's no space left. Writes might actually work for a bit if the
778 * hardlimit is set higher than softlimit. Effectively the disk becomes
779 * made of rubber latex and begins to expand to accommodate the user :-)
781 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
782 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
783 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
785 if (D.dqb_bsoftlimit==0)
788 *dsize = D.dqb_bsoftlimit;
790 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
792 *dsize = D.dqb_curblocks;
794 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
796 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
797 path,(double)*bsize,(double)*dfree,(double)*dsize));
802 #endif /* SUNOS5 || ... */
804 #endif /* VXFS_QUOTA */