root/source3/smbd/quotas.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_smb_linux_xfs_quota
  2. get_smb_linux_xfs_quota
  3. get_smb_linux_v1_quota
  4. get_smb_linux_v2_quota
  5. get_smb_linux_gen_quota
  6. disk_quotas
  7. disk_quotas
  8. my_xdr_getquota_args
  9. my_xdr_getquota_rslt
  10. nfs_quotas
  11. disk_quotas
  12. disk_quotas
  13. disk_quotas
  14. my_xdr_getquota_args
  15. my_xdr_getquota_rslt
  16. nfs_quotas
  17. disk_quotas
  18. disk_quotas_vxfs
  19. disk_quotas
  20. disk_quotas

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    support for quotas
   4    Copyright (C) Andrew Tridgell 1992-1998
   5    
   6    This program is free software; you can redistribute it and/or modify
   7    it under the terms of the GNU General Public License as published by
   8    the Free Software Foundation; either version 3 of the License, or
   9    (at your option) any later version.
  10    
  11    This program is distributed in the hope that it will be useful,
  12    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14    GNU General Public License for more details.
  15    
  16    You should have received a copy of the GNU General Public License
  17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19 
  20 
  21 /* 
  22  * This is one of the most system dependent parts of Samba, and its
  23  * done a litle differently. Each system has its own way of doing 
  24  * things :-(
  25  */
  26 
  27 #include "includes.h"
  28 
  29 #undef DBGC_CLASS
  30 #define DBGC_CLASS DBGC_QUOTA
  31 
  32 #ifndef HAVE_SYS_QUOTAS
  33 
  34 /* just a quick hack because sysquotas.h is included before linux/quota.h */
  35 #ifdef QUOTABLOCK_SIZE
  36 #undef QUOTABLOCK_SIZE
  37 #endif
  38 
  39 #ifdef WITH_QUOTAS
  40 
  41 #if defined(VXFS_QUOTA)
  42 
  43 /*
  44  * In addition to their native filesystems, some systems have Veritas VxFS.
  45  * Declare here, define at end: reduces likely "include" interaction problems.
  46  *      David Lee <T.D.Lee@durham.ac.uk>
  47  */
  48 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize);
  49 
  50 #endif /* VXFS_QUOTA */
  51 
  52 #ifdef LINUX
  53 
  54 #include <sys/types.h>
  55 #include <mntent.h>
  56 
  57 /*
  58  * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
  59  * So we include all the files has *should* be in the system into a large,
  60  * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA.
  61  */
  62 
  63 #include "samba_linux_quota.h"
  64 
  65 typedef struct _LINUX_SMB_DISK_QUOTA {
  66         uint64_t bsize;
  67         uint64_t hardlimit; /* In bsize units. */
  68         uint64_t softlimit; /* In bsize units. */
  69         uint64_t curblocks; /* In bsize units. */
  70         uint64_t ihardlimit; /* inode hard limit. */
  71         uint64_t isoftlimit; /* inode soft limit. */
  72         uint64_t curinodes; /* Current used inodes. */
  73 } LINUX_SMB_DISK_QUOTA;
  74 
  75 
  76 #ifdef HAVE_LINUX_DQBLK_XFS_H
  77 #include <linux/dqblk_xfs.h>
  78 
  79 /****************************************************************************
  80  Abstract out the XFS Quota Manager quota get call.
  81 ****************************************************************************/
  82 
  83 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
     /* [<][>][^][v][top][bottom][index][help] */
  84 {
  85         struct fs_disk_quota D;
  86         int ret;
  87 
  88         ZERO_STRUCT(D);
  89 
  90         ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
  91 
  92         if (ret)
  93                 ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
  94 
  95         if (ret)
  96                 return ret;
  97 
  98         dp->bsize = (uint64_t)512;
  99         dp->softlimit = (uint64_t)D.d_blk_softlimit;
 100         dp->hardlimit = (uint64_t)D.d_blk_hardlimit;
 101         dp->ihardlimit = (uint64_t)D.d_ino_hardlimit;
 102         dp->isoftlimit = (uint64_t)D.d_ino_softlimit;
 103         dp->curinodes = (uint64_t)D.d_icount;
 104         dp->curblocks = (uint64_t)D.d_bcount;
 105 
 106         return ret;
 107 }
 108 #else
 109 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
     /* [<][>][^][v][top][bottom][index][help] */
 110 {
 111         DEBUG(0,("XFS quota support not available\n"));
 112         errno = ENOSYS;
 113         return -1;
 114 }
 115 #endif
 116 
 117 
 118 /****************************************************************************
 119  Abstract out the old and new Linux quota get calls.
 120 ****************************************************************************/
 121 
 122 static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
     /* [<][>][^][v][top][bottom][index][help] */
 123 {
 124         struct v1_kern_dqblk D;
 125         int ret;
 126 
 127         ZERO_STRUCT(D);
 128 
 129         ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
 130 
 131         if (ret && errno != EDQUOT)
 132                 ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
 133 
 134         if (ret && errno != EDQUOT)
 135                 return ret;
 136 
 137         dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
 138         dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
 139         dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
 140         dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
 141         dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
 142         dp->curinodes = (uint64_t)D.dqb_curinodes;
 143         dp->curblocks = (uint64_t)D.dqb_curblocks;
 144 
 145         return ret;
 146 }
 147 
 148 static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
     /* [<][>][^][v][top][bottom][index][help] */
 149 {
 150         struct v2_kern_dqblk D;
 151         int ret;
 152 
 153         ZERO_STRUCT(D);
 154 
 155         ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
 156 
 157         if (ret && errno != EDQUOT)
 158                 ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
 159 
 160         if (ret && errno != EDQUOT)
 161                 return ret;
 162 
 163         dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
 164         dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
 165         dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
 166         dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
 167         dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
 168         dp->curinodes = (uint64_t)D.dqb_curinodes;
 169         dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
 170 
 171         return ret;
 172 }
 173 
 174 /****************************************************************************
 175  Brand-new generic quota interface.
 176 ****************************************************************************/
 177 
 178 static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
     /* [<][>][^][v][top][bottom][index][help] */
 179 {
 180         struct if_dqblk D;
 181         int ret;
 182 
 183         ZERO_STRUCT(D);
 184 
 185         ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
 186 
 187         if (ret && errno != EDQUOT)
 188                 ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
 189 
 190         if (ret && errno != EDQUOT)
 191                 return ret;
 192 
 193         dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
 194         dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
 195         dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
 196         dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
 197         dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
 198         dp->curinodes = (uint64_t)D.dqb_curinodes;
 199         dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
 200 
 201         return ret;
 202 }
 203 
 204 /****************************************************************************
 205  Try to get the disk space from disk quotas (LINUX version).
 206 ****************************************************************************/
 207 
 208 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
     /* [<][>][^][v][top][bottom][index][help] */
 209 {
 210         int r;
 211         SMB_STRUCT_STAT S;
 212         FILE *fp;
 213         LINUX_SMB_DISK_QUOTA D;
 214         struct mntent *mnt;
 215         SMB_DEV_T devno;
 216         int found;
 217         uid_t euser_id;
 218         gid_t egrp_id;
 219 
 220         ZERO_STRUCT(D);
 221 
 222         euser_id = geteuid();
 223         egrp_id = getegid();
 224 
 225         /* find the block device file */
 226 
 227         if ( sys_stat(path, &S) == -1 )
 228                 return(False) ;
 229 
 230         devno = S.st_dev ;
 231 
 232         if ((fp = setmntent(MOUNTED,"r")) == NULL)
 233                 return(False) ;
 234 
 235         found = False ;
 236 
 237         while ((mnt = getmntent(fp))) {
 238                 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
 239                         continue ;
 240 
 241                 if (S.st_dev == devno) {
 242                         found = True ;
 243                         break;
 244                 }
 245         }
 246 
 247         endmntent(fp) ;
 248 
 249         if (!found)
 250                 return(False);
 251 
 252         become_root();
 253 
 254         if (strcmp(mnt->mnt_type, "xfs")==0) {
 255                 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
 256         } else {
 257                 r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
 258                 if (r == -1 && errno != EDQUOT) {
 259                         r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
 260                         if (r == -1 && errno != EDQUOT)
 261                                 r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
 262                 }
 263         }
 264 
 265         unbecome_root();
 266 
 267         /* Use softlimit to determine disk space, except when it has been exceeded */
 268         *bsize = D.bsize;
 269         if (r == -1) {
 270                 if (errno == EDQUOT) {
 271                         *dfree =0;
 272                         *dsize =D.curblocks;
 273                         return (True);
 274                 } else {
 275                         return(False);
 276                 }
 277         }
 278 
 279         /* Use softlimit to determine disk space, except when it has been exceeded */
 280         if (
 281                 (D.softlimit && D.curblocks >= D.softlimit) ||
 282                 (D.hardlimit && D.curblocks >= D.hardlimit) ||
 283                 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
 284                 (D.ihardlimit && D.curinodes>=D.ihardlimit)
 285         ) {
 286                 *dfree = 0;
 287                 *dsize = D.curblocks;
 288         } else if (D.softlimit==0 && D.hardlimit==0) {
 289                 return(False);
 290         } else {
 291                 if (D.softlimit == 0)
 292                         D.softlimit = D.hardlimit;
 293                 *dfree = D.softlimit - D.curblocks;
 294                 *dsize = D.softlimit;
 295         }
 296 
 297         return (True);
 298 }
 299 
 300 #elif defined(CRAY)
 301 
 302 #include <sys/quota.h>
 303 #include <mntent.h>
 304 
 305 /****************************************************************************
 306 try to get the disk space from disk quotas (CRAY VERSION)
 307 ****************************************************************************/
 308 
 309 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
     /* [<][>][^][v][top][bottom][index][help] */
 310 {
 311         struct mntent *mnt;
 312         FILE *fd;
 313         SMB_STRUCT_STAT sbuf;
 314         SMB_DEV_T devno ;
 315         struct q_request request ;
 316         struct qf_header header ;
 317         int quota_default = 0 ;
 318         bool found = false;
 319 
 320         if (sys_stat(path,&sbuf) == -1) {
 321                 return false;
 322         }
 323 
 324         devno = sbuf.st_dev ;
 325 
 326         if ((fd = setmntent(KMTAB)) == NULL) {
 327                 return false;
 328         }
 329 
 330         while ((mnt = getmntent(fd)) != NULL) {
 331                 if (sys_stat(mnt->mnt_dir,&sbuf) == -1) {
 332                         continue;
 333                 }
 334                 if (sbuf.st_dev == devno) {
 335                         found = frue ;
 336                         break;
 337                 }
 338         }
 339 
 340         name = talloc_strdup(talloc_tos(), mnt->mnt_dir);
 341         endmntent(fd);
 342         if (!found) {
 343                 return false;
 344         }
 345 
 346         if (!name) {
 347                 return false;
 348         }
 349 
 350         request.qf_magic = QF_MAGIC ;
 351         request.qf_entry.id = geteuid() ;
 352 
 353         if (quotactl(name, Q_GETQUOTA, &request) == -1) {
 354                 return false;
 355         }
 356 
 357         if (!request.user) {
 358                 return False;
 359         }
 360 
 361         if (request.qf_entry.user_q.f_quota == QFV_DEFAULT) {
 362                 if (!quota_default) {
 363                         if (quotactl(name, Q_GETHEADER, &header) == -1) {
 364                                 return false;
 365                         } else {
 366                                 quota_default = header.user_h.def_fq;
 367                         }
 368                 }
 369                 *dfree = quota_default;
 370         } else if (request.qf_entry.user_q.f_quota == QFV_PREVENT) {
 371                 *dfree = 0;
 372         } else {
 373                 *dfree = request.qf_entry.user_q.f_quota;
 374         }
 375 
 376         *dsize = request.qf_entry.user_q.f_use;
 377 
 378         if (*dfree < *dsize) {
 379                 *dfree = 0;
 380         } else {
 381                 *dfree -= *dsize;
 382         }
 383 
 384         *bsize = 4096 ;  /* Cray blocksize */
 385         return true;
 386 }
 387 
 388 
 389 #elif defined(SUNOS5) || defined(SUNOS4)
 390 
 391 #include <fcntl.h>
 392 #include <sys/param.h>
 393 #if defined(SUNOS5)
 394 #include <sys/fs/ufs_quota.h>
 395 #include <sys/mnttab.h>
 396 #include <sys/mntent.h>
 397 #else /* defined(SUNOS4) */
 398 #include <ufs/quota.h>
 399 #include <mntent.h>
 400 #endif
 401 
 402 #if defined(SUNOS5)
 403 
 404 /****************************************************************************
 405  Allows querying of remote hosts for quotas on NFS mounted shares.
 406  Supports normal NFS and AMD mounts.
 407  Alan Romeril <a.romeril@ic.ac.uk> July 2K.
 408 ****************************************************************************/
 409 
 410 #include <rpc/rpc.h>
 411 #include <rpc/types.h>
 412 #include <rpcsvc/rquota.h>
 413 #include <rpc/nettype.h>
 414 #include <rpc/xdr.h>
 415 
 416 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
     /* [<][>][^][v][top][bottom][index][help] */
 417 {
 418         if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
 419                 return(0);
 420         if (!xdr_int(xdrsp, &args->gqa_uid))
 421                 return(0);
 422         return (1);
 423 }
 424 
 425 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
     /* [<][>][^][v][top][bottom][index][help] */
 426 {
 427         int quotastat;
 428 
 429         if (!xdr_int(xdrsp, &quotastat)) {
 430                 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
 431                 return 0;
 432         }
 433         gqr->status = quotastat;
 434 
 435         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
 436                 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
 437                 return 0;
 438         }
 439         if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
 440                 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
 441                 return 0;
 442         }
 443         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
 444                 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
 445                 return 0;
 446         }
 447         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
 448                 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
 449                 return 0;
 450         }
 451         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
 452                 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
 453                 return 0;
 454         }
 455         return (1);
 456 }
 457 
 458 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
 459 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
     /* [<][>][^][v][top][bottom][index][help] */
 460 {
 461         uid_t uid = euser_id;
 462         struct dqblk D;
 463         char *mnttype = nfspath;
 464         CLIENT *clnt;
 465         struct getquota_rslt gqr;
 466         struct getquota_args args;
 467         char *cutstr, *pathname, *host, *testpath;
 468         int len;
 469         static struct timeval timeout = {2,0};
 470         enum clnt_stat clnt_stat;
 471         bool ret = True;
 472 
 473         *bsize = *dfree = *dsize = (uint64_t)0;
 474 
 475         len=strcspn(mnttype, ":");
 476         pathname=strstr(mnttype, ":");
 477         cutstr = (char *) SMB_MALLOC(len+1);
 478         if (!cutstr)
 479                 return False;
 480 
 481         memset(cutstr, '\0', len+1);
 482         host = strncat(cutstr,mnttype, sizeof(char) * len );
 483         DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
 484         DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
 485         testpath=strchr_m(mnttype, ':');
 486         args.gqa_pathp = testpath+1;
 487         args.gqa_uid = uid;
 488 
 489         DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
 490 
 491         if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
 492                 ret = False;
 493                 goto out;
 494         }
 495 
 496         clnt->cl_auth = authunix_create_default();
 497         DEBUG(9,("nfs_quotas: auth_success\n"));
 498 
 499         clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
 500 
 501         if (clnt_stat != RPC_SUCCESS) {
 502                 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
 503                 ret = False;
 504                 goto out;
 505         }
 506 
 507         /*
 508          * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
 509          * no quota set, and 3 if no permission to get the quota.  If 0 or 3 return
 510          * something sensible.
 511          */
 512 
 513         switch (gqr.status) {
 514         case 0:
 515                 DEBUG(9,("nfs_quotas: Remote Quotas Failed!  Error \"%i\" \n", gqr.status));
 516                 ret = False;
 517                 goto out;
 518 
 519         case 1:
 520                 DEBUG(9,("nfs_quotas: Good quota data\n"));
 521                 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
 522                 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
 523                 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
 524                 break;
 525 
 526         case 2:
 527         case 3:
 528                 D.dqb_bsoftlimit = 1;
 529                 D.dqb_curblocks = 1;
 530                 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
 531                 break;
 532 
 533         default:
 534                 DEBUG(9,("nfs_quotas: Remote Quotas Questionable!  Error \"%i\" \n", gqr.status ));
 535                 break;
 536         }
 537 
 538         DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
 539                         gqr.status,
 540                         gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
 541                         gqr.getquota_rslt_u.gqr_rquota.rq_active,
 542                         gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
 543                         gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
 544                         gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
 545 
 546         *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
 547         *dsize = D.dqb_bsoftlimit;
 548 
 549         if (D.dqb_curblocks == 1)
 550                 *bsize = 512;
 551 
 552         if (D.dqb_curblocks > D.dqb_bsoftlimit) {
 553                 *dfree = 0;
 554                 *dsize = D.dqb_curblocks;
 555         } else
 556                 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
 557 
 558   out:
 559 
 560         if (clnt) {
 561                 if (clnt->cl_auth)
 562                         auth_destroy(clnt->cl_auth);
 563                 clnt_destroy(clnt);
 564         }
 565 
 566         DEBUG(5,("nfs_quotas: For path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
 567 
 568         SAFE_FREE(cutstr);
 569         DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
 570         return ret;
 571 }
 572 #endif
 573 
 574 /****************************************************************************
 575 try to get the disk space from disk quotas (SunOS & Solaris2 version)
 576 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
 577 ****************************************************************************/
 578 
 579 bool disk_quotas(const char *path,
     /* [<][>][^][v][top][bottom][index][help] */
 580                 uint64_t *bsize,
 581                 uint64_t *dfree,
 582                 uint64_t *dsize)
 583 {
 584         uid_t euser_id;
 585         int ret;
 586         struct dqblk D;
 587 #if defined(SUNOS5)
 588         struct quotctl command;
 589         int file;
 590         struct mnttab mnt;
 591 #else /* SunOS4 */
 592         struct mntent *mnt;
 593 #endif
 594         char *name = NULL;
 595         FILE *fd;
 596         SMB_STRUCT_STAT sbuf;
 597         SMB_DEV_T devno;
 598         bool found = false;
 599 
 600         euser_id = geteuid();
 601 
 602         if (sys_stat(path,&sbuf) == -1) {
 603                 return false;
 604         }
 605 
 606         devno = sbuf.st_dev ;
 607         DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
 608                 path, (unsigned int)devno));
 609 #if defined(SUNOS5)
 610         if ((fd = sys_fopen(MNTTAB, "r")) == NULL) {
 611                 return false;
 612         }
 613 
 614         while (getmntent(fd, &mnt) == 0) {
 615                 if (sys_stat(mnt.mnt_mountp, &sbuf) == -1) {
 616                         continue;
 617                 }
 618 
 619                 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
 620                         mnt.mnt_mountp, (unsigned int)devno));
 621 
 622                 /* quotas are only on vxfs, UFS or NFS */
 623                 if ((sbuf.st_dev == devno) && (
 624                         strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
 625                         strcmp( mnt.mnt_fstype, "nfs" ) == 0    ||
 626                         strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
 627                                 found = true;
 628                                 name = talloc_asprintf(talloc_tos(),
 629                                                 "%s/quotas",
 630                                                 mnt.mnt_mountp);
 631                                 break;
 632                 }
 633         }
 634 
 635         fclose(fd);
 636 #else /* SunOS4 */
 637         if ((fd = setmntent(MOUNTED, "r")) == NULL) {
 638                 return false;
 639         }
 640 
 641         while ((mnt = getmntent(fd)) != NULL) {
 642                 if (sys_stat(mnt->mnt_dir,&sbuf) == -1) {
 643                         continue;
 644                 }
 645                 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
 646                                         mnt->mnt_dir,
 647                                         (unsigned int)sbuf.st_dev));
 648                 if (sbuf.st_dev == devno) {
 649                         found = true;
 650                         name = talloc_strdup(talloc_tos(),
 651                                         mnt->mnt_fsname);
 652                         break;
 653                 }
 654         }
 655 
 656         endmntent(fd);
 657 #endif
 658         if (!found) {
 659                 return false;
 660         }
 661 
 662         if (!name) {
 663                 return false;
 664         }
 665         become_root();
 666 
 667 #if defined(SUNOS5)
 668         if (strcmp(mnt.mnt_fstype, "nfs") == 0) {
 669                 bool retval;
 670                 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n",
 671                                         mnt.mnt_special));
 672                 retval = nfs_quotas(mnt.mnt_special,
 673                                 euser_id, bsize, dfree, dsize);
 674                 unbecome_root();
 675                 return retval;
 676         }
 677 
 678         DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
 679         if((file=sys_open(name, O_RDONLY,0))<0) {
 680                 unbecome_root();
 681                 return false;
 682         }
 683         command.op = Q_GETQUOTA;
 684         command.uid = euser_id;
 685         command.addr = (caddr_t) &D;
 686         ret = ioctl(file, Q_QUOTACTL, &command);
 687         close(file);
 688 #else
 689         DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
 690         ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
 691 #endif
 692 
 693         unbecome_root();
 694 
 695         if (ret < 0) {
 696                 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n",
 697                                         strerror(errno) ));
 698 
 699 #if defined(SUNOS5) && defined(VXFS_QUOTA)
 700                 /* If normal quotactl() fails, try vxfs private calls */
 701                 set_effective_uid(euser_id);
 702                 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
 703                 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
 704                         bool retval;
 705                         retval = disk_quotas_vxfs(name, path,
 706                                         bsize, dfree, dsize);
 707                         return retval;
 708                 }
 709 #else
 710                 return false;
 711 #endif
 712         }
 713 
 714         /* If softlimit is zero, set it equal to hardlimit.
 715          */
 716 
 717         if (D.dqb_bsoftlimit==0) {
 718                 D.dqb_bsoftlimit = D.dqb_bhardlimit;
 719         }
 720 
 721         /* Use softlimit to determine disk space. A user exceeding the quota
 722          * is told that there's no space left. Writes might actually work for
 723          * a bit if the hardlimit is set higher than softlimit. Effectively
 724          * the disk becomes made of rubber latex and begins to expand to
 725          * accommodate the user :-)
 726          */
 727 
 728         if (D.dqb_bsoftlimit==0)
 729                 return(False);
 730         *bsize = DEV_BSIZE;
 731         *dsize = D.dqb_bsoftlimit;
 732 
 733         if (D.dqb_curblocks > D.dqb_bsoftlimit) {
 734                 *dfree = 0;
 735                 *dsize = D.dqb_curblocks;
 736         } else {
 737                 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
 738         }
 739 
 740         DEBUG(5,("disk_quotas for path \"%s\" returning "
 741                 "bsize %.0f, dfree %.0f, dsize %.0f\n",
 742                 path,(double)*bsize,(double)*dfree,(double)*dsize));
 743 
 744         return true;
 745 }
 746 
 747 
 748 #elif defined(OSF1)
 749 #include <ufs/quota.h>
 750 
 751 /****************************************************************************
 752 try to get the disk space from disk quotas - OSF1 version
 753 ****************************************************************************/
 754 
 755 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
     /* [<][>][^][v][top][bottom][index][help] */
 756 {
 757   int r, save_errno;
 758   struct dqblk D;
 759   SMB_STRUCT_STAT S;
 760   uid_t euser_id;
 761 
 762   /*
 763    * This code presumes that OSF1 will only
 764    * give out quota info when the real uid 
 765    * matches the effective uid. JRA.
 766    */
 767   euser_id = geteuid();
 768   save_re_uid();
 769   if (set_re_uid() != 0) return False;
 770 
 771   r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
 772   if (r) {
 773      save_errno = errno;
 774   }
 775 
 776   restore_re_uid();
 777 
 778   *bsize = DEV_BSIZE;
 779 
 780   if (r)
 781   {
 782       if (save_errno == EDQUOT)   /* disk quota exceeded */
 783       {
 784          *dfree = 0;
 785          *dsize = D.dqb_curblocks;
 786          return (True);
 787       }
 788       else
 789          return (False);  
 790   }
 791 
 792   /* If softlimit is zero, set it equal to hardlimit.
 793    */
 794 
 795   if (D.dqb_bsoftlimit==0)
 796     D.dqb_bsoftlimit = D.dqb_bhardlimit;
 797 
 798   /* Use softlimit to determine disk space, except when it has been exceeded */
 799 
 800   if (D.dqb_bsoftlimit==0)
 801     return(False);
 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     *dsize = D.dqb_bsoftlimit;
 809   }
 810   return (True);
 811 }
 812 
 813 #elif defined (IRIX6)
 814 /****************************************************************************
 815 try to get the disk space from disk quotas (IRIX 6.2 version)
 816 ****************************************************************************/
 817 
 818 #include <sys/quota.h>
 819 #include <mntent.h>
 820 
 821 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
     /* [<][>][^][v][top][bottom][index][help] */
 822 {
 823   uid_t euser_id;
 824   int r;
 825   struct dqblk D;
 826   struct fs_disk_quota        F;
 827   SMB_STRUCT_STAT S;
 828   FILE *fp;
 829   struct mntent *mnt;
 830   SMB_DEV_T devno;
 831   int found;
 832   
 833   /* find the block device file */
 834   
 835   if ( sys_stat(path, &S) == -1 ) {
 836     return(False) ;
 837   }
 838 
 839   devno = S.st_dev ;
 840   
 841   fp = setmntent(MOUNTED,"r");
 842   found = False ;
 843   
 844   while ((mnt = getmntent(fp))) {
 845     if ( sys_stat(mnt->mnt_dir,&S) == -1 )
 846       continue ;
 847     if (S.st_dev == devno) {
 848       found = True ;
 849       break ;
 850     }
 851   }
 852   endmntent(fp) ;
 853   
 854   if (!found) {
 855     return(False);
 856   }
 857 
 858   euser_id=geteuid();
 859   become_root();
 860 
 861   /* Use softlimit to determine disk space, except when it has been exceeded */
 862 
 863   *bsize = 512;
 864 
 865   if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
 866   {
 867     r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
 868 
 869     unbecome_root();
 870 
 871     if (r==-1)
 872       return(False);
 873         
 874     /* Use softlimit to determine disk space, except when it has been exceeded */
 875     if (
 876         (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
 877         (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
 878         (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
 879         (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
 880        )
 881     {
 882       *dfree = 0;
 883       *dsize = D.dqb_curblocks;
 884     }
 885     else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
 886     {
 887       return(False);
 888     }
 889     else 
 890     {
 891       *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
 892       *dsize = D.dqb_bsoftlimit;
 893     }
 894 
 895   }
 896   else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
 897   {
 898     r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
 899 
 900     unbecome_root();
 901 
 902     if (r==-1)
 903     {
 904       DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
 905       return(False);
 906     }
 907         
 908     /* No quota for this user. */
 909     if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
 910     {
 911       return(False);
 912     }
 913 
 914     /* Use softlimit to determine disk space, except when it has been exceeded */
 915     if (
 916         (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
 917         (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
 918         (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
 919         (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
 920        )
 921     {
 922       *dfree = 0;
 923       *dsize = F.d_bcount;
 924     }
 925     else 
 926     {
 927       *dfree = (F.d_blk_softlimit - F.d_bcount);
 928       *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
 929     }
 930 
 931   }
 932   else
 933   {
 934           unbecome_root();
 935           return(False);
 936   }
 937 
 938   return (True);
 939 
 940 }
 941 
 942 #else
 943 
 944 #if    defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
 945 #include <ufs/ufs/quota.h>
 946 #include <machine/param.h>
 947 #elif         AIX
 948 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
 949 #include <jfs/quota.h>
 950 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
 951 #define dqb_curfiles dqb_curinodes
 952 #define dqb_fhardlimit dqb_ihardlimit
 953 #define dqb_fsoftlimit dqb_isoftlimit
 954 #ifdef _AIXVERSION_530 
 955 #include <sys/statfs.h>
 956 #include <sys/vmount.h>
 957 #endif /* AIX 5.3 */
 958 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
 959 #include <sys/quota.h>
 960 #include <devnm.h>
 961 #endif
 962 
 963 #if defined(__FreeBSD__) || defined(__DragonFly__)
 964 
 965 #include <rpc/rpc.h>
 966 #include <rpc/types.h>
 967 #include <rpcsvc/rquota.h>
 968 #ifdef HAVE_RPC_NETTYPE_H
 969 #include <rpc/nettype.h>
 970 #endif
 971 #include <rpc/xdr.h>
 972 
 973 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
     /* [<][>][^][v][top][bottom][index][help] */
 974 {
 975         if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
 976                 return(0);
 977         if (!xdr_int(xdrsp, &args->gqa_uid))
 978                 return(0);
 979         return (1);
 980 }
 981 
 982 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
     /* [<][>][^][v][top][bottom][index][help] */
 983 {
 984         int quotastat;
 985 
 986         if (!xdr_int(xdrsp, &quotastat)) {
 987                 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
 988                 return 0;
 989         }
 990         gqr->status = quotastat;
 991 
 992         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
 993                 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
 994                 return 0;
 995         }
 996         if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
 997                 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
 998                 return 0;
 999         }
1000         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
1001                 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
1002                 return 0;
1003         }
1004         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
1005                 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
1006                 return 0;
1007         }
1008         if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
1009                 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
1010                 return 0;
1011         }
1012         return (1);
1013 }
1014 
1015 /* Works on FreeBSD, too. :-) */
1016 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
     /* [<][>][^][v][top][bottom][index][help] */
1017 {
1018         uid_t uid = euser_id;
1019         struct dqblk D;
1020         char *mnttype = nfspath;
1021         CLIENT *clnt;
1022         struct getquota_rslt gqr;
1023         struct getquota_args args;
1024         char *cutstr, *pathname, *host, *testpath;
1025         int len;
1026         static struct timeval timeout = {2,0};
1027         enum clnt_stat clnt_stat;
1028         bool ret = True;
1029 
1030         *bsize = *dfree = *dsize = (uint64_t)0;
1031 
1032         len=strcspn(mnttype, ":");
1033         pathname=strstr(mnttype, ":");
1034         cutstr = (char *) SMB_MALLOC(len+1);
1035         if (!cutstr)
1036                 return False;
1037 
1038         memset(cutstr, '\0', len+1);
1039         host = strncat(cutstr,mnttype, sizeof(char) * len );
1040         DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1041         DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1042         testpath=strchr_m(mnttype, ':');
1043         args.gqa_pathp = testpath+1;
1044         args.gqa_uid = uid;
1045 
1046         DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1047 
1048         if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1049                 ret = False;
1050                 goto out;
1051         }
1052 
1053         clnt->cl_auth = authunix_create_default();
1054         DEBUG(9,("nfs_quotas: auth_success\n"));
1055 
1056         clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, (const xdrproc_t) my_xdr_getquota_args, (caddr_t)&args, (const xdrproc_t) my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
1057 
1058         if (clnt_stat != RPC_SUCCESS) {
1059                 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1060                 ret = False;
1061                 goto out;
1062         }
1063 
1064         /* 
1065          * gqr->status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1066          * no quota set, and 3 if no permission to get the quota.  If 0 or 3 return
1067          * something sensible.
1068          */   
1069 
1070         switch (gqr.status) {
1071         case 0:
1072                 DEBUG(9,("nfs_quotas: Remote Quotas Failed!  Error \"%i\" \n", gqr.status));
1073                 ret = False;
1074                 goto out;
1075 
1076         case 1:
1077                 DEBUG(9,("nfs_quotas: Good quota data\n"));
1078                 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1079                 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1080                 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1081                 break;
1082 
1083         case 2:
1084         case 3:
1085                 D.dqb_bsoftlimit = 1;
1086                 D.dqb_curblocks = 1;
1087                 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
1088                 break;
1089 
1090         default:
1091                 DEBUG(9,("nfs_quotas: Remote Quotas Questionable!  Error \"%i\" \n", gqr.status));
1092                 break;
1093         }
1094 
1095         DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
1096                         gqr.status,
1097                         gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1098                         gqr.getquota_rslt_u.gqr_rquota.rq_active,
1099                         gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1100                         gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1101                         gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1102 
1103         if (D.dqb_bsoftlimit == 0)
1104                 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1105         if (D.dqb_bsoftlimit == 0)
1106                 return False;
1107 
1108         *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1109         *dsize = D.dqb_bsoftlimit;
1110 
1111         if (D.dqb_curblocks == 1)
1112                 *bsize = DEV_BSIZE;
1113 
1114         if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1115                 *dfree = 0;
1116                 *dsize = D.dqb_curblocks;
1117         } else
1118                 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1119 
1120   out:
1121 
1122         if (clnt) {
1123                 if (clnt->cl_auth)
1124                         auth_destroy(clnt->cl_auth);
1125                 clnt_destroy(clnt);
1126         }
1127 
1128         DEBUG(5,("nfs_quotas: For path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1129 
1130         SAFE_FREE(cutstr);
1131         DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1132         return ret;
1133 }
1134 
1135 #endif
1136 
1137 /****************************************************************************
1138 try to get the disk space from disk quotas - default version
1139 ****************************************************************************/
1140 
1141 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
     /* [<][>][^][v][top][bottom][index][help] */
1142 {
1143   int r;
1144   struct dqblk D;
1145   uid_t euser_id;
1146 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1147   char dev_disk[256];
1148   SMB_STRUCT_STAT S;
1149 
1150   /* find the block device file */
1151 
1152 #ifdef HPUX
1153   /* Need to set the cache flag to 1 for HPUX. Seems
1154    * to have a significant performance boost when
1155    * lstat calls on /dev access this function.
1156    */
1157   if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0))
1158 #else
1159   if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) 
1160         return (False);
1161 #endif /* ifdef HPUX */
1162 
1163 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1164 
1165   euser_id = geteuid();
1166 
1167 #ifdef HPUX
1168   /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1169   save_re_uid();
1170   if (set_re_uid() != 0) return False;
1171   
1172   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1173 
1174   restore_re_uid();
1175 #else 
1176 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1177   {
1178     /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1179     gid_t egrp_id;
1180 #if defined(__FreeBSD__) || defined(__DragonFly__)
1181     SMB_DEV_T devno;
1182     struct statfs *mnts;
1183     SMB_STRUCT_STAT st;
1184     int mntsize, i;
1185     
1186     if (sys_stat(path,&st) < 0)
1187         return False;
1188     devno = st.st_dev;
1189 
1190     mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1191     if (mntsize <= 0)
1192         return False;
1193 
1194     for (i = 0; i < mntsize; i++) {
1195         if (sys_stat(mnts[i].f_mntonname,&st) < 0)
1196             return False;
1197         if (st.st_dev == devno)
1198             break;
1199     }
1200     if (i == mntsize)
1201         return False;
1202 #endif
1203     
1204     become_root();
1205 
1206 #if defined(__FreeBSD__) || defined(__DragonFly__)
1207     if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1208         bool retval;
1209         retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1210         unbecome_root();
1211         return retval;
1212     }
1213 #endif
1214 
1215     egrp_id = getegid();
1216     r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1217 
1218     /* As FreeBSD has group quotas, if getting the user
1219        quota fails, try getting the group instead. */
1220     if (r) {
1221             r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1222     }
1223 
1224     unbecome_root();
1225   }
1226 #elif defined(AIX)
1227   /* AIX has both USER and GROUP quotas: 
1228      Get the USER quota (ohnielse@fysik.dtu.dk) */
1229 #ifdef _AIXVERSION_530
1230   {
1231     struct statfs statbuf;
1232     quota64_t user_quota;
1233     if (statfs(path,&statbuf) != 0)
1234       return False;
1235     if(statbuf.f_vfstype == MNT_J2)
1236     {
1237     /* For some reason we need to be root for jfs2 */
1238       become_root();
1239       r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
1240       unbecome_root();
1241     /* Copy results to old struct to let the following code work as before */
1242       D.dqb_curblocks  = user_quota.bused;
1243       D.dqb_bsoftlimit = user_quota.bsoft;
1244       D.dqb_bhardlimit = user_quota.bhard;
1245       D.dqb_curfiles   = user_quota.iused;
1246       D.dqb_fsoftlimit = user_quota.isoft;
1247       D.dqb_fhardlimit = user_quota.ihard;
1248     }
1249     else if(statbuf.f_vfstype == MNT_JFS)
1250     {
1251 #endif /* AIX 5.3 */
1252   save_re_uid();
1253   if (set_re_uid() != 0) 
1254     return False;
1255   r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1256   restore_re_uid();
1257 #ifdef _AIXVERSION_530
1258     }
1259     else
1260       r = 1; /* Fail for other FS-types */
1261   }
1262 #endif /* AIX 5.3 */
1263 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1264   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1265 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1266 #endif /* HPUX */
1267 
1268   /* Use softlimit to determine disk space, except when it has been exceeded */
1269 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1270   *bsize = DEV_BSIZE;
1271 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1272   *bsize = 1024;
1273 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1274 
1275   if (r)
1276     {
1277       if (errno == EDQUOT) 
1278         {
1279           *dfree =0;
1280           *dsize =D.dqb_curblocks;
1281           return (True);
1282         }
1283       else return(False);
1284     }
1285 
1286   /* If softlimit is zero, set it equal to hardlimit.
1287    */
1288 
1289   if (D.dqb_bsoftlimit==0)
1290     D.dqb_bsoftlimit = D.dqb_bhardlimit;
1291 
1292   if (D.dqb_bsoftlimit==0)
1293     return(False);
1294   /* Use softlimit to determine disk space, except when it has been exceeded */
1295   if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1296 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1297 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1298 #endif
1299     ) {
1300       *dfree = 0;
1301       *dsize = D.dqb_curblocks;
1302     }
1303   else {
1304     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1305     *dsize = D.dqb_bsoftlimit;
1306   }
1307   return (True);
1308 }
1309 
1310 #endif
1311 
1312 #if defined(VXFS_QUOTA)
1313 
1314 /****************************************************************************
1315 Try to get the disk space from Veritas disk quotas.
1316     David Lee <T.D.Lee@durham.ac.uk> August 1999.
1317 
1318 Background assumptions:
1319     Potentially under many Operating Systems.  Initially Solaris 2.
1320 
1321     My guess is that Veritas is largely, though not entirely,
1322     independent of OS.  So I have separated it out.
1323 
1324     There may be some details.  For example, OS-specific "include" files.
1325 
1326     It is understood that HPUX 10 somehow gets Veritas quotas without
1327     any special effort; if so, this routine need not be compiled in.
1328         Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1329 
1330 Warning:
1331     It is understood that Veritas do not publicly support this ioctl interface.
1332     Rather their preference would be for the user (us) to call the native
1333     OS and then for the OS itself to call through to the VxFS filesystem.
1334     Presumably HPUX 10, see above, does this.
1335 
1336 Hints for porting:
1337     Add your OS to "IFLIST" below.
1338     Get it to compile successfully:
1339         Almost certainly "include"s require attention: see SUNOS5.
1340     In the main code above, arrange for it to be called: see SUNOS5.
1341     Test!
1342     
1343 ****************************************************************************/
1344 
1345 /* "IFLIST"
1346  * This "if" is a list of ports:
1347  *      if defined(OS1) || defined(OS2) || ...
1348  */
1349 #if defined(SUNOS5)
1350 
1351 #if defined(SUNOS5)
1352 #include <sys/fs/vx_solaris.h>
1353 #endif
1354 #include <sys/fs/vx_machdep.h>
1355 #include <sys/fs/vx_layout.h>
1356 #include <sys/fs/vx_quota.h>
1357 #include <sys/fs/vx_aioctl.h>
1358 #include <sys/fs/vx_ioctl.h>
1359 
1360 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
     /* [<][>][^][v][top][bottom][index][help] */
