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