1/*
2   Unix SMB/Netbios implementation.
3   Version 1.9.
4   support for quotas
5   Copyright (C) Andrew Tridgell 1992-1998
6
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.
11
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.
16
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.
20*/
21
22
23/*
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
26 * things :-(
27 */
28
29#include "includes.h"
30
31extern int DEBUGLEVEL;
32
33#if defined(VXFS_QUOTA)
34
35/*
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>
39 */
40static BOOL disk_quotas_vxfs(const pstring name, char *path,
41			     SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree,
42			     SMB_BIG_UINT *dsize);
43
44#endif /* VXFS_QUOTA */
45
46#ifdef LINUX
47
48#include <sys/types.h>
49#include <asm/types.h>
50#include <sys/quota.h>
51
52#include <mntent.h>
53#include <linux/unistd.h>
54
55_syscall4(int, quotactl, int, cmd, const char *, special, int, id, caddr_t, addr);
56
57/****************************************************************************
58try to get the disk space from disk quotas (LINUX version)
59****************************************************************************/
60
61BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
62{
63  int r;
64  struct dqblk D;
65  SMB_STRUCT_STAT S;
66  FILE *fp;
67  struct mntent *mnt;
68  SMB_DEV_T devno;
69  int found;
70  uid_t euser_id;
71
72  euser_id = geteuid();
73
74  /* find the block device file */
75
76  if ( sys_stat(path, &S) == -1 ) {
77    return(False) ;
78  }
79
80  devno = S.st_dev ;
81
82  fp = setmntent(MOUNTED,"r");
83  found = False ;
84
85  while ((mnt = getmntent(fp))) {
86    if ( sys_stat(mnt->mnt_dir,&S) == -1 )
87      continue ;
88    if (S.st_dev == devno) {
89      found = True ;
90      break ;
91    }
92  }
93  endmntent(fp) ;
94
95  if (!found) {
96      return(False);
97    }
98
99  save_re_uid();
100  set_effective_uid(0);
101  r=quotactl(QCMD(Q_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D);
102  restore_re_uid();
103
104  /* Use softlimit to determine disk space, except when it has been exceeded */
105  *bsize = 1024;
106  if (r)
107    {
108      if (errno == EDQUOT)
109       {
110         *dfree =0;
111         *dsize =D.dqb_curblocks;
112         return (True);
113    }
114      else return(False);
115  }
116  /* Use softlimit to determine disk space, except when it has been exceeded */
117  if (
118      (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
119      (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
120      (D.dqb_isoftlimit && D.dqb_curinodes>=D.dqb_isoftlimit) ||
121      (D.dqb_ihardlimit && D.dqb_curinodes>=D.dqb_ihardlimit)
122     )
123    {
124      *dfree = 0;
125      *dsize = D.dqb_curblocks;
126    }
127  else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
128    {
129      return(False);
130    }
131  else {
132    if (D.dqb_bsoftlimit == 0)
133      D.dqb_bsoftlimit = D.dqb_bhardlimit;
134    *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
135    *dsize = D.dqb_bsoftlimit;
136  }
137  return (True);
138}
139
140#elif defined(CRAY)
141
142#include <sys/quota.h>
143#include <mntent.h>
144
145/****************************************************************************
146try to get the disk space from disk quotas (CRAY VERSION)
147****************************************************************************/
148
149BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
150{
151  struct mntent *mnt;
152  FILE *fd;
153  SMB_STRUCT_STAT sbuf;
154  SMB_DEV_T devno ;
155  static SMB_DEV_T devno_cached = 0 ;
156  static pstring name;
157  struct q_request request ;
158  struct qf_header header ;
159  static int quota_default = 0 ;
160  int found ;
161
162  if ( sys_stat(path,&sbuf) == -1 )
163    return(False) ;
164
165  devno = sbuf.st_dev ;
166
167  if ( devno != devno_cached ) {
168
169    devno_cached = devno ;
170
171    if ((fd = setmntent(KMTAB)) == NULL)
172      return(False) ;
173
174    found = False ;
175
176    while ((mnt = getmntent(fd)) != NULL) {
177
178      if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
179	continue ;
180
181      if (sbuf.st_dev == devno) {
182
183	found = True ;
184	break ;
185
186      }
187
188    }
189
190    pstrcpy(name,mnt->mnt_dir) ;
191    endmntent(fd) ;
192
193    if ( ! found )
194      return(False) ;
195  }
196
197  request.qf_magic = QF_MAGIC ;
198  request.qf_entry.id = geteuid() ;
199
200  if (quotactl(name, Q_GETQUOTA, &request) == -1)
201    return(False) ;
202
203  if ( ! request.user )
204    return(False) ;
205
206  if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
207
208    if ( ! quota_default ) {
209
210      if ( quotactl(name, Q_GETHEADER, &header) == -1 )
211	return(False) ;
212      else
213	quota_default = header.user_h.def_fq ;
214    }
215
216    *dfree = quota_default ;
217
218  }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
219
220    *dfree = 0 ;
221
222  }else{
223
224    *dfree = request.qf_entry.user_q.f_quota ;
225
226  }
227
228  *dsize = request.qf_entry.user_q.f_use ;
229
230  if ( *dfree < *dsize )
231    *dfree = 0 ;
232  else
233    *dfree -= *dsize ;
234
235  *bsize = 4096 ;  /* Cray blocksize */
236
237  return(True) ;
238
239}
240
241
242#elif defined(SUNOS5) || defined(SUNOS4)
243
244#include <fcntl.h>
245#include <sys/param.h>
246#if defined(SUNOS5)
247#include <sys/fs/ufs_quota.h>
248#include <sys/mnttab.h>
249#else /* defined(SUNOS4) */
250#include <ufs/quota.h>
251#include <mntent.h>
252#endif
253
254/****************************************************************************
255try to get the disk space from disk quotas (SunOS & Solaris2 version)
256Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
257****************************************************************************/
258
259BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
260{
261  uid_t euser_id;
262  int ret;
263  struct dqblk D;
264#if defined(SUNOS5)
265  struct quotctl command;
266  int file;
267  static struct mnttab mnt;
268  static pstring name;
269#else /* SunOS4 */
270  struct mntent *mnt;
271  static pstring name;
272#endif
273  FILE *fd;
274  SMB_STRUCT_STAT sbuf;
275  SMB_DEV_T devno ;
276  static SMB_DEV_T devno_cached = 0 ;
277  int found ;
278
279  euser_id = geteuid();
280
281  if ( sys_stat(path,&sbuf) == -1 )
282    return(False) ;
283
284  devno = sbuf.st_dev ;
285  DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%o\n", path,devno));
286  if ( devno != devno_cached ) {
287    devno_cached = devno ;
288#if defined(SUNOS5)
289    if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
290      return(False) ;
291
292    found = False ;
293    while (getmntent(fd, &mnt) == 0) {
294      if ( sys_stat(mnt.mnt_mountp,&sbuf) == -1 )
295	continue ;
296      DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n",
297	       mnt.mnt_mountp,sbuf.st_dev));
298      if (sbuf.st_dev == devno) {
299	found = True ;
300	break ;
301      }
302    }
303
304    pstrcpy(name,mnt.mnt_mountp) ;
305    pstrcat(name,"/quotas") ;
306    fclose(fd) ;
307#else /* SunOS4 */
308    if ((fd = setmntent(MOUNTED, "r")) == NULL)
309      return(False) ;
310
311    found = False ;
312    while ((mnt = getmntent(fd)) != NULL) {
313      if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
314	continue ;
315      DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n",
316	       mnt->mnt_dir,sbuf.st_dev));
317      if (sbuf.st_dev == devno) {
318	found = True ;
319	break ;
320      }
321    }
322
323    pstrcpy(name,mnt->mnt_fsname) ;
324    endmntent(fd) ;
325#endif
326
327    if ( ! found )
328      return(False) ;
329  }
330
331
332  save_re_uid();
333  set_effective_uid(0);
334
335#if defined(SUNOS5)
336  DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
337  if((file=sys_open(name, O_RDONLY,0))<0) {
338	  restore_re_uid();
339	  return(False);
340  }
341  command.op = Q_GETQUOTA;
342  command.uid = euser_id;
343  command.addr = (caddr_t) &D;
344  ret = ioctl(file, Q_QUOTACTL, &command);
345  close(file);
346#else
347  DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
348  ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
349#endif
350
351  restore_re_uid();
352
353  if (ret < 0) {
354    DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
355#if defined(SUNOS5) && defined(VXFS_QUOTA)
356    /* If normal quotactl() fails, try vxfs private calls */
357    set_effective_uid(euser_id);
358    DEBUG(5,("disk_quotas: VXFS_QUOTA: mount type \"%s\"\n", mnt.mnt_fstype));
359    if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
360      DEBUG(5,("disk_quotas: Trying VxFS quotactl call..\n"));
361      ret = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
362
363      return(ret);
364    }
365#endif
366
367    return(False);
368  }
369
370  /* If softlimit is zero, set it equal to hardlimit.
371   */
372
373  if (D.dqb_bsoftlimit==0)
374    D.dqb_bsoftlimit = D.dqb_bhardlimit;
375
376  /* Use softlimit to determine disk space. A user exceeding the quota is told
377   * that there's no space left. Writes might actually work for a bit if the
378   * hardlimit is set higher than softlimit. Effectively the disk becomes
379   * made of rubber latex and begins to expand to accommodate the user :-)
380   */
381
382  if (D.dqb_bsoftlimit==0)
383    return(False);
384  *bsize = DEV_BSIZE;
385  *dsize = D.dqb_bsoftlimit;
386
387  if (D.dqb_curblocks > D.dqb_bsoftlimit) {
388     *dfree = 0;
389     *dsize = D.dqb_curblocks;
390  } else
391    *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
392
393  DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",
394         path,(double)*bsize,(double)*dfree,(double)*dsize));
395
396      return(True);
397}
398
399
400#elif defined(OSF1)
401#include <ufs/quota.h>
402
403/****************************************************************************
404try to get the disk space from disk quotas - OSF1 version
405****************************************************************************/
406
407BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
408{
409  int r, save_errno;
410  struct dqblk D;
411  SMB_STRUCT_STAT S;
412  uid_t euser_id;
413
414  /*
415   * This code presumes that OSF1 will only
416   * give out quota info when the real uid
417   * matches the effective uid. JRA.
418   */
419  euser_id = geteuid();
420  save_re_uid();
421  if (set_re_uid() != 0) return False;
422
423  r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
424  if (r) {
425     save_errno = errno;
426  }
427
428  restore_re_uid();
429
430  *bsize = DEV_BSIZE;
431
432  if (r)
433  {
434      if (save_errno == EDQUOT)   // disk quota exceeded
435      {
436         *dfree = 0;
437         *dsize = D.dqb_curblocks;
438         return (True);
439      }
440      else
441         return (False);
442  }
443
444  /* If softlimit is zero, set it equal to hardlimit.
445   */
446
447  if (D.dqb_bsoftlimit==0)
448    D.dqb_bsoftlimit = D.dqb_bhardlimit;
449
450  /* Use softlimit to determine disk space, except when it has been exceeded */
451
452  if (D.dqb_bsoftlimit==0)
453    return(False);
454
455  if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
456    *dfree = 0;
457    *dsize = D.dqb_curblocks;
458  } else {
459    *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
460    *dsize = D.dqb_bsoftlimit;
461  }
462  return (True);
463}
464
465#elif defined (IRIX6)
466/****************************************************************************
467try to get the disk space from disk quotas (IRIX 6.2 version)
468****************************************************************************/
469
470#include <sys/quota.h>
471#include <mntent.h>
472
473BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
474{
475  uid_t euser_id;
476  int r;
477  struct dqblk D;
478  struct fs_disk_quota        F;
479  SMB_STRUCT_STAT S;
480  FILE *fp;
481  struct mntent *mnt;
482  SMB_DEV_T devno;
483  int found;
484
485  /* find the block device file */
486
487  if ( sys_stat(path, &S) == -1 ) {
488    return(False) ;
489  }
490
491  devno = S.st_dev ;
492
493  fp = setmntent(MOUNTED,"r");
494  found = False ;
495
496  while ((mnt = getmntent(fp))) {
497    if ( sys_stat(mnt->mnt_dir,&S) == -1 )
498      continue ;
499    if (S.st_dev == devno) {
500      found = True ;
501      break ;
502    }
503  }
504  endmntent(fp) ;
505
506  if (!found) {
507    return(False);
508  }
509
510  euser_id=geteuid();
511  save_re_uid();
512  set_effective_uid(0);
513
514  /* Use softlimit to determine disk space, except when it has been exceeded */
515
516  *bsize = 512;
517
518  if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
519  {
520    r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
521
522    restore_re_uid();
523
524    if (r==-1)
525      return(False);
526
527    /* Use softlimit to determine disk space, except when it has been exceeded */
528    if (
529        (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
530        (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
531        (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
532        (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
533       )
534    {
535      *dfree = 0;
536      *dsize = D.dqb_curblocks;
537    }
538    else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
539    {
540      return(False);
541    }
542    else
543    {
544      *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
545      *dsize = D.dqb_bsoftlimit;
546    }
547
548  }
549  else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
550  {
551    r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
552
553    restore_re_uid();
554
555    if (r==-1)
556      return(False);
557
558    /* Use softlimit to determine disk space, except when it has been exceeded */
559    if (
560        (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
561        (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
562        (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
563        (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
564       )
565    {
566      *dfree = 0;
567      *dsize = F.d_bcount;
568    }
569    else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
570    {
571      return(False);
572    }
573    else
574    {
575      *dfree = (F.d_blk_softlimit - F.d_bcount);
576      *dsize = F.d_blk_softlimit;
577    }
578
579  }
580  else
581  {
582	  restore_re_uid();
583	  return(False);
584  }
585
586  return (True);
587
588}
589
590#else
591
592#if    defined(__FreeBSD__) || defined(__OpenBSD__)
593#include <ufs/ufs/quota.h>
594#include <machine/param.h>
595#elif         AIX
596/* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
597#include <jfs/quota.h>
598/* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
599#define dqb_curfiles dqb_curinodes
600#define dqb_fhardlimit dqb_ihardlimit
601#define dqb_fsoftlimit dqb_isoftlimit
602#else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
603#include <sys/quota.h>
604#include <devnm.h>
605#endif
606
607/****************************************************************************
608try to get the disk space from disk quotas - default version
609****************************************************************************/
610
611BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
612{
613  int r;
614  struct dqblk D;
615  uid_t euser_id;
616#if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
617  char dev_disk[256];
618  SMB_STRUCT_STAT S;
619  /* find the block device file */
620  if ((sys_stat(path, &S)<0) ||
621      (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
622#endif
623
624  euser_id = geteuid();
625
626#ifdef HPUX
627  /* for HPUX, real uid must be same as euid to execute quotactl for euid */
628  save_re_uid();
629  if (set_re_uid() != 0) return False;
630
631  r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
632
633  restore_re_uid();
634#else
635#if defined(__FreeBSD__) || defined(__OpenBSD__)
636  {
637    /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
638    gid_t egrp_id;
639
640    save_re_uid();
641    set_effective_uid(0);
642
643    egrp_id = getegid();
644    r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
645
646    /* As FreeBSD has group quotas, if getting the user
647       quota fails, try getting the group instead. */
648    if (r) {
649	    r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
650    }
651
652    restore_re_uid();
653  }
654#elif defined(AIX)
655  /* AIX has both USER and GROUP quotas:
656     Get the USER quota (ohnielse@fysik.dtu.dk) */
657  r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
658#else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
659  r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
660#endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
661#endif /* HPUX */
662
663  /* Use softlimit to determine disk space, except when it has been exceeded */
664#if defined(__FreeBSD__) || defined(__OpenBSD__)
665  *bsize = DEV_BSIZE;
666#else /* !__FreeBSD__ && !__OpenBSD__ */
667  *bsize = 1024;
668#endif /*!__FreeBSD__ && !__OpenBSD__ */
669
670  if (r)
671    {
672      if (errno == EDQUOT)
673	{
674 	  *dfree =0;
675 	  *dsize =D.dqb_curblocks;
676 	  return (True);
677	}
678      else return(False);
679    }
680
681  /* If softlimit is zero, set it equal to hardlimit.
682   */
683
684  if (D.dqb_bsoftlimit==0)
685    D.dqb_bsoftlimit = D.dqb_bhardlimit;
686
687  if (D.dqb_bsoftlimit==0)
688    return(False);
689  /* Use softlimit to determine disk space, except when it has been exceeded */
690  if ((D.dqb_curblocks>D.dqb_bsoftlimit)
691#if !defined(__FreeBSD__) && !defined(__OpenBSD__)
692||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
693#endif
694    ) {
695      *dfree = 0;
696      *dsize = D.dqb_curblocks;
697    }
698  else {
699    *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
700    *dsize = D.dqb_bsoftlimit;
701  }
702  return (True);
703}
704
705#endif
706
707#if defined(VXFS_QUOTA)
708
709/****************************************************************************
710Try to get the disk space from Veritas disk quotas.
711    David Lee <T.D.Lee@durham.ac.uk> August 1999.
712
713Warning:
714    It is understood that Veritas do not publicly support this ioctl interface.
715    Rather their preference would be for the user (us) to call the native
716    OS and then for the OS itself to call through to the VxFS filesystem.
717    Presumably HPUX 10 does this, which is why this patch is not required for
718    HPUX 10.
719
720****************************************************************************/
721/***************************************************************************
722   VERITAS Disclaimer:
723   The following code uses private VxFS interfaces that are subject
724   to change without notice. It is distributed in the hope that it will
725   be useful, but WITHOUT ANY WARRANTY whatsoever.
726   VERITAS disclaims all liability resulting from use of this code.
727   VERITAS is under no obligation to maintain these private
728   interfaces in future releases of VERITAS products.
729 ***************************************************************************/
730
731#if defined(SUNOS5)
732#include <sys/fs/vx_solaris.h>
733#endif
734#include <sys/fs/vx_machdep.h>
735#include <sys/fs/vx_layout.h>
736#include <sys/fs/vx_quota.h>
737#include <sys/fs/vx_aioctl.h>
738#include <sys/fs/vx_ioctl.h>
739
740static BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
741{
742  uid_t user_id, euser_id;
743  int ret;
744  struct vx_dqblk D;
745  struct vx_quotctl quotabuf;
746  struct vx_genioctl genbuf;
747  pstring qfname;
748  int file;
749
750  /*
751   * "name" may or may not include a trailing "/quotas".
752   * Arranging consistency of calling here in "quotas.c" may not be easy and
753   * it might be easier to examine and adjust it here.
754   * Fortunately, VxFS seems not to mind at present.
755   */
756  pstrcpy(qfname, name) ;
757  /* pstrcat(qfname, "/quotas") ; */	/* possibly examine and adjust "name" */
758
759  euser_id = geteuid();
760  set_effective_uid(0);
761
762  DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
763  if((file=sys_open(qfname, O_RDONLY,0))<0) {
764    set_effective_uid(euser_id);
765    return(False);
766  }
767  genbuf.ioc_cmd = VX_QUOTACTL;
768  genbuf.ioc_up = (void *) &quotabuf;
769
770  quotabuf.cmd = VX_GETQUOTA;
771  quotabuf.uid = euser_id;
772  quotabuf.addr = (caddr_t) &D;
773  ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
774  close(file);
775
776  set_effective_uid(euser_id);
777
778  if (ret < 0) {
779    DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
780    return(False);
781  }
782
783  /* If softlimit is zero, set it equal to hardlimit.
784   */
785
786  if (D.dqb_bsoftlimit==0)
787    D.dqb_bsoftlimit = D.dqb_bhardlimit;
788
789  /* Use softlimit to determine disk space. A user exceeding the quota is told
790   * that there's no space left. Writes might actually work for a bit if the
791   * hardlimit is set higher than softlimit. Effectively the disk becomes
792   * made of rubber latex and begins to expand to accommodate the user :-)
793   */
794  DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
795         path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
796         D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
797
798  if (D.dqb_bsoftlimit==0)
799    return(False);
800  *bsize = DEV_BSIZE;
801  *dsize = D.dqb_bsoftlimit;
802
803  if (D.dqb_curblocks > D.dqb_bsoftlimit) {
804     *dfree = 0;
805     *dsize = D.dqb_curblocks;
806  } else
807    *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
808
809  DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",
810         path,(double)*bsize,(double)*dfree,(double)*dsize));
811
812  return(True);
813}
814
815#endif /* VXFS_QUOTA */
816