1/* 2 * Copyright (c) 2002-2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * Copyright (c) 1980, 1990, 1993 25 * The Regents of the University of California. All rights reserved. 26 * 27 * This code is derived from software contributed to Berkeley by 28 * Robert Elz at The University of Melbourne. 29 * 30 * Redistribution and use in source and binary forms, with or without 31 * modification, are permitted provided that the following conditions 32 * are met: 33 * 1. Redistributions of source code must retain the above copyright 34 * notice, this list of conditions and the following disclaimer. 35 * 2. Redistributions in binary form must reproduce the above copyright 36 * notice, this list of conditions and the following disclaimer in the 37 * documentation and/or other materials provided with the distribution. 38 * 3. All advertising materials mentioning features or use of this software 39 * must display the following acknowledgement: 40 * This product includes software developed by the University of 41 * California, Berkeley and its contributors. 42 * 4. Neither the name of the University nor the names of its contributors 43 * may be used to endorse or promote products derived from this software 44 * without specific prior written permission. 45 * 46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56 * SUCH DAMAGE. 57 */ 58 59 60/* 61 * Disk quota reporting program. 62 */ 63#include <sys/param.h> 64#include <sys/file.h> 65#ifdef __APPLE__ 66#include <sys/mount.h> 67#endif /* __APPLE */ 68#include <sys/stat.h> 69#include <sys/queue.h> 70 71#include <sys/quota.h> 72#include <libkern/OSByteOrder.h> 73 74#include <ctype.h> 75#include <errno.h> 76#include <fstab.h> 77#include <grp.h> 78#include <pwd.h> 79#include <stdio.h> 80#include <stdlib.h> 81#include <string.h> 82#include <unistd.h> 83 84char *qfname = QUOTAFILENAME; 85char *qfextension[] = INITQFNAMES; 86 87#ifdef __APPLE__ 88u_int32_t quotamagic[MAXQUOTAS] = INITQMAGICS; 89#endif /* __APPLE__ */ 90 91struct quotause { 92 struct quotause *next; 93 long flags; 94 struct dqblk dqblk; 95 char fsname[MAXPATHLEN + 1]; 96} *getprivs(); 97#define FOUND 0x01 98 99int qflag; 100int vflag; 101 102int alldigits __P((char *)); 103int hasquota __P((struct statfs *, int, char **)); 104void heading __P((int, u_long, char *, char *)); 105void showgid __P((u_long)); 106void showuid __P((u_long)); 107void showgrpname __P((char *)); 108void showquotas __P((int, u_long, char *)); 109void showusrname __P((char *)); 110void usage __P((void)); 111 112#ifdef __APPLE__ 113int qflookup(int, u_long, int, struct dqblk *); 114#endif /* __APPLE__ */ 115 116int 117main(argc, argv) 118 char *argv[]; 119{ 120 int ngroups; 121 gid_t gidset[NGROUPS]; 122 int i, gflag = 0, uflag = 0; 123 char ch; 124 125#if 0 126 if (quotactl("/", 0, 0, (caddr_t)0) < 0 && errno == ENOTSUP) { 127 fprintf(stderr, "There are no quotas on this system\n"); 128 exit(0); 129 } 130#endif 131 132 while ((ch = getopt(argc, argv, "ugvq")) != EOF) { 133 switch(ch) { 134 case 'g': 135 gflag++; 136 break; 137 case 'u': 138 uflag++; 139 break; 140 case 'v': 141 vflag++; 142 break; 143 case 'q': 144 qflag++; 145 break; 146 default: 147 usage(); 148 } 149 } 150 argc -= optind; 151 argv += optind; 152 if (!uflag && !gflag) 153 uflag++; 154 if (argc == 0) { 155 if (uflag) 156 showuid(getuid()); 157 if (gflag) { 158 ngroups = getgroups(NGROUPS, gidset); 159 if (ngroups < 0) { 160 perror("quota: getgroups"); 161 exit(1); 162 } 163 for (i = 1; i < ngroups; i++) 164 showgid(gidset[i]); 165 } 166 exit(0); 167 } 168 if (uflag && gflag) 169 usage(); 170 if (uflag) { 171 for (; argc > 0; argc--, argv++) { 172 if (alldigits(*argv)) 173 showuid(atoi(*argv)); 174 else 175 showusrname(*argv); 176 } 177 exit(0); 178 } 179 if (gflag) { 180 for (; argc > 0; argc--, argv++) { 181 if (alldigits(*argv)) 182 showgid(atoi(*argv)); 183 else 184 showgrpname(*argv); 185 } 186 exit(0); 187 } 188 exit(0); 189} 190 191void 192usage() 193{ 194 195 fprintf(stderr, "%s\n%s\n%s\n", 196 "Usage: quota [-guqv]", 197 "\tquota [-qv] -u username ...", 198 "\tquota [-qv] -g groupname ..."); 199 exit(1); 200} 201 202/* 203 * Print out quotas for a specified user identifier. 204 */ 205void 206showuid(uid) 207 u_long uid; 208{ 209 struct passwd *pwd = getpwuid(uid); 210 u_long myuid; 211 char *name; 212 213 if (pwd == NULL) 214 name = "(no account)"; 215 else 216 name = pwd->pw_name; 217 myuid = getuid(); 218 if (uid != myuid && myuid != 0) { 219 printf("quota: %s (uid %ld): permission denied\n", name, uid); 220 return; 221 } 222 showquotas(USRQUOTA, uid, name); 223} 224 225/* 226 * Print out quotas for a specifed user name. 227 */ 228void 229showusrname(name) 230 char *name; 231{ 232 struct passwd *pwd = getpwnam(name); 233 u_long myuid; 234 235 if (pwd == NULL) { 236 fprintf(stderr, "quota: %s: unknown user\n", name); 237 return; 238 } 239 myuid = getuid(); 240 if (pwd->pw_uid != myuid && myuid != 0) { 241 fprintf(stderr, "quota: %s (uid %d): permission denied\n", 242 name, pwd->pw_uid); 243 return; 244 } 245 showquotas(USRQUOTA, pwd->pw_uid, name); 246} 247 248/* 249 * Print out quotas for a specified group identifier. 250 */ 251void 252showgid(gid) 253 u_long gid; 254{ 255 struct group *grp = getgrgid(gid); 256 int ngroups; 257 gid_t gidset[NGROUPS]; 258 register int i; 259 char *name; 260 261 if (grp == NULL) 262 name = "(no entry)"; 263 else 264 name = grp->gr_name; 265 ngroups = getgroups(NGROUPS, gidset); 266 if (ngroups < 0) { 267 perror("quota: getgroups"); 268 return; 269 } 270 for (i = 1; i < ngroups; i++) 271 if (gid == gidset[i]) 272 break; 273 if (i >= ngroups && getuid() != 0) { 274 fprintf(stderr, "quota: %s (gid %ld): permission denied\n", 275 name, gid); 276 return; 277 } 278 showquotas(GRPQUOTA, gid, name); 279} 280 281/* 282 * Print out quotas for a specifed group name. 283 */ 284void 285showgrpname(name) 286 char *name; 287{ 288 struct group *grp = getgrnam(name); 289 int ngroups; 290 gid_t gidset[NGROUPS]; 291 register int i; 292 293 if (grp == NULL) { 294 fprintf(stderr, "quota: %s: unknown group\n", name); 295 return; 296 } 297 ngroups = getgroups(NGROUPS, gidset); 298 if (ngroups < 0) { 299 perror("quota: getgroups"); 300 return; 301 } 302 for (i = 1; i < ngroups; i++) 303 if (grp->gr_gid == gidset[i]) 304 break; 305 if (i >= ngroups && getuid() != 0) { 306 fprintf(stderr, "quota: %s (gid %d): permission denied\n", 307 name, grp->gr_gid); 308 return; 309 } 310 showquotas(GRPQUOTA, grp->gr_gid, name); 311} 312 313void 314showquotas(type, id, name) 315 int type; 316 u_long id; 317 char *name; 318{ 319 register struct quotause *qup; 320 struct quotause *quplist, *getprivs(); 321 char *msgi, *msgb, *timeprt(); 322 int lines = 0; 323 static time_t now; 324 325 if (now == 0) 326 time(&now); 327 quplist = getprivs(id, type); 328 for (qup = quplist; qup; qup = qup->next) { 329 if (!vflag && 330 qup->dqblk.dqb_isoftlimit == 0 && 331 qup->dqblk.dqb_ihardlimit == 0 && 332 qup->dqblk.dqb_bsoftlimit == 0 && 333 qup->dqblk.dqb_bhardlimit == 0) 334 continue; 335 msgi = (char *)0; 336 if (qup->dqblk.dqb_ihardlimit && 337 qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit) { 338 msgi = "File limit reached on"; 339 } else if (qup->dqblk.dqb_isoftlimit && 340 qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) { 341 if (qup->dqblk.dqb_itime > now) { 342 msgi = "In file grace period on"; 343 } else { 344 msgi = "Over file quota on"; 345 } 346 } 347 msgb = (char *)0; 348#ifdef __APPLE__ 349 if (qup->dqblk.dqb_bhardlimit && 350 qup->dqblk.dqb_curbytes >= qup->dqblk.dqb_bhardlimit) { 351 msgb = "Block limit reached on"; 352 } else if (qup->dqblk.dqb_bsoftlimit && 353 qup->dqblk.dqb_curbytes >= qup->dqblk.dqb_bsoftlimit) { 354 if (qup->dqblk.dqb_btime > now) { 355 msgb = "In block grace period on"; 356 } else { 357 msgb = "Over block quota on"; 358 } 359 } 360#else 361 if (qup->dqblk.dqb_bhardlimit && 362 qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit) { 363 msgb = "Block limit reached on"; 364 } else if (qup->dqblk.dqb_bsoftlimit && 365 qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) { 366 if (qup->dqblk.dqb_btime > now) { 367 msgb = "In block grace period on"; 368 } else { 369 msgb = "Over block quota on"; 370 } 371 } 372#endif /* __APPLE__ */ 373 374 if (qflag) { 375 if ((msgi != (char *)0 || msgb != (char *)0) && 376 lines++ == 0) 377 heading(type, id, name, ""); 378 if (msgi != (char *)0) 379 printf("\t%s %s\n", msgi, qup->fsname); 380 if (msgb != (char *)0) 381 printf("\t%s %s\n", msgb, qup->fsname); 382 continue; 383 } 384#ifdef __APPLE__ 385 if (vflag || 386 qup->dqblk.dqb_curbytes || 387 qup->dqblk.dqb_curinodes) { 388 if (lines++ == 0) 389 heading(type, id, name, ""); 390 391 printf("%15s %12qd%c %12qd %12qd %8s" 392 , qup->fsname 393 , qup->dqblk.dqb_curbytes / 1024 394 , (msgb == (char *)0) ? ' ' : '*' 395 , qup->dqblk.dqb_bsoftlimit / 1024 396 , qup->dqblk.dqb_bhardlimit / 1024 397 , (msgb == (char *)0) ? "" 398 : timeprt(qup->dqblk.dqb_btime)); 399#else 400 if (vflag || 401 qup->dqblk.dqb_curblocks || 402 qup->dqblk.dqb_curinodes) { 403 if (lines++ == 0) 404 heading(type, id, name, ""); 405 406 printf("%15s%8d%c%7d%8d%8s" 407 , qup->fsname 408 , dbtob(qup->dqblk.dqb_curblocks) / 1024 409 , (msgb == (char *)0) ? ' ' : '*' 410 , dbtob(qup->dqblk.dqb_bsoftlimit) / 1024 411 , dbtob(qup->dqblk.dqb_bhardlimit) / 1024 412 , (msgb == (char *)0) ? "" 413 : timeprt(qup->dqblk.dqb_btime)); 414#endif /* __APPLE__ */ 415 printf("%8d%c%7d%8d%8s\n" 416 , qup->dqblk.dqb_curinodes 417 , (msgi == (char *)0) ? ' ' : '*' 418 , qup->dqblk.dqb_isoftlimit 419 , qup->dqblk.dqb_ihardlimit 420 , (msgi == (char *)0) ? "" 421 : timeprt(qup->dqblk.dqb_itime) 422 ); 423 continue; 424 } 425 } 426 if (!qflag && lines == 0) 427 heading(type, id, name, "none"); 428} 429 430void 431heading(type, id, name, tag) 432 int type; 433 u_long id; 434 char *name, *tag; 435{ 436 437 printf("Disk quotas for %s %s (%cid %ld): %s\n", qfextension[type], 438 name, *qfextension[type], id, tag); 439 if (!qflag && tag[0] == '\0') { 440#ifdef __APPLE__ 441 printf("%15s %12s %12s %12s %8s%8s %7s%8s%8s\n" 442 , "Filesystem" 443 , "1K blocks" 444#else 445 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n" 446 , "Filesystem" 447 , "blocks" 448#endif /* __APPLE __*/ 449 , "quota" 450 , "limit" 451 , "grace" 452 , "files" 453 , "quota" 454 , "limit" 455 , "grace" 456 ); 457 } 458} 459 460/* 461 * Calculate the grace period and return a printable string for it. 462 */ 463char * 464timeprt(seconds) 465 time_t seconds; 466{ 467 time_t hours, minutes; 468 static char buf[20]; 469 static time_t now; 470 471 if (now == 0) 472 time(&now); 473 if (now > seconds) 474 return ("none"); 475 seconds -= now; 476 minutes = (seconds + 30) / 60; 477 hours = (minutes + 30) / 60; 478 if (hours >= 36) { 479 snprintf(buf, sizeof(buf), "%ddays", (int)((hours + 12) / 24)); 480 return (buf); 481 } 482 if (minutes >= 60) { 483 sprintf(buf, "%2d:%d", (int)(minutes / 60), (int)(minutes % 60)); 484 return (buf); 485 } 486 sprintf(buf, "%2d", (int)minutes); 487 return (buf); 488} 489 490typedef struct { 491 int alloced; 492 int nels; 493 char **strings; 494} mount_list_t; 495 496static void * 497init_list(int max) 498{ 499 mount_list_t *retval = NULL; 500 retval = malloc(sizeof(*retval)); 501 if (retval) { 502 retval->strings = malloc(sizeof(char*) * max); 503 if (retval->strings) { 504 retval->alloced = max; 505 } else { 506 retval->alloced = 0; 507 } 508 retval->nels = 0; 509 } 510 return retval; 511} 512static void 513free_list(void *list) 514{ 515 mount_list_t *tmp = list; 516 int i; 517 518 if (tmp == NULL) 519 return; 520 for (i = 0; i < tmp->nels; i++) { 521 free(tmp->strings[i]); 522 } 523 free(tmp); 524 return; 525} 526 527static int 528hasseen(void *tmp, const char *mp) 529{ 530 int retval = 0; 531 mount_list_t *list = tmp; 532 int i; 533 534 if (tmp == NULL || mp == NULL) 535 goto done; 536 537 /* 538 * This could also be a binary search, but then we'd have to sort 539 * after each addition. We may want to change the behaviour based 540 * on the number of elements in the array. 541 */ 542 543 for (i = 0; i < list->nels; i++) { 544 if (strcmp(list->strings[i], mp) == 0) { 545 retval = 1; 546 goto done; 547 } 548 } 549 if (list->nels <= list->alloced) { 550 char **a = realloc(list->strings, (list->alloced + 10) * sizeof(char*)); 551 if (a) { 552 list->alloced = list->alloced + 10; 553 list->strings = a; 554 } else { 555 goto done; 556 } 557 } 558 list->strings[list->nels++] = strdup(mp); 559 560done: 561 return retval; 562} 563 564/* 565 * Collect the requested quota information. 566 */ 567#ifdef __APPLE__ 568struct quotause * 569getprivs(id, quotatype) 570 register long id; 571 int quotatype; 572{ 573 struct statfs *fst; 574 register struct quotause *qup, *quptail; 575 struct quotause *quphead; 576 struct dqblk dqb; 577 char *qfpathname; 578 int qcmd, fd; 579 int nfst, i; 580 int error; 581 void *cache; 582 583 quptail = quphead = (struct quotause *)0; 584 qcmd = QCMD(Q_GETQUOTA, quotatype); 585 586 nfst = getmntinfo(&fst, MNT_WAIT); 587 if (nfst==0) { 588 fprintf(stderr, "quota: no mounted filesystems\n"); 589 exit(1); 590 } 591 592 cache = init_list(nfst); 593 594 for (i=0; i<nfst; i++) { 595 if (hasseen(cache, fst[i].f_mntonname)) 596 continue; 597 error = quotactl(fst[i].f_mntonname, qcmd, id, (char *)&dqb); 598 if (error) { 599 if (strcmp(fst[i].f_fstypename, "hfs")) 600 continue; 601 if (!hasquota(&fst[i], quotatype, &qfpathname)) 602 continue; 603 } 604 if ((qup = (struct quotause *)malloc(sizeof *qup)) == NULL) { 605 fprintf(stderr, "quota: out of memory\n"); 606 exit(2); 607 } 608 if (!error) { 609 bcopy(&dqb, &qup->dqblk, sizeof(dqb)); 610 } else { 611 if ((fd = open(qfpathname, O_RDONLY)) < 0) { 612 perror(qfpathname); 613 free(qup); 614 continue; 615 } 616 if ((error = qflookup(fd, id, quotatype, &qup->dqblk))) { 617 perror(qfpathname); 618 close(fd); 619 free(qup); 620 continue; 621 } 622 close(fd); 623 } 624 strlcpy(qup->fsname, fst[i].f_mntonname, sizeof(qup->fsname)); 625 if (quphead == NULL) 626 quphead = qup; 627 else 628 quptail->next = qup; 629 quptail = qup; 630 qup->next = 0; 631 } 632 free_list(cache); 633 634 return (quphead); 635} 636#else 637struct quotause * 638getprivs(id, quotatype) 639 register long id; 640 int quotatype; 641{ 642 register struct fstab *fs; 643 register struct quotause *qup, *quptail; 644 struct quotause *quphead; 645 char *qfpathname; 646 int qcmd, fd; 647 648 setfsent(); 649 quphead = (struct quotause *)0; 650 qcmd = QCMD(Q_GETQUOTA, quotatype); 651 while (fs = getfsent()) { 652 if (strcmp(fs->fs_vfstype, "ufs")) 653 continue; 654 if (!hasquota(fs, quotatype, &qfpathname)) 655 continue; 656 if ((qup = (struct quotause *)malloc(sizeof *qup)) == NULL) { 657 fprintf(stderr, "quota: out of memory\n"); 658 exit(2); 659 } 660 if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) { 661 if ((fd = open(qfpathname, O_RDONLY)) < 0) { 662 perror(qfpathname); 663 free(qup); 664 continue; 665 } 666 lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET); 667 switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) { 668 case 0: /* EOF */ 669 /* 670 * Convert implicit 0 quota (EOF) 671 * into an explicit one (zero'ed dqblk) 672 */ 673 bzero((caddr_t)&qup->dqblk, 674 sizeof(struct dqblk)); 675 break; 676 677 case sizeof(struct dqblk): /* OK */ 678 break; 679 680 default: /* ERROR */ 681 fprintf(stderr, "quota: read error"); 682 perror(qfpathname); 683 close(fd); 684 free(qup); 685 continue; 686 } 687 close(fd); 688 } 689 strlcpy(qup->fsname, fs->fs_file, sizeof(qup->fsname)); 690 if (quphead == NULL) 691 quphead = qup; 692 else 693 quptail->next = qup; 694 quptail = qup; 695 qup->next = 0; 696 } 697 endfsent(); 698 return (quphead); 699} 700#endif /* __APPLE__ */ 701 702 703#ifdef __APPLE__ 704/* 705 * Lookup an entry in the quota file. 706 */ 707int 708qflookup(fd, id, type, dqbp) 709 int fd; 710 u_long id; 711 int type; 712 struct dqblk *dqbp; 713{ 714 struct dqfilehdr dqhdr; 715 int i, skip, last, m; 716 u_long mask; 717 718 bzero(dqbp, sizeof(struct dqblk)); 719 720 if (id == 0) 721 return (0); 722 723 lseek(fd, 0, L_SET); 724 if (read(fd, &dqhdr, sizeof(struct dqfilehdr)) != sizeof(struct dqfilehdr)) { 725 fprintf(stderr, "quota: read error\n"); 726 return (errno); 727 } 728 729 /* Sanity check the quota file header. */ 730 if ((OSSwapBigToHostInt32(dqhdr.dqh_magic) != quotamagic[type]) || 731 (OSSwapBigToHostInt32(dqhdr.dqh_version) > QF_VERSION) || 732 (!powerof2(OSSwapBigToHostInt32(dqhdr.dqh_maxentries)))) { 733 fprintf(stderr, "quota: invalid quota file header\n"); 734 return (EINVAL); 735 } 736 737 m = OSSwapBigToHostInt32(dqhdr.dqh_maxentries); 738 mask = m - 1; 739 i = dqhash1(id, dqhashshift(m), mask); 740 skip = dqhash2(id, mask); 741 742 for (last = (i + (m-1) * skip) & mask; 743 i != last; 744 i = (i + skip) & mask) { 745 lseek(fd, dqoffset(i), L_SET); 746 if (read(fd, dqbp, sizeof(struct dqblk)) < sizeof(struct dqblk)) { 747 fprintf(stderr, "quota: read error at index %d\n", i); 748 return (errno); 749 } 750 /* 751 * Stop when an empty entry is found 752 * or we encounter a matching id. 753 */ 754 if (dqbp->dqb_id == 0 || OSSwapBigToHostInt32(dqbp->dqb_id) == id) 755 break; 756 } 757 /* Put data in host native byte order. */ 758 dqbp->dqb_bhardlimit = OSSwapBigToHostInt64(dqbp->dqb_bhardlimit); 759 dqbp->dqb_bsoftlimit = OSSwapBigToHostInt64(dqbp->dqb_bsoftlimit); 760 dqbp->dqb_curbytes = OSSwapBigToHostInt64(dqbp->dqb_curbytes); 761 dqbp->dqb_ihardlimit = OSSwapBigToHostInt32(dqbp->dqb_ihardlimit); 762 dqbp->dqb_isoftlimit = OSSwapBigToHostInt32(dqbp->dqb_isoftlimit); 763 dqbp->dqb_curinodes = OSSwapBigToHostInt32(dqbp->dqb_curinodes); 764 dqbp->dqb_btime = OSSwapBigToHostInt32(dqbp->dqb_btime); 765 dqbp->dqb_itime = OSSwapBigToHostInt32(dqbp->dqb_itime); 766 dqbp->dqb_id = OSSwapBigToHostInt32(dqbp->dqb_id); 767 768 return (0); 769} 770#endif /* __APPLE__ */ 771 772 773/* 774 * Check to see if a particular quota is to be enabled. 775 */ 776#ifdef __APPLE__ 777int 778hasquota(fst, type, qfnamep) 779 register struct statfs *fst; 780 int type; 781 char **qfnamep; 782{ 783 struct stat sb; 784 static char initname, usrname[100], grpname[100]; 785 static char buf[BUFSIZ]; 786 787 if (!initname) { 788 snprintf(usrname, sizeof(usrname), "%s%s", qfextension[USRQUOTA], qfname); 789 snprintf(grpname, sizeof(grpname), "%s%s", qfextension[GRPQUOTA], qfname); 790 initname = 1; 791 } 792 /* 793 We only support the default path to the 794 on disk quota files. 795 */ 796 797 (void)snprintf(buf, sizeof(buf), "%s/%s.%s", fst->f_mntonname, 798 QUOTAOPSNAME, qfextension[type] ); 799 if (stat(buf, &sb) != 0) { 800 /* There appears to be no mount option file */ 801 return(0); 802 } 803 804 (void) snprintf(buf, sizeof(buf), "%s/%s.%s", fst->f_mntonname, qfname, qfextension[type]); 805 *qfnamep = buf; 806 return (1); 807} 808#else 809hasquota(fs, type, qfnamep) 810 register struct fstab *fs; 811 int type; 812 char **qfnamep; 813{ 814 register char *opt; 815 char *cp, *index(), *strtok(); 816 static char initname, usrname[100], grpname[100]; 817 static char buf[BUFSIZ]; 818 819 if (!initname) { 820 snprintf(usrname, sizeof(usrname), "%s%s", qfextension[USRQUOTA], qfname); 821 snprintf(grpname, sizeof(grpname), "%s%s", qfextension[GRPQUOTA], qfname); 822 initname = 1; 823 } 824 strlcpy(buf, fs->fs_mntops, sizeof(buf)); 825 for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 826 if (cp = index(opt, '=')) 827 *cp++ = '\0'; 828 if (type == USRQUOTA && strcmp(opt, usrname) == 0) 829 break; 830 if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 831 break; 832 } 833 if (!opt) 834 return (0); 835 if (cp) { 836 *qfnamep = cp; 837 return (1); 838 } 839 (void) snprintf(buf, sizeof(buf), "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 840 *qfnamep = buf; 841 return (1); 842} 843#endif /* __APPLE__ */ 844 845int 846alldigits(s) 847 register char *s; 848{ 849 register int c; 850 851 c = *s++; 852 do { 853 if (!isdigit(c)) 854 return (0); 855 } while ((c = *s++)); 856 return (1); 857} 858