1361 {
1362   uid_t user_id, euser_id;
1363   int ret;
1364   struct vx_dqblk D;
1365   struct vx_quotctl quotabuf;
1366   struct vx_genioctl genbuf;
1367   char *qfname;
1368   int file;
1369 
1370   /*
1371    * "name" may or may not include a trailing "/quotas".
1372    * Arranging consistency of calling here in "quotas.c" may not be easy and
1373    * it might be easier to examine and adjust it here.
1374    * Fortunately, VxFS seems not to mind at present.
1375    */
1376   qfname = talloc_strdup(talloc_tos(), name);
1377   if (!qfname) {
1378           return false;
1379   }
1380   /* pstrcat(qfname, "/quotas") ; */    /* possibly examine and adjust "name" */
1381 
1382   euser_id = geteuid();
1383   set_effective_uid(0);
1384 
1385   DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1386   if((file=sys_open(qfname, O_RDONLY,0))<0) {
1387     set_effective_uid(euser_id);
1388     return(False);
1389   }
1390   genbuf.ioc_cmd = VX_QUOTACTL;
1391   genbuf.ioc_up = (void *) &quotabuf;
1392 
1393   quotabuf.cmd = VX_GETQUOTA;
1394   quotabuf.uid = euser_id;
1395   quotabuf.addr = (caddr_t) &D;
1396   ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1397   close(file);
1398 
1399   set_effective_uid(euser_id);
1400 
1401   if (ret < 0) {
1402     DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1403     return(False);
1404   }
1405 
1406   /* If softlimit is zero, set it equal to hardlimit.
1407    */
1408 
1409   if (D.dqb_bsoftlimit==0)
1410     D.dqb_bsoftlimit = D.dqb_bhardlimit;
1411 
1412   /* Use softlimit to determine disk space. A user exceeding the quota is told
1413    * that there's no space left. Writes might actually work for a bit if the
1414    * hardlimit is set higher than softlimit. Effectively the disk becomes
1415    * made of rubber latex and begins to expand to accommodate the user :-)
1416    */
1417   DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1418          path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1419          D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1420 
1421   if (D.dqb_bsoftlimit==0)
1422     return(False);
1423   *bsize = DEV_BSIZE;
1424   *dsize = D.dqb_bsoftlimit;
1425 
1426   if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1427      *dfree = 0;
1428      *dsize = D.dqb_curblocks;
1429   } else
1430     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1431       
1432   DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",
1433          path,(double)*bsize,(double)*dfree,(double)*dsize));
1434 
1435   return(True);
1436 }
1437 
1438 #endif /* SUNOS5 || ... */
1439 
1440 #endif /* VXFS_QUOTA */
1441 
1442 #else /* WITH_QUOTAS */
1443 
1444 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
     /* [<][>][^][v][top][bottom][index][help] */
