Cleaned up call_trans2getdfsreferral for when MS_DFS is not defined.
[ira/wip.git] / source3 / smbd / quotas.c
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
31 extern 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  */
40 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
41
42 #endif /* VXFS_QUOTA */
43
44 #ifdef LINUX
45
46 #include <sys/types.h>
47 #include <asm/types.h>
48 #include <sys/quota.h>
49
50 #include <mntent.h>
51 #include <linux/unistd.h>
52
53 _syscall4(int, quotactl, int, cmd, const char *, special, int, id, caddr_t, addr);
54
55 /****************************************************************************
56 try to get the disk space from disk quotas (LINUX version)
57 ****************************************************************************/
58
59 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
60 {
61   int r;
62   struct dqblk D;
63   SMB_STRUCT_STAT S;
64   FILE *fp;
65   struct mntent *mnt;
66   SMB_DEV_T devno;
67   int found;
68   uid_t euser_id;
69
70   euser_id = geteuid();
71   
72   /* find the block device file */
73   
74   if ( sys_stat(path, &S) == -1 ) {
75     return(False) ;
76   }
77
78   devno = S.st_dev ;
79   
80   fp = setmntent(MOUNTED,"r");
81   found = False ;
82   
83   while ((mnt = getmntent(fp))) {
84     if ( sys_stat(mnt->mnt_dir,&S) == -1 )
85       continue ;
86     if (S.st_dev == devno) {
87       found = True ;
88       break ;
89     }
90   }
91   endmntent(fp) ;
92   
93   if (!found) {
94       return(False);
95     }
96
97   save_re_uid();
98   set_effective_uid(0);  
99   r=quotactl(QCMD(Q_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D);
100   restore_re_uid();
101
102   /* Use softlimit to determine disk space, except when it has been exceeded */
103   *bsize = 1024;
104   if (r)
105     {
106       if (errno == EDQUOT) 
107        {
108          *dfree =0;
109          *dsize =D.dqb_curblocks;
110          return (True);
111     }
112       else return(False);
113   }
114   /* Use softlimit to determine disk space, except when it has been exceeded */
115   if (
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)
120      )
121     {
122       *dfree = 0;
123       *dsize = D.dqb_curblocks;
124     }
125   else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
126     {
127       return(False);
128     }
129   else {
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;
134   }
135   return (True);
136 }
137
138 #elif defined(CRAY)
139
140 #include <sys/quota.h>
141 #include <mntent.h>
142
143 /****************************************************************************
144 try to get the disk space from disk quotas (CRAY VERSION)
145 ****************************************************************************/
146
147 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
148 {
149   struct mntent *mnt;
150   FILE *fd;
151   SMB_STRUCT_STAT sbuf;
152   SMB_DEV_T devno ;
153   static SMB_DEV_T devno_cached = 0 ;
154   static pstring name;
155   struct q_request request ;
156   struct qf_header header ;
157   static int quota_default = 0 ;
158   int found ;
159   
160   if ( sys_stat(path,&sbuf) == -1 )
161     return(False) ;
162   
163   devno = sbuf.st_dev ;
164   
165   if ( devno != devno_cached ) {
166     
167     devno_cached = devno ;
168     
169     if ((fd = setmntent(KMTAB)) == NULL)
170       return(False) ;
171     
172     found = False ;
173     
174     while ((mnt = getmntent(fd)) != NULL) {
175       
176       if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
177         continue ;
178       
179       if (sbuf.st_dev == devno) {
180         
181         found = True ;
182         break ;
183         
184       }
185       
186     }
187     
188     pstrcpy(name,mnt->mnt_dir) ;
189     endmntent(fd) ;
190     
191     if ( ! found )
192       return(False) ;
193   }
194   
195   request.qf_magic = QF_MAGIC ;
196   request.qf_entry.id = geteuid() ;
197   
198   if (quotactl(name, Q_GETQUOTA, &request) == -1)
199     return(False) ;
200   
201   if ( ! request.user )
202     return(False) ;
203   
204   if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
205     
206     if ( ! quota_default ) {
207       
208       if ( quotactl(name, Q_GETHEADER, &header) == -1 )
209         return(False) ;
210       else
211         quota_default = header.user_h.def_fq ;
212     }
213     
214     *dfree = quota_default ;
215     
216   }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
217     
218     *dfree = 0 ;
219     
220   }else{
221     
222     *dfree = request.qf_entry.user_q.f_quota ;
223     
224   }
225   
226   *dsize = request.qf_entry.user_q.f_use ;
227   
228   if ( *dfree < *dsize )
229     *dfree = 0 ;
230   else
231     *dfree -= *dsize ;
232   
233   *bsize = 4096 ;  /* Cray blocksize */
234   
235   return(True) ;
236   
237 }
238
239
240 #elif defined(SUNOS5) || defined(SUNOS4)
241
242 #include <fcntl.h>
243 #include <sys/param.h>
244 #if defined(SUNOS5)
245 #include <sys/fs/ufs_quota.h>
246 #include <sys/mnttab.h>
247 #else /* defined(SUNOS4) */
248 #include <ufs/quota.h>
249 #include <mntent.h>
250 #endif
251
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 ****************************************************************************/
256
257 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
258 {
259   uid_t euser_id;
260   int ret;
261   struct dqblk D;
262 #if defined(SUNOS5)
263   struct quotctl command;
264   int file;
265   static struct mnttab mnt;
266   static pstring name;
267 #else /* SunOS4 */
268   struct mntent *mnt;
269   static pstring name;
270 #endif
271   FILE *fd;
272   SMB_STRUCT_STAT sbuf;
273   SMB_DEV_T devno ;
274   static SMB_DEV_T devno_cached = 0 ;
275   int found ;
276
277   euser_id = geteuid();
278   
279   if ( sys_stat(path,&sbuf) == -1 )
280     return(False) ;
281   
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 ;
286 #if defined(SUNOS5)
287     if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
288       return(False) ;
289     
290     found = False ;
291     while (getmntent(fd, &mnt) == 0) {
292       if ( sys_stat(mnt.mnt_mountp,&sbuf) == -1 )
293         continue ;
294       DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n", 
295                mnt.mnt_mountp,sbuf.st_dev));
296       if (sbuf.st_dev == devno) {
297         found = True ;
298         break ;
299       }
300     }
301     
302     pstrcpy(name,mnt.mnt_mountp) ;
303     pstrcat(name,"/quotas") ;
304     fclose(fd) ;
305 #else /* SunOS4 */
306     if ((fd = setmntent(MOUNTED, "r")) == NULL)
307       return(False) ;
308     
309     found = False ;
310     while ((mnt = getmntent(fd)) != NULL) {
311       if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
312         continue ;
313       DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n", 
314                mnt->mnt_dir,sbuf.st_dev));
315       if (sbuf.st_dev == devno) {
316         found = True ;
317         break ;
318       }
319     }
320     
321     pstrcpy(name,mnt->mnt_fsname) ;
322     endmntent(fd) ;
323 #endif
324     
325     if ( ! found )
326       return(False) ;
327   }
328
329   save_re_uid();
330   set_effective_uid(0);
331
332 #if defined(SUNOS5)
333   DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
334   if((file=sys_open(name, O_RDONLY,0))<0) {
335           restore_re_uid();
336           return(False);
337   }
338   command.op = Q_GETQUOTA;
339   command.uid = euser_id;
340   command.addr = (caddr_t) &D;
341   ret = ioctl(file, Q_QUOTACTL, &command);
342   close(file);
343 #else
344   DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
345   ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
346 #endif
347
348   restore_re_uid();
349
350   if (ret < 0) {
351     DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
352
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);
359       return(ret);
360     }
361 #else
362       return(False);
363 #endif
364   }
365
366
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 :-)
371    */
372
373   if (D.dqb_bsoftlimit==0)
374     return(False);
375   *bsize = DEV_BSIZE;
376   *dsize = D.dqb_bsoftlimit;
377
378   if (D.dqb_curblocks > D.dqb_bsoftlimit) {
379      *dfree = 0;
380      *dsize = D.dqb_curblocks;
381   } else
382     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
383       
384   DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",
385          path,(double)*bsize,(double)*dfree,(double)*dsize));
386
387       return(True);
388 }
389
390
391 #elif defined(OSF1)
392 #include <ufs/quota.h>
393
394 /****************************************************************************
395 try to get the disk space from disk quotas - OSF1 version
396 ****************************************************************************/
397
398 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
399 {
400   int r, save_errno;
401   struct dqblk D;
402   SMB_STRUCT_STAT S;
403   uid_t euser_id;
404
405   /*
406    * This code presumes that OSF1 will only
407    * give out quota info when the real uid 
408    * matches the effective uid. JRA.
409    */
410   euser_id = geteuid();
411   save_re_uid();
412   if (set_re_uid() != 0) return False;
413
414   r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
415   if (r) {
416      save_errno = errno;
417   }
418
419   restore_re_uid();
420
421   *bsize = DEV_BSIZE;
422
423   if (r)
424   {
425       if (save_errno == EDQUOT)   // disk quota exceeded
426       {
427          *dfree = 0;
428          *dsize = D.dqb_curblocks;
429          return (True);
430       }
431       else
432          return (False);  
433   }
434
435   /* Use softlimit to determine disk space, except when it has been exceeded */
436
437   if (D.dqb_bsoftlimit==0)
438     return(False);
439
440   if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
441     *dfree = 0;
442     *dsize = D.dqb_curblocks;
443   } else {
444     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
445     *dsize = D.dqb_bsoftlimit;
446   }
447   return (True);
448 }
449
450 #elif defined (IRIX6)
451 /****************************************************************************
452 try to get the disk space from disk quotas (IRIX 6.2 version)
453 ****************************************************************************/
454
455 #include <sys/quota.h>
456 #include <mntent.h>
457
458 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
459 {
460   uid_t euser_id;
461   int r;
462   struct dqblk D;
463   struct fs_disk_quota        F;
464   SMB_STRUCT_STAT S;
465   FILE *fp;
466   struct mntent *mnt;
467   SMB_DEV_T devno;
468   int found;
469   
470   /* find the block device file */
471   
472   if ( sys_stat(path, &S) == -1 ) {
473     return(False) ;
474   }
475
476   devno = S.st_dev ;
477   
478   fp = setmntent(MOUNTED,"r");
479   found = False ;
480   
481   while ((mnt = getmntent(fp))) {
482     if ( sys_stat(mnt->mnt_dir,&S) == -1 )
483       continue ;
484     if (S.st_dev == devno) {
485       found = True ;
486       break ;
487     }
488   }
489   endmntent(fp) ;
490   
491   if (!found) {
492     return(False);
493   }
494
495   euser_id=geteuid();
496   save_re_uid();
497   set_effective_uid(0);  
498
499   /* Use softlimit to determine disk space, except when it has been exceeded */
500
501   *bsize = 512;
502
503   if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
504   {
505     r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
506
507     restore_re_uid();
508
509     if (r==-1)
510       return(False);
511         
512     /* Use softlimit to determine disk space, except when it has been exceeded */
513     if (
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)
518        )
519     {
520       *dfree = 0;
521       *dsize = D.dqb_curblocks;
522     }
523     else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
524     {
525       return(False);
526     }
527     else 
528     {
529       *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
530       *dsize = D.dqb_bsoftlimit;
531     }
532
533   }
534   else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
535   {
536     r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
537
538     restore_re_uid();
539
540     if (r==-1)
541       return(False);
542         
543     /* Use softlimit to determine disk space, except when it has been exceeded */
544     if (
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)
549        )
550     {
551       *dfree = 0;
552       *dsize = F.d_bcount;
553     }
554     else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
555     {
556       return(False);
557     }
558     else 
559     {
560       *dfree = (F.d_blk_softlimit - F.d_bcount);
561       *dsize = F.d_blk_softlimit;
562     }
563
564   }
565   else
566   {
567           restore_re_uid();
568           return(False);
569   }
570
571   return (True);
572
573 }
574
575 #else
576
577 #if    defined(__FreeBSD__) || defined(__OpenBSD__)
578 #include <ufs/ufs/quota.h>
579 #include <machine/param.h>
580 #elif         AIX
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>
589 #include <devnm.h>
590 #endif
591
592 /****************************************************************************
593 try to get the disk space from disk quotas - default version
594 ****************************************************************************/
595
596 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
597 {
598   int r;
599   struct dqblk D;
600   uid_t euser_id;
601 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
602   char dev_disk[256];
603   SMB_STRUCT_STAT S;
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);
607 #endif
608
609   euser_id = geteuid();
610
611 #ifdef HPUX
612   /* for HPUX, real uid must be same as euid to execute quotactl for euid */
613   save_re_uid();
614   if (set_re_uid() != 0) return False;
615   
616   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
617
618   restore_re_uid();
619 #else 
620 #if defined(__FreeBSD__) || defined(__OpenBSD__)
621   {
622     /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
623     gid_t egrp_id;
624  
625     save_re_uid();
626     set_effective_uid(0);
627
628     egrp_id = getegid();
629     r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
630
631     /* As FreeBSD has group quotas, if getting the user
632        quota fails, try getting the group instead. */
633     if (r) {
634             r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
635     }
636
637     restore_re_uid();
638   }
639 #elif defined(AIX)
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__ */
646 #endif /* HPUX */
647
648   /* Use softlimit to determine disk space, except when it has been exceeded */
649 #if defined(__FreeBSD__) || defined(__OpenBSD__)
650   *bsize = DEV_BSIZE;
651 #else /* !__FreeBSD__ && !__OpenBSD__ */
652   *bsize = 1024;
653 #endif /*!__FreeBSD__ && !__OpenBSD__ */
654
655   if (r)
656     {
657       if (errno == EDQUOT) 
658         {
659           *dfree =0;
660           *dsize =D.dqb_curblocks;
661           return (True);
662         }
663       else return(False);
664     }
665   if (D.dqb_bsoftlimit==0)
666     return(False);
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))
671 #endif
672     ) {
673       *dfree = 0;
674       *dsize = D.dqb_curblocks;
675     }
676   else {
677     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
678     *dsize = D.dqb_bsoftlimit;
679   }
680   return (True);
681 }
682
683 #endif
684
685 #if defined(VXFS_QUOTA)
686
687 /****************************************************************************
688 Try to get the disk space from Veritas disk quotas.
689     David Lee <T.D.Lee@durham.ac.uk> August 1999.
690
691 Background assumptions:
692     Potentially under many Operating Systems.  Initially Solaris 2.
693
694     My guess is that Veritas is largely, though not entirely,
695     independent of OS.  So I have separated it out.
696
697     There may be some details.  For example, OS-specific "include" files.
698
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>
702
703 Warning:
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.
708
709 Hints for porting:
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.
714     Test!
715     
716 ****************************************************************************/
717
718 /* "IFLIST"
719  * This "if" is a list of ports:
720  *      if defined(OS1) || defined(OS2) || ...
721  */
722 #if defined(SUNOS5)
723
724 #if defined(SUNOS5)
725 #include <sys/fs/vx_solaris.h>
726 #endif
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>
732
733 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
734 {
735   uid_t user_id, euser_id;
736   int ret;
737   struct vx_dqblk D;
738   struct vx_quotctl quotabuf;
739   struct vx_genioctl genbuf;
740   pstring qfname;
741   int file;
742
743   /*
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.
748    */
749   pstrcpy(qfname, name) ;
750   /* pstrcat(qfname, "/quotas") ; */    /* possibly examine and adjust "name" */
751
752   euser_id = geteuid();
753   set_effective_uid(0);
754
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);
758     return(False);
759   }
760   genbuf.ioc_cmd = VX_QUOTACTL;
761   genbuf.ioc_up = (void *) &quotabuf;
762
763   quotabuf.cmd = VX_GETQUOTA;
764   quotabuf.uid = euser_id;
765   quotabuf.addr = (caddr_t) &D;
766   ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
767   close(file);
768
769   set_effective_uid(euser_id);
770
771   if (ret < 0) {
772     DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
773     return(False);
774   }
775
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 :-)
780    */
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));
784
785   if (D.dqb_bsoftlimit==0)
786     return(False);
787   *bsize = DEV_BSIZE;
788   *dsize = D.dqb_bsoftlimit;
789
790   if (D.dqb_curblocks > D.dqb_bsoftlimit) {
791      *dfree = 0;
792      *dsize = D.dqb_curblocks;
793   } else
794     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
795       
796   DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",
797          path,(double)*bsize,(double)*dfree,(double)*dsize));
798
799   return(True);
800 }
801
802 #endif /* SUNOS5 || ... */
803
804 #endif /* VXFS_QUOTA */