1/* 2 * $Id: quota.c,v 1.35 2010-04-03 07:11:35 franklahm Exp $ 3 * 4 * Copyright (c) 1990,1993 Regents of The University of Michigan. 5 * All Rights Reserved. See COPYRIGHT. 6 */ 7 8#ifdef HAVE_CONFIG_H 9#include "config.h" 10#endif /* HAVE_CONFIG_H */ 11 12#ifndef NO_QUOTA_SUPPORT 13#include <stdio.h> 14#include <stdlib.h> 15#include <string.h> 16#include <errno.h> 17#include <sys/types.h> 18/* STDC check */ 19#if STDC_HEADERS 20#include <string.h> 21#else /* STDC_HEADERS */ 22#ifndef HAVE_STRCHR 23#define strchr index 24#define strrchr index 25#endif /* HAVE_STRCHR */ 26char *strchr (), *strrchr (); 27#ifndef HAVE_MEMCPY 28#define memcpy(d,s,n) bcopy ((s), (d), (n)) 29#define memmove(d,s,n) bcopy ((s), (d), (n)) 30#endif /* ! HAVE_MEMCPY */ 31#endif /* STDC_HEADERS */ 32#include <sys/stat.h> 33#include <sys/time.h> 34#include <sys/param.h> 35#ifdef HAVE_UNISTD_H 36#include <unistd.h> 37#endif /* HAVE_UNISTD_H */ 38#ifdef HAVE_FCNTL_H 39#include <fcntl.h> 40#endif /* HAVE_FCNTL_H */ 41 42#include <atalk/logger.h> 43#include <atalk/afp.h> 44#include <atalk/compat.h> 45 46#include "auth.h" 47#include "volume.h" 48#include "unix.h" 49 50/* 51#define DEBUG_QUOTA 0 52*/ 53 54#define WANT_USER_QUOTA 0 55#define WANT_GROUP_QUOTA 1 56 57#ifdef NEED_QUOTACTL_WRAPPER 58int quotactl(int cmd, const char *special, int id, caddr_t addr) 59{ 60 return syscall(__NR_quotactl, cmd, special, id, addr); 61} 62#endif /* NEED_QUOTACTL_WRAPPER */ 63 64static int overquota( struct dqblk *); 65 66#ifdef linux 67 68#ifdef HAVE_LINUX_XQM_H 69#include <linux/xqm.h> 70#else 71#ifdef HAVE_XFS_XQM_H 72#include <xfs/xqm.h> 73#define HAVE_LINUX_XQM_H 74#else 75#ifdef HAVE_LINUX_DQBLK_XFS_H 76#include <linux/dqblk_xfs.h> 77#define HAVE_LINUX_XQM_H 78#endif /* HAVE_LINUX_DQBLK_XFS_H */ 79#endif /* HAVE_XFS_XQM_H */ 80#endif /* HAVE_LINUX_XQM_H */ 81 82#include <linux/unistd.h> 83 84static int is_xfs = 0; 85 86static int get_linux_xfs_quota(int, char*, uid_t, struct dqblk *); 87static int get_linux_fs_quota(int, char*, uid_t, struct dqblk *); 88 89/* format supported by current kernel */ 90static int kernel_iface = IFACE_UNSET; 91 92/* 93** Check kernel quota version 94** Taken from quota-tools 3.08 by Jan Kara <jack@suse.cz> 95*/ 96static void linuxquota_get_api( void ) 97{ 98#ifndef LINUX_API_VERSION 99 struct stat st; 100 101 if (stat("/proc/sys/fs/quota", &st) == 0) { 102 kernel_iface = IFACE_GENERIC; 103 } 104 else { 105 struct dqstats_v2 v2_stats; 106 struct sigaction sig; 107 struct sigaction oldsig; 108 109 /* This signal handling is needed because old kernels send us SIGSEGV as they try to resolve the device */ 110 sig.sa_handler = SIG_IGN; 111 sig.sa_sigaction = NULL; 112 sig.sa_flags = 0; 113 sigemptyset(&sig.sa_mask); 114 if (sigaction(SIGSEGV, &sig, &oldsig) < 0) { 115 LOG( log_error, logtype_afpd, "cannot set SEGV signal handler: %s", strerror(errno)); 116 goto failure; 117 } 118 if (quotactl(QCMD(Q_V2_GETSTATS, 0), NULL, 0, (void *)&v2_stats) >= 0) { 119 kernel_iface = IFACE_VFSV0; 120 } 121 else if (errno != ENOSYS && errno != ENOTSUP) { 122 /* RedHat 7.1 (2.4.2-2) newquota check 123 * Q_V2_GETSTATS in it's old place, Q_GETQUOTA in the new place 124 * (they haven't moved Q_GETSTATS to its new value) */ 125 int err_stat = 0; 126 int err_quota = 0; 127 char tmp[1024]; /* Just temporary buffer */ 128 129 if (quotactl(QCMD(Q_V1_GETSTATS, 0), NULL, 0, tmp)) 130 err_stat = errno; 131 if (quotactl(QCMD(Q_V1_GETQUOTA, 0), "/dev/null", 0, tmp)) 132 err_quota = errno; 133 134 /* On a RedHat 2.4.2-2 we expect 0, EINVAL 135 * On a 2.4.x we expect 0, ENOENT 136 * On a 2.4.x-ac we wont get here */ 137 if (err_stat == 0 && err_quota == EINVAL) { 138 kernel_iface = IFACE_VFSV0; 139 } 140 else { 141 kernel_iface = IFACE_VFSOLD; 142 } 143 } 144 else { 145 /* This branch is *not* in quota-tools 3.08 146 ** but without it quota version is not correctly 147 ** identified for the original SuSE 8.0 kernel */ 148 unsigned int vers_no; 149 FILE * qf; 150 151 if ((qf = fopen("/proc/fs/quota", "r"))) { 152 if (fscanf(qf, "Version %u", &vers_no) == 1) { 153 if ( (vers_no == (6*10000 + 5*100 + 0)) || 154 (vers_no == (6*10000 + 5*100 + 1)) ) { 155 kernel_iface = IFACE_VFSV0; 156 } 157 } 158 fclose(qf); 159 } 160 } 161 if (sigaction(SIGSEGV, &oldsig, NULL) < 0) { 162 LOG(log_error, logtype_afpd, "cannot reset signal handler: %s", strerror(errno)); 163 goto failure; 164 } 165 } 166 167failure: 168 if (kernel_iface == IFACE_UNSET) 169 kernel_iface = IFACE_VFSOLD; 170 171#else /* defined LINUX_API_VERSION */ 172 kernel_iface = LINUX_API_VERSION; 173#endif 174} 175 176/****************************************************************************/ 177 178static int get_linux_quota(int what, char *path, uid_t euser_id, struct dqblk *dp) 179{ 180 int r; /* result */ 181 182 if ( is_xfs ) 183 r=get_linux_xfs_quota(what, path, euser_id, dp); 184 else 185 r=get_linux_fs_quota(what, path, euser_id, dp); 186 187 return r; 188} 189 190/**************************************************************************** 191 Abstract out the XFS Quota Manager quota get call. 192****************************************************************************/ 193 194static int get_linux_xfs_quota(int what, char *path, uid_t euser_id, struct dqblk *dqb) 195{ 196 int ret = -1; 197#ifdef HAVE_LINUX_XQM_H 198 struct fs_disk_quota D; 199 200 memset (&D, 0, sizeof(D)); 201 202 if ((ret = quotactl(QCMD(Q_XGETQUOTA,(what ? GRPQUOTA : USRQUOTA)), path, euser_id, (caddr_t)&D))) 203 return ret; 204 205 dqb->bsize = (u_int64_t)512; 206 dqb->dqb_bsoftlimit = (u_int64_t)D.d_blk_softlimit; 207 dqb->dqb_bhardlimit = (u_int64_t)D.d_blk_hardlimit; 208 dqb->dqb_ihardlimit = (u_int64_t)D.d_ino_hardlimit; 209 dqb->dqb_isoftlimit = (u_int64_t)D.d_ino_softlimit; 210 dqb->dqb_curinodes = (u_int64_t)D.d_icount; 211 dqb->dqb_curblocks = (u_int64_t)D.d_bcount; 212#endif 213 return ret; 214} 215 216/* 217** Wrapper for the quotactl(GETQUOTA) call. 218** For API v2 the results are copied back into a v1 structure. 219** Taken from quota-1.4.8 perl module 220*/ 221static int get_linux_fs_quota(int what, char *path, uid_t euser_id, struct dqblk *dqb) 222{ 223 int ret; 224 225 if (kernel_iface == IFACE_UNSET) 226 linuxquota_get_api(); 227 228 if (kernel_iface == IFACE_GENERIC) 229 { 230 struct dqblk_v3 dqb3; 231 232 ret = quotactl(QCMD(Q_V3_GETQUOTA, (what ? GRPQUOTA : USRQUOTA)), path, euser_id, (caddr_t) &dqb3); 233 if (ret == 0) 234 { 235 dqb->dqb_bhardlimit = dqb3.dqb_bhardlimit; 236 dqb->dqb_bsoftlimit = dqb3.dqb_bsoftlimit; 237 dqb->dqb_curblocks = dqb3.dqb_curspace / DEV_QBSIZE; 238 dqb->dqb_ihardlimit = dqb3.dqb_ihardlimit; 239 dqb->dqb_isoftlimit = dqb3.dqb_isoftlimit; 240 dqb->dqb_curinodes = dqb3.dqb_curinodes; 241 dqb->dqb_btime = dqb3.dqb_btime; 242 dqb->dqb_itime = dqb3.dqb_itime; 243 dqb->bsize = DEV_QBSIZE; 244 } 245 } 246 else if (kernel_iface == IFACE_VFSV0) 247 { 248 struct dqblk_v2 dqb2; 249 250 ret = quotactl(QCMD(Q_V2_GETQUOTA, (what ? GRPQUOTA : USRQUOTA)), path, euser_id, (caddr_t) &dqb2); 251 if (ret == 0) 252 { 253 dqb->dqb_bhardlimit = dqb2.dqb_bhardlimit; 254 dqb->dqb_bsoftlimit = dqb2.dqb_bsoftlimit; 255 dqb->dqb_curblocks = dqb2.dqb_curspace / DEV_QBSIZE; 256 dqb->dqb_ihardlimit = dqb2.dqb_ihardlimit; 257 dqb->dqb_isoftlimit = dqb2.dqb_isoftlimit; 258 dqb->dqb_curinodes = dqb2.dqb_curinodes; 259 dqb->dqb_btime = dqb2.dqb_btime; 260 dqb->dqb_itime = dqb2.dqb_itime; 261 dqb->bsize = DEV_QBSIZE; 262 } 263 } 264 else /* if (kernel_iface == IFACE_VFSOLD) */ 265 { 266 struct dqblk_v1 dqb1; 267 268 ret = quotactl(QCMD(Q_V1_GETQUOTA, (what ? GRPQUOTA : USRQUOTA)), path, euser_id, (caddr_t) &dqb1); 269 if (ret == 0) 270 { 271 dqb->dqb_bhardlimit = dqb1.dqb_bhardlimit; 272 dqb->dqb_bsoftlimit = dqb1.dqb_bsoftlimit; 273 dqb->dqb_curblocks = dqb1.dqb_curblocks; 274 dqb->dqb_ihardlimit = dqb1.dqb_ihardlimit; 275 dqb->dqb_isoftlimit = dqb1.dqb_isoftlimit; 276 dqb->dqb_curinodes = dqb1.dqb_curinodes; 277 dqb->dqb_btime = dqb1.dqb_btime; 278 dqb->dqb_itime = dqb1.dqb_itime; 279 dqb->bsize = DEV_QBSIZE; 280 } 281 } 282 return ret; 283} 284 285#endif /* linux */ 286 287#if defined(HAVE_SYS_MNTTAB_H) || defined(__svr4__) 288/* 289 * Return the mount point associated with the filesystem 290 * on which "file" resides. Returns NULL on failure. 291 */ 292static char * 293mountp( char *file, int *nfs) 294{ 295 struct stat sb; 296 FILE *mtab; 297 dev_t devno; 298 static struct mnttab mnt; 299 300 if ( lstat( file, &sb ) < 0 ) { 301 return( NULL ); 302 } 303 devno = sb.st_dev; 304 305 if (( mtab = fopen( "/etc/mnttab", "r" )) == NULL ) { 306 return( NULL ); 307 } 308 309 while ( getmntent( mtab, &mnt ) == 0 ) { 310 /* local fs */ 311 if ( (lstat( mnt.mnt_special, &sb ) == 0) && (devno == sb.st_rdev)) { 312 fclose( mtab ); 313 return mnt.mnt_mountp; 314 } 315 316 /* check for nfs. we probably should use 317 * strcmp(mnt.mnt_fstype, MNTTYPE_NFS), but that's not as fast. */ 318 if ((lstat(mnt.mnt_mountp, &sb) == 0) && (devno == sb.st_dev) && 319 strchr(mnt.mnt_special, ':')) { 320 *nfs = 1; 321 fclose( mtab ); 322 return mnt.mnt_special; 323 } 324 } 325 326 fclose( mtab ); 327 return( NULL ); 328} 329 330#else /* __svr4__ */ 331#ifdef ultrix 332/* 333* Return the block-special device name associated with the filesystem 334* on which "file" resides. Returns NULL on failure. 335*/ 336 337static char * 338special( char *file, int *nfs) 339{ 340 static struct fs_data fsd; 341 342 if ( getmnt(0, &fsd, 0, STAT_ONE, file ) < 0 ) { 343 LOG(log_info, logtype_afpd, "special: getmnt %s: %s", file, strerror(errno) ); 344 return( NULL ); 345 } 346 347 /* XXX: does this really detect an nfs mounted fs? */ 348 if (strchr(fsd.fd_req.devname, ':')) 349 *nfs = 1; 350 return( fsd.fd_req.devname ); 351} 352 353#else /* ultrix */ 354#if (defined(HAVE_SYS_MOUNT_H) && !defined(__linux__)) || defined(BSD4_4) || defined(_IBMR2) 355 356static char * 357special(char *file, int *nfs) 358{ 359 static struct statfs sfs; 360 361 if ( statfs( file, &sfs ) < 0 ) { 362 return( NULL ); 363 } 364 365#ifdef TRU64 366 /* Digital UNIX: The struct sfs contains a field sfs.f_type, 367 * the MOUNT_* constants are defined in <sys/mount.h> */ 368 if ((sfs.f_type == MOUNT_NFS)||(sfs.f_type == MOUNT_NFS3)) 369#else /* TRU64 */ 370 /* XXX: make sure this really detects an nfs mounted fs */ 371 if (strchr(sfs.f_mntfromname, ':')) 372#endif /* TRU64 */ 373 *nfs = 1; 374 return( sfs.f_mntfromname ); 375} 376 377#else /* BSD4_4 */ 378 379static char * 380special(char *file, int *nfs) 381{ 382 struct stat sb; 383 FILE *mtab; 384 dev_t devno; 385 struct mntent *mnt; 386 int found=0; 387 388 if ( lstat( file, &sb ) < 0 ) { 389 return( NULL ); 390 } 391 devno = sb.st_dev; 392 393 if (( mtab = setmntent( "/etc/mtab", "r" )) == NULL ) { 394 return( NULL ); 395 } 396 397 while (( mnt = getmntent( mtab )) != NULL ) { 398 /* check for local fs */ 399 if ( (lstat( mnt->mnt_fsname, &sb ) == 0) && devno == sb.st_rdev) { 400 found = 1; 401 break; 402 } 403 404 /* check for an nfs mount entry. the alternative is to use 405 * strcmp(mnt->mnt_type, MNTTYPE_NFS) instead of the strchr. */ 406 if ((lstat(mnt->mnt_dir, &sb) == 0) && (devno == sb.st_dev) && 407 strchr(mnt->mnt_fsname, ':')) { 408 *nfs = 1; 409 found = 1; 410 break; 411 } 412 } 413 414 endmntent( mtab ); 415 416 if (!found) 417 return (NULL); 418#ifdef linux 419 if (strcmp(mnt->mnt_type, "xfs") == 0) 420 is_xfs = 1; 421#endif 422 423 return( mnt->mnt_fsname ); 424} 425 426#endif /* BSD4_4 */ 427#endif /* ultrix */ 428#endif /* __svr4__ */ 429 430 431static int getfsquota(struct vol *vol, const int uid, struct dqblk *dq) 432 433{ 434 struct dqblk dqg; 435 436#ifdef __svr4__ 437 struct quotctl qc; 438#endif 439 440 memset(&dqg, 0, sizeof(dqg)); 441 442#ifdef __svr4__ 443 qc.op = Q_GETQUOTA; 444 qc.uid = uid; 445 qc.addr = (caddr_t)dq; 446 if ( ioctl( vol->v_qfd, Q_QUOTACTL, &qc ) < 0 ) { 447 return( AFPERR_PARAM ); 448 } 449 450#else /* __svr4__ */ 451#ifdef ultrix 452 if ( quota( Q_GETDLIM, uid, vol->v_gvs, dq ) != 0 ) { 453 return( AFPERR_PARAM ); 454 } 455#else /* ultrix */ 456 457#ifndef USRQUOTA 458#define USRQUOTA 0 459#endif 460 461#ifndef QCMD 462#define QCMD(a,b) (a) 463#endif 464 465#ifndef TRU64 466 /* for group quotas. we only use these if the user belongs 467 * to one group. */ 468#endif /* TRU64 */ 469 470#ifdef BSD4_4 471 if ( seteuid( getuid() ) == 0 ) { 472 if ( quotactl( vol->v_path, QCMD(Q_GETQUOTA,USRQUOTA), 473 uid, (char *)dq ) != 0 ) { 474 /* try group quotas */ 475 if (ngroups >= 1) { 476 if ( quotactl(vol->v_path, QCMD(Q_GETQUOTA, GRPQUOTA), 477 groups[0], (char *) &dqg) != 0 ) { 478 seteuid( uid ); 479 return( AFPERR_PARAM ); 480 } 481 } 482 } 483 seteuid( uid ); 484 } 485 486#elif defined(TRU64) 487 if ( seteuid( getuid() ) == 0 ) { 488 if ( quotactl( vol->v_path, QCMD(Q_GETQUOTA, USRQUOTA), 489 uid, (char *)dq ) != 0 ) { 490 seteuid( uid ); 491 return ( AFPERR_PARAM ); 492 } 493 seteuid( uid ); 494 } 495 496#else /* BSD4_4 */ 497 if (get_linux_quota (WANT_USER_QUOTA, vol->v_gvs, uid, dq) !=0) { 498 return( AFPERR_PARAM ); 499 } 500 501 if (get_linux_quota(WANT_GROUP_QUOTA, vol->v_gvs, getegid(), &dqg) != 0) { 502#ifdef DEBUG_QUOTA 503 LOG(log_debug, logtype_afpd, "group quota did not work!" ); 504#endif /* DEBUG_QUOTA */ 505 506 return AFP_OK; /* no need to check user vs group quota */ 507 } 508#endif /* BSD4_4 */ 509 510 511#ifndef TRU64 512 /* return either the group quota entry or user quota entry, 513 whichever has the least amount of space remaining 514 */ 515 516 /* if user space remaining > group space remaining */ 517 if( 518 /* if overquota, free space is 0 otherwise hard-current */ 519 ( overquota( dq ) ? 0 : ( dq->dqb_bhardlimit ? dq->dqb_bhardlimit - 520 dq->dqb_curblocks : ~((u_int64_t) 0) ) ) 521 522 > 523 524 ( overquota( &dqg ) ? 0 : ( dqg.dqb_bhardlimit ? dqg.dqb_bhardlimit - 525 dqg.dqb_curblocks : ~((u_int64_t) 0) ) ) 526 527 ) /* if */ 528 { 529 /* use group quota limits rather than user limits */ 530 dq->dqb_curblocks = dqg.dqb_curblocks; 531 dq->dqb_bhardlimit = dqg.dqb_bhardlimit; 532 dq->dqb_bsoftlimit = dqg.dqb_bsoftlimit; 533 dq->dqb_btimelimit = dqg.dqb_btimelimit; 534 } /* if */ 535 536#endif /* TRU64 */ 537 538#endif /* ultrix */ 539#endif /* __svr4__ */ 540 541 return AFP_OK; 542} 543 544 545static int getquota( struct vol *vol, struct dqblk *dq, const u_int32_t bsize) 546{ 547 char *p; 548 549#ifdef __svr4__ 550 char buf[ MAXPATHLEN + 1]; 551 552 if ( vol->v_qfd == -1 && vol->v_gvs == NULL) { 553 if (( p = mountp( vol->v_path, &vol->v_nfs)) == NULL ) { 554 LOG(log_info, logtype_afpd, "getquota: mountp %s fails", vol->v_path ); 555 return( AFPERR_PARAM ); 556 } 557 558 if (vol->v_nfs) { 559 if (( vol->v_gvs = (char *)malloc( strlen( p ) + 1 )) == NULL ) { 560 LOG(log_error, logtype_afpd, "getquota: malloc: %s", strerror(errno) ); 561 return AFPERR_MISC; 562 } 563 strcpy( vol->v_gvs, p ); 564 565 } else { 566 sprintf( buf, "%s/quotas", p ); 567 if (( vol->v_qfd = open( buf, O_RDONLY, 0 )) < 0 ) { 568 LOG(log_info, logtype_afpd, "open %s: %s", buf, strerror(errno) ); 569 return( AFPERR_PARAM ); 570 } 571 } 572 573 } 574#else 575 if ( vol->v_gvs == NULL ) { 576 if (( p = special( vol->v_path, &vol->v_nfs )) == NULL ) { 577 LOG(log_info, logtype_afpd, "getquota: special %s fails", vol->v_path ); 578 return( AFPERR_PARAM ); 579 } 580 581 if (( vol->v_gvs = (char *)malloc( strlen( p ) + 1 )) == NULL ) { 582 LOG(log_error, logtype_afpd, "getquota: malloc: %s", strerror(errno) ); 583 return AFPERR_MISC; 584 } 585 strcpy( vol->v_gvs, p ); 586 } 587#endif 588 589#ifdef TRU64 590 /* Digital UNIX: Two forms of specifying an NFS filesystem are possible, 591 either 'hostname:path' or 'path@hostname' (Ultrix heritage) */ 592 if (vol->v_nfs) { 593 char *hostpath; 594 char pathstring[MNAMELEN]; 595 /* MNAMELEN ist defined in <sys/mount.h> */ 596 int result; 597 598 if ((hostpath = strchr(vol->v_gvs,'@')) != NULL ) { 599 /* convert 'path@hostname' to 'hostname:path', 600 * call getnfsquota(), 601 * convert 'hostname:path' back to 'path@hostname' */ 602 *hostpath = '\0'; 603 sprintf(pathstring,"%s:%s",hostpath+1,vol->v_gvs); 604 strcpy(vol->v_gvs,pathstring); 605 606 result = getnfsquota(vol, uuid, bsize, dq); 607 608 hostpath = strchr(vol->v_gvs,':'); 609 *hostpath = '\0'; 610 sprintf(pathstring,"%s@%s",hostpath+1,vol->v_gvs); 611 strcpy(vol->v_gvs,pathstring); 612 613 return result; 614 } 615 else 616 /* vol->v_gvs is of the form 'hostname:path' */ 617 return getnfsquota(vol, uuid, bsize, dq); 618 } else 619 /* local filesystem */ 620 return getfsquota(vol, uuid, dq); 621 622#else /* TRU64 */ 623 return vol->v_nfs ? getnfsquota(vol, uuid, bsize, dq) : 624 getfsquota(vol, uuid, dq); 625#endif /* TRU64 */ 626} 627 628static int overquota( struct dqblk *dqblk) 629{ 630 struct timeval tv; 631 632 if ( dqblk->dqb_curblocks > dqblk->dqb_bhardlimit && 633 dqblk->dqb_bhardlimit != 0 ) { 634 return( 1 ); 635 } 636 637 if ( dqblk->dqb_curblocks < dqblk->dqb_bsoftlimit || 638 dqblk->dqb_bsoftlimit == 0 ) { 639 return( 0 ); 640 } 641#ifdef ultrix 642 if ( dqblk->dqb_bwarn ) { 643 return( 0 ); 644 } 645#else /* ultrix */ 646 if ( gettimeofday( &tv, NULL ) < 0 ) { 647 LOG(log_error, logtype_afpd, "overquota: gettimeofday: %s", strerror(errno) ); 648 return( AFPERR_PARAM ); 649 } 650 if ( dqblk->dqb_btimelimit && dqblk->dqb_btimelimit > tv.tv_sec ) { 651 return( 0 ); 652 } 653#endif /* ultrix */ 654 return( 1 ); 655} 656 657/* 658 * This next bit is basically for linux -- everything is fine 659 * if you use 1k blocks... but if you try (for example) to mount 660 * a volume via nfs from a netapp (which might use 4k blocks) everything 661 * gets reported improperly. I have no idea about dbtob on other 662 * platforms. 663 */ 664 665#ifdef HAVE_BROKEN_DBTOB 666#undef dbtob 667#define dbtob(a, b) ((VolSpace)((VolSpace)(a) * (VolSpace)(b))) 668#define HAVE_2ARG_DBTOB 669#endif 670 671#ifndef dbtob 672#define dbtob(a) ((a) << 10) 673#endif 674 675/* i do the cast to VolSpace here to make sure that 64-bit shifts 676 work */ 677#ifdef HAVE_2ARG_DBTOB 678#define tobytes(a, b) dbtob((VolSpace) (a), (VolSpace) (b)) 679#else 680#define tobytes(a, b) dbtob((VolSpace) (a)) 681#endif 682 683int uquota_getvolspace( struct vol *vol, VolSpace *bfree, VolSpace *btotal, const u_int32_t bsize) 684{ 685 u_int64_t this_bsize; 686 struct dqblk dqblk; 687 688 this_bsize = bsize; 689 690 if (getquota( vol, &dqblk, bsize) != 0 ) { 691 return( AFPERR_PARAM ); 692 } 693 694#ifdef linux 695 this_bsize = dqblk.bsize; 696#endif 697 698#ifdef DEBUG_QUOTA 699 LOG(log_debug, logtype_afpd, "after calling getquota in uquota_getvolspace!" ); 700 LOG(log_debug, logtype_afpd, "dqb_ihardlimit: %u", dqblk.dqb_ihardlimit ); 701 LOG(log_debug, logtype_afpd, "dqb_isoftlimit: %u", dqblk.dqb_isoftlimit ); 702 LOG(log_debug, logtype_afpd, "dqb_curinodes : %u", dqblk.dqb_curinodes ); 703 LOG(log_debug, logtype_afpd, "dqb_bhardlimit: %u", dqblk.dqb_bhardlimit ); 704 LOG(log_debug, logtype_afpd, "dqb_bsoftlimit: %u", dqblk.dqb_bsoftlimit ); 705 LOG(log_debug, logtype_afpd, "dqb_curblocks : %u", dqblk.dqb_curblocks ); 706 LOG(log_debug, logtype_afpd, "dqb_btime : %u", dqblk.dqb_btime ); 707 LOG(log_debug, logtype_afpd, "dqb_itime : %u", dqblk.dqb_itime ); 708 LOG(log_debug, logtype_afpd, "bsize/this_bsize : %u/%u", bsize, this_bsize ); 709 LOG(log_debug, logtype_afpd, "dqblk.dqb_bhardlimit size: %u", tobytes( dqblk.dqb_bhardlimit, this_bsize )); 710 LOG(log_debug, logtype_afpd, "dqblk.dqb_bsoftlimit size: %u", tobytes( dqblk.dqb_bsoftlimit, this_bsize )); 711 LOG(log_debug, logtype_afpd, "dqblk.dqb_curblocks size: %u", tobytes( dqblk.dqb_curblocks, this_bsize )); 712#endif /* DEBUG_QUOTA */ 713 714 /* no limit set for this user. it might be set in the future. */ 715 if (dqblk.dqb_bsoftlimit == 0 && dqblk.dqb_bhardlimit == 0) { 716 *btotal = *bfree = ~((VolSpace) 0); 717 } else if ( overquota( &dqblk )) { 718 if ( tobytes( dqblk.dqb_curblocks, this_bsize ) > tobytes( dqblk.dqb_bsoftlimit, this_bsize ) ) { 719 *btotal = tobytes( dqblk.dqb_curblocks, this_bsize ); 720 *bfree = 0; 721 } 722 else { 723 *btotal = tobytes( dqblk.dqb_bsoftlimit, this_bsize ); 724 *bfree = tobytes( dqblk.dqb_bsoftlimit, this_bsize ) - 725 tobytes( dqblk.dqb_curblocks, this_bsize ); 726 } 727 } else { 728 *btotal = tobytes( dqblk.dqb_bhardlimit, this_bsize ); 729 *bfree = tobytes( dqblk.dqb_bhardlimit, this_bsize ) - 730 tobytes( dqblk.dqb_curblocks, this_bsize ); 731 } 732 733#ifdef DEBUG_QUOTA 734 LOG(log_debug, logtype_afpd, "bfree : %u", *bfree ); 735 LOG(log_debug, logtype_afpd, "btotal : %u", *btotal ); 736 LOG(log_debug, logtype_afpd, "bfree : %uKB", *bfree/1024 ); 737 LOG(log_debug, logtype_afpd, "btotal : %uKB", *btotal/1024 ); 738#endif 739 740 return( AFP_OK ); 741} 742#endif 743