Makefile: Split definitions for SGI4,5,6.
[kai/samba.git] / source / smbd / quotas.c
index eba76d4c74b2384d2f3094a5f611b6e13649b521..8810bcd909d5e15780f9e8c605e03881afeea1a3 100644 (file)
@@ -33,47 +33,42 @@ extern int DEBUGLEVEL;
 
 #ifdef LINUX
 
-#ifdef __KERNEL__
-# undef __KERNEL__
-# include <sys/quota.h>
-# define __KERNEL__
-#else
-# include <sys/quota.h>
-#endif
+#include <sys/types.h>
+#include <asm/types.h>
+#include <sys/quota.h>
 
 #include <mntent.h>
+#include <linux/unistd.h>
+
+_syscall4(int, quotactl, int, cmd, const char *, special, int, id, caddr_t, addr);
 
 /****************************************************************************
 try to get the disk space from disk quotas (LINUX version)
 ****************************************************************************/
-/*
-If you didn't make the symlink to the quota package, too bad :(
-*/
-#include "quota/quotactl.c"
-#include "quota/hasquota.c"
+
 BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
 {
   uid_t euser_id;
+  int r;
   struct dqblk D;
   struct stat S;
-  dev_t devno ;
-  struct mntent *mnt;
   FILE *fp;
-  int found ;
-  int qcmd, fd ;
-  char *qfpathname;
+  struct mntent *mnt;
+  int devno;
+  int found;
   
   /* find the block device file */
   
-  if ( stat(path, &S) == -1 )
+  if ( stat(path, &S) == -1 ) {
     return(False) ;
+  }
 
   devno = S.st_dev ;
   
   fp = setmntent(MOUNTED,"r");
   found = False ;
   
-  while ((mnt = getmntent(fp)) != (struct mntent *) 0) {
+  while ((mnt = getmntent(fp))) {
     if ( stat(mnt->mnt_dir,&S) == -1 )
       continue ;
     if (S.st_dev == devno) {
@@ -83,48 +78,42 @@ BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
   }
   endmntent(fp) ;
   
-  if ( ! found )
-    return(False) ;
-  
-  qcmd = QCMD(Q_GETQUOTA, USRQUOTA);
-  
-  if (hasmntopt(mnt, MNTOPT_NOAUTO) || hasmntopt(mnt, MNTOPT_NOQUOTA))
-    return(False) ;
-  
-  if (!hasquota(mnt, USRQUOTA, &qfpathname))
-    return(False) ;
-  
-  euser_id = geteuid();
-  seteuid(0);
-  
-  if (quotactl(qcmd, mnt->mnt_fsname, euser_id, (caddr_t)&D) != 0) {
-    if ((fd = open(qfpathname, O_RDONLY)) < 0) {
-      seteuid(euser_id);
+  if (!found) {
       return(False);
     }
-    lseek(fd, (long) dqoff(euser_id), L_SET);
-    switch (read(fd, &D, sizeof(struct dqblk))) {
-    case 0:/* EOF */
-      memset((caddr_t)&D, 0, sizeof(struct dqblk));
-      break;
-    case sizeof(struct dqblk):   /* OK */
-      break;
-    default:   /* ERROR */
-      close(fd);
+
+  euser_id=geteuid();
+  seteuid(0);  
+  r=quotactl(QCMD(Q_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D);
       seteuid(euser_id);
-      return(False);
+
+  /* Use softlimit to determine disk space, except when it has been exceeded */
+  *bsize = 1024;
+  if (r)
+    {
+      if (errno == EDQUOT) 
+       {
+         *dfree =0;
+         *dsize =D.dqb_curblocks;
+         return (True);
     }
+      else return(False);
   }
-  seteuid(euser_id);
-  *bsize=1024;
-
-  if (D.dqb_bsoftlimit==0)
-    return(False);
-  if ((D.dqb_curblocks>D.dqb_bsoftlimit)||(D.dqb_curinodes>D.dqb_isoftlimit))
+  /* Use softlimit to determine disk space, except when it has been exceeded */
+  if (
+      (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
+      (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
+      (D.dqb_isoftlimit && D.dqb_curinodes>=D.dqb_isoftlimit) ||
+      (D.dqb_ihardlimit && D.dqb_curinodes>=D.dqb_ihardlimit)
+     )
     {
       *dfree = 0;
       *dsize = D.dqb_curblocks;
     }
+  else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
+    {
+      return(False);
+    }
   else {
     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
     *dsize = D.dqb_bsoftlimit;
@@ -342,7 +331,7 @@ BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
   ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
 #endif
 
-  setuid(user_id);  /* Restore the original UID status */
+  setuid(user_id); /* Restore the original uid status. */
   seteuid(euser_id);
 
   if (ret < 0) {
@@ -374,11 +363,193 @@ DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %d, dfree %d, dsize %d\n"
       return(True);
 }
 
+
+#elif defined(OSF1)
+#include <ufs/quota.h>
+
+/****************************************************************************
+try to get the disk space from disk quotas - OFS1 version
+****************************************************************************/
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+  uid_t user_id, euser_id;
+  int r, save_errno;
+  struct dqblk D;
+  struct stat S;
+
+  euser_id = geteuid();
+  user_id = getuid();
+
+  setreuid(euser_id, -1);
+  r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
+  if (r)
+     save_errno = errno;
+
+  if (setreuid(user_id, -1) == -1)
+    DEBUG(5,("Unable to reset uid to %d\n", user_id));
+
+  *bsize = DEV_BSIZE;
+
+  if (r)
+  {
+      if (save_errno == EDQUOT)   // disk quota exceeded
+      {
+         *dfree = 0;
+         *dsize = D.dqb_curblocks;
+         return (True);
+      }
+      else
+         return (False);  
+  }
+
+  /* Use softlimit to determine disk space, except when it has been exceeded */
+
+  if (D.dqb_bsoftlimit==0)
+    return(False);
+
+  if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
+    *dfree = 0;
+    *dsize = D.dqb_curblocks;
+  } else {
+    *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+    *dsize = D.dqb_bsoftlimit;
+  }
+  return (True);
+}
+
+#elif defined (SGI6)
+/****************************************************************************
+try to get the disk space from disk quotas (IRIX 6.2 version)
+****************************************************************************/
+
+#include <sys/quota.h>
+#include <mntent.h>
+
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+  uid_t euser_id;
+  int r;
+  struct dqblk D;
+  struct fs_disk_quota        F;
+  struct stat S;
+  FILE *fp;
+  struct mntent *mnt;
+  int devno;
+  int found;
+  
+  /* find the block device file */
+  
+  if ( stat(path, &S) == -1 ) {
+    return(False) ;
+  }
+
+  devno = S.st_dev ;
+  
+  fp = setmntent(MOUNTED,"r");
+  found = False ;
+  
+  while ((mnt = getmntent(fp))) {
+    if ( stat(mnt->mnt_dir,&S) == -1 )
+      continue ;
+    if (S.st_dev == devno) {
+      found = True ;
+      break ;
+    }
+  }
+  endmntent(fp) ;
+  
+  if (!found) {
+    return(False);
+  }
+
+  euser_id=geteuid();
+  seteuid(0);  
+
+  /* Use softlimit to determine disk space, except when it has been exceeded */
+
+  *bsize = 512;
+
+  if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
+  {
+    r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
+
+    if (r==-1)
+      return(False);
+        
+    /* Use softlimit to determine disk space, except when it has been exceeded */
+    if (
+        (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
+        (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
+        (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
+        (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
+       )
+    {
+      *dfree = 0;
+      *dsize = D.dqb_curblocks;
+    }
+    else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
+    {
+      return(False);
+    }
+    else 
+    {
+      *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+      *dsize = D.dqb_bsoftlimit;
+    }
+
+  }
+  else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
+  {
+    r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
+
+    if (r==-1)
+      return(False);
+        
+    /* Use softlimit to determine disk space, except when it has been exceeded */
+    if (
+        (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
+        (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
+        (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
+        (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
+       )
+    {
+      /*
+       * Fixme!: these are __uint64_t, this may truncate values
+       */
+      *dfree = 0;
+      *dsize = (int) F.d_bcount;
+    }
+    else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
+    {
+      return(False);
+    }
+    else 
+    {
+      *dfree = (int)(F.d_blk_softlimit - F.d_bcount);
+      *dsize = (int)F.d_blk_softlimit;
+    }
+
+  }
+  else
+    return(False);
+
+  return (True);
+
+}
+
 #else
 
 #ifdef        __FreeBSD__
 #include <ufs/ufs/quota.h>
-#else
+#include <machine/param.h>
+#elif         AIX
+/* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
+#include <jfs/quota.h>
+/* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
+#define dqb_curfiles dqb_curinodes
+#define dqb_fhardlimit dqb_ihardlimit
+#define dqb_fsoftlimit dqb_isoftlimit
+#else /* !__FreeBSD__ && !AIX */
 #include <sys/quota.h>
 #include <devnm.h>
 #endif
@@ -388,12 +559,12 @@ try to get the disk space from disk quotas - default version
 ****************************************************************************/
 BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
 {
-  uid_t user_id, euser_id;
+  uid_t euser_id;
   int r;
-  char dev_disk[256];
   struct dqblk D;
+#if !defined(__FreeBSD__) && !defined(AIX)
+  char dev_disk[256];
   struct stat S;
-#ifndef __FreeBSD__
   /* find the block device file */
   if ((stat(path, &S)<0) ||
       (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
@@ -402,22 +573,53 @@ BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
   euser_id = geteuid();
 
 #ifdef USE_SETRES
-  /* for HPUX, real uid must be same as euid to execute quotactl for euid */
-  user_id = getuid();
-  setresuid(euser_id,-1,-1);
-  r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
-  if (setresuid(user_id,-1,-1))
-    DEBUG(5,("Unable to reset uid to %d\n", user_id));
-#else
+  {
+    uid_t user_id;
+
+    /* for HPUX, real uid must be same as euid to execute quotactl for euid */
+    user_id = getuid();
+    setresuid(euser_id,-1,-1);
+    r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
+    if (setresuid(user_id,-1,-1))
+      DEBUG(5,("Unable to reset uid to %d\n", user_id));
+  }
+#else /* USE_SETRES */
 #if defined(__FreeBSD__)
-  r= quotactl(path,Q_GETQUOTA,euser_id,(char *) &D);
-#else
+  {
+    /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
+    uid_t user_id;
+    gid_t egrp_id;
+    /* Need to be root to get quotas in FreeBSD */
+    user_id = getuid();
+    egrp_id = getegid();
+    setuid(0);
+    seteuid(0);
+    r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
+
+    /* As FreeBSD has group quotas, if getting the user
+       quota fails, try getting the group instead. */
+    if (r)
+      r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
+    setuid(user_id);
+    seteuid(euser_id);
+  }
+#elif defined(AIX)
+  /* AIX has both USER and GROUP quotas: 
+     Get the USER quota (ohnielse@fysik.dtu.dk) */
+  r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
+#else /* !__FreeBSD__ && !AIX */
   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
-#endif
-#endif
+#endif /* !__FreeBSD__ && !AIX */
+#endif /* USE_SETRES */
 
   /* Use softlimit to determine disk space, except when it has been exceeded */
+#if defined(__FreeBSD__)
+  *bsize = DEV_BSIZE;
+#else /* !__FreeBSD__ */
   *bsize = 1024;
+#endif /*!__FreeBSD__ */
+
   if (r)
     {
       if (errno == EDQUOT) 
@@ -433,7 +635,7 @@ BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
   /* Use softlimit to determine disk space, except when it has been exceeded */
   if ((D.dqb_curblocks>D.dqb_bsoftlimit)
 #if !defined(__FreeBSD__)
-||(D.dqb_curfiles>D.dqb_fsoftlimit)
+||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
 #endif
     ) {
       *dfree = 0;