1445 {
1446         (*bsize) = 512; /* This value should be ignored */
1447 
1448         /* And just to be sure we set some values that hopefully */
1449         /* will be larger that any possible real-world value     */
1450         (*dfree) = (uint64_t)-1;
1451         (*dsize) = (uint64_t)-1;
1452 
1453         /* As we have select not to use quotas, allways fail */
1454         return false;
1455 }
1456 #endif /* WITH_QUOTAS */
1457 
1458 #else /* HAVE_SYS_QUOTAS */
1459 /* wrapper to the new sys_quota interface
1460    this file should be removed later
1461    */
1462 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
     /* [<][>][^][v][top][bottom][index][help] */
1463 {
1464         int r;
1465         SMB_DISK_QUOTA D;
1466         unid_t id;
1467 
1468         id.uid = geteuid();
1469 
1470         ZERO_STRUCT(D);
1471         r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1472 
1473         /* Use softlimit to determine disk space, except when it has been exceeded */
1474         *bsize = D.bsize;
1475         if (r == -1) {
1476                 if (errno == EDQUOT) {
1477                         *dfree =0;
1478                         *dsize =D.curblocks;
1479                         return (True);
1480                 } else {
1481                         goto try_group_quota;
1482                 }
1483         }
1484 
1485         /* Use softlimit to determine disk space, except when it has been exceeded */
1486         if (
1487                 (D.softlimit && D.curblocks >= D.softlimit) ||
1488                 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1489                 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1490                 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1491         ) {
1492                 *dfree = 0;
1493                 *dsize = D.curblocks;
1494         } else if (D.softlimit==0 && D.hardlimit==0) {
1495                 goto try_group_quota;
1496         } else {
1497                 if (D.softlimit == 0)
1498                         D.softlimit = D.hardlimit;
1499                 *dfree = D.softlimit - D.curblocks;
1500                 *dsize = D.softlimit;
1501         }
1502 
1503         return True;
1504         
1505 try_group_quota:
1506         id.gid = getegid();
1507 
1508         ZERO_STRUCT(D);
1509         r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1510 
1511         /* Use softlimit to determine disk space, except when it has been exceeded */
1512         *bsize = D.bsize;
1513         if (r == -1) {
1514                 if (errno == EDQUOT) {
1515                         *dfree =0;
1516                         *dsize =D.curblocks;
1517                         return (True);
1518                 } else {
1519                         return False;
1520                 }
1521         }
1522 
1523         /* Use softlimit to determine disk space, except when it has been exceeded */
1524         if (
1525                 (D.softlimit && D.curblocks >= D.softlimit) ||
1526                 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1527                 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1528                 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1529         ) {
1530                 *dfree = 0;
1531                 *dsize = D.curblocks;
1532         } else if (D.softlimit==0 && D.hardlimit==0) {
1533                 return False;
1534         } else {
1535                 if (D.softlimit == 0)
1536                         D.softlimit = D.hardlimit;
1537                 *dfree = D.softlimit - D.curblocks;
1538                 *dsize = D.softlimit;
1539         }
1540 
1541         return (True);
1542 }
1543 #endif /* HAVE_SYS_QUOTAS */

/* [<][>][^][v][top][bottom][index][help] */