1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * University Copyright- Copyright (c) 1982, 1986, 1988 31 * The Regents of the University of California 32 * All Rights Reserved 33 * 34 * University Acknowledgment- Portions of this document are derived from 35 * software developed by the University of California, Berkeley, and its 36 * contributors. 37 */ 38 39 /* 40 * Disk quota reporting program. 41 */ 42 #include <stdio.h> 43 #include <sys/mnttab.h> 44 #include <ctype.h> 45 #include <pwd.h> 46 #include <errno.h> 47 #include <fcntl.h> 48 #include <memory.h> 49 #include <sys/time.h> 50 #include <sys/param.h> 51 #include <sys/types.h> 52 #include <sys/sysmacros.h> 53 #include <sys/mntent.h> 54 #include <sys/file.h> 55 #include <sys/stat.h> 56 #include <sys/fs/ufs_quota.h> 57 #include <priv_utils.h> 58 #include <locale.h> 59 #include <rpc/rpc.h> 60 #include <netdb.h> 61 #include <rpcsvc/rquota.h> 62 #include <zone.h> 63 #include "../../nfs/lib/replica.h" 64 65 int vflag; 66 int nolocalquota; 67 68 extern int optind; 69 extern char *optarg; 70 71 #define QFNAME "quotas" 72 73 #if DEV_BSIZE < 1024 74 #define kb(x) ((x) / (1024 / DEV_BSIZE)) 75 #else 76 #define kb(x) ((x) * (DEV_BSIZE / 1024)) 77 #endif 78 79 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 80 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 81 #endif 82 83 static int getnfsquota(char *, char *, uid_t, struct dqblk *); 84 static void showuid(uid_t); 85 static void showquotas(uid_t, char *); 86 static void warn(struct mnttab *, struct dqblk *); 87 static void heading(uid_t, char *); 88 static void prquota(struct mnttab *, struct dqblk *); 89 static void fmttime(char *, long); 90 91 int 92 main(int argc, char *argv[]) 93 { 94 int opt; 95 int i; 96 int status = 0; 97 98 (void) setlocale(LC_ALL, ""); 99 (void) textdomain(TEXT_DOMAIN); 100 101 /* 102 * PRIV_FILE_DAC_READ is needed to read the QFNAME file 103 * Clear all other privleges from the limit set, and add 104 * the required privilege to the bracketed set. 105 */ 106 107 if (__init_suid_priv(PU_CLEARLIMITSET, PRIV_FILE_DAC_READ, 108 NULL) == -1) { 109 (void) fprintf(stderr, 110 gettext("Insufficient privileges, " 111 "quota must be set-uid root or have " 112 "file_dac_read privileges\n")); 113 114 exit(1); 115 } 116 117 while ((opt = getopt(argc, argv, "vV")) != EOF) { 118 switch (opt) { 119 120 case 'v': 121 vflag++; 122 break; 123 124 case 'V': /* Print command line */ 125 { 126 char *opt_text; 127 int opt_count; 128 129 (void) fprintf(stdout, "quota -F UFS "); 130 for (opt_count = 1; opt_count < argc; opt_count++) { 131 opt_text = argv[opt_count]; 132 if (opt_text) 133 (void) fprintf(stdout, " %s ", 134 opt_text); 135 } 136 (void) fprintf(stdout, "\n"); 137 } 138 break; 139 140 case '?': 141 fprintf(stderr, "ufs usage: quota [-v] [username]\n"); 142 exit(32); 143 } 144 } 145 if (quotactl(Q_ALLSYNC, NULL, (uid_t)0, NULL) < 0 && errno == EINVAL) { 146 if (vflag) 147 fprintf(stderr, "There are no quotas on this system\n"); 148 nolocalquota++; 149 } 150 if (argc == optind) { 151 showuid(getuid()); 152 exit(0); 153 } 154 for (i = optind; i < argc; i++) { 155 if (alldigits(argv[i])) { 156 showuid((uid_t)atoi(argv[i])); 157 } else 158 status |= showname(argv[i]); 159 } 160 __priv_relinquish(); 161 return (status); 162 } 163 164 static void 165 showuid(uid_t uid) 166 { 167 struct passwd *pwd = getpwuid(uid); 168 169 if (uid == 0) { 170 if (vflag) 171 printf("no disk quota for uid 0\n"); 172 return; 173 } 174 if (pwd == NULL) 175 showquotas(uid, "(no account)"); 176 else 177 showquotas(uid, pwd->pw_name); 178 } 179 180 int 181 showname(char *name) 182 { 183 struct passwd *pwd = getpwnam(name); 184 185 if (pwd == NULL) { 186 fprintf(stderr, "quota: %s: unknown user\n", name); 187 return (32); 188 } 189 if (pwd->pw_uid == 0) { 190 if (vflag) 191 printf("no disk quota for %s (uid 0)\n", name); 192 return (0); 193 } 194 showquotas(pwd->pw_uid, name); 195 return (0); 196 } 197 198 static void 199 showquotas(uid_t uid, char *name) 200 { 201 struct mnttab mnt; 202 FILE *mtab; 203 struct dqblk dqblk; 204 uid_t myuid; 205 struct failed_srv { 206 char *serv_name; 207 struct failed_srv *next; 208 }; 209 struct failed_srv *failed_srv_list = NULL; 210 int rc; 211 char my_zonename[ZONENAME_MAX]; 212 zoneid_t my_zoneid = getzoneid(); 213 214 myuid = getuid(); 215 if (uid != myuid && myuid != 0) { 216 printf("quota: %s (uid %d): permission denied\n", name, uid); 217 exit(32); 218 } 219 220 memset(my_zonename, '\0', ZONENAME_MAX); 221 getzonenamebyid(my_zoneid, my_zonename, ZONENAME_MAX); 222 223 if (vflag) 224 heading(uid, name); 225 mtab = fopen(MNTTAB, "r"); 226 while (getmntent(mtab, &mnt) == NULL) { 227 if (strcmp(mnt.mnt_fstype, MNTTYPE_UFS) == 0) { 228 if (nolocalquota || 229 (quotactl(Q_GETQUOTA, 230 mnt.mnt_mountp, uid, &dqblk) != 0 && 231 !(vflag && getdiskquota(&mnt, uid, &dqblk)))) 232 continue; 233 } else if (strcmp(mnt.mnt_fstype, MNTTYPE_NFS) == 0) { 234 235 struct replica *rl; 236 int count; 237 char *mntopt = NULL; 238 239 /* 240 * Skip checking quotas for file systems mounted 241 * in other zones. Zone names will be passed in 242 * following format from hasmntopt(): 243 * "zone=<zone-name>,<mnt options...>" 244 */ 245 if ((mntopt = hasmntopt(&mnt, MNTOPT_ZONE)) && 246 (my_zonename[0] != '\0')) { 247 mntopt += strcspn(mntopt, "="); 248 if (strncmp(++mntopt, my_zonename, 249 strcspn(mntopt, ",")) != 0) 250 continue; 251 } 252 253 if (hasopt(MNTOPT_NOQUOTA, mnt.mnt_mntopts)) 254 continue; 255 256 /* 257 * Skip quota processing if mounted with public 258 * option. We are not likely to be able to pierce 259 * a fire wall to contact the quota server. 260 */ 261 if (hasopt(MNTOPT_PUBLIC, mnt.mnt_mntopts)) 262 continue; 263 264 rl = parse_replica(mnt.mnt_special, &count); 265 266 if (rl == NULL) { 267 268 if (count < 0) 269 fprintf(stderr, "cannot find hostname " 270 "and/or pathname for %s\n", 271 mnt.mnt_mountp); 272 else 273 fprintf(stderr, "no memory to parse " 274 "mnttab entry for %s\n", 275 mnt.mnt_mountp); 276 continue; 277 } 278 279 /* 280 * We skip quota reporting on mounts with replicas 281 * for the following reasons: 282 * 283 * (1) Very little point in reporting quotas on 284 * a set of read-only replicas ... how will the 285 * user correct the problem? 286 * 287 * (2) Which replica would we report the quota 288 * for? If we pick the current replica, what 289 * happens when a fail over event occurs? The 290 * next time quota is run, the quota will look 291 * all different, or there won't even be one. 292 * This has the potential to break scripts. 293 * 294 * If we prnt quouta for all replicas, how do 295 * we present the output without breaking scripts? 296 */ 297 298 if (count > 1) { 299 free_replica(rl, count); 300 continue; 301 } 302 303 /* 304 * Skip file systems mounted using public fh. 305 * We are not likely to be able to pierce 306 * a fire wall to contact the quota server. 307 */ 308 if (strcmp(rl[0].host, "nfs") == 0 && 309 strncmp(rl[0].path, "//", 2) == 0) { 310 free_replica(rl, count); 311 continue; 312 } 313 314 /* 315 * Skip getting quotas from failing servers 316 */ 317 if (failed_srv_list != NULL) { 318 struct failed_srv *tmp_list; 319 int found_failed = 0; 320 size_t len = strlen(rl[0].host); 321 322 tmp_list = failed_srv_list; 323 do { 324 if (strncasecmp(rl[0].host, 325 tmp_list->serv_name, len) == 0) { 326 found_failed = 1; 327 break; 328 } 329 } while ((tmp_list = tmp_list->next) != NULL); 330 if (found_failed) { 331 free_replica(rl, count); 332 continue; 333 } 334 } 335 336 rc = getnfsquota(rl[0].host, rl[0].path, uid, &dqblk); 337 if (rc != RPC_SUCCESS) { 338 size_t len; 339 struct failed_srv *tmp_srv; 340 341 /* 342 * Failed to get quota from this server. Add 343 * this server to failed_srv_list and skip 344 * getting quotas for other mounted filesystems 345 * from this server. 346 */ 347 if (rc == RPC_TIMEDOUT || rc == RPC_CANTSEND) { 348 len = strlen(rl[0].host); 349 tmp_srv = (struct failed_srv *)malloc( 350 sizeof (struct failed_srv)); 351 tmp_srv->serv_name = (char *)malloc( 352 len * sizeof (char) + 1); 353 strncpy(tmp_srv->serv_name, rl[0].host, 354 len); 355 tmp_srv->serv_name[len] = '\0'; 356 357 tmp_srv->next = failed_srv_list; 358 failed_srv_list = tmp_srv; 359 } 360 361 free_replica(rl, count); 362 continue; 363 } 364 365 free_replica(rl, count); 366 } else { 367 continue; 368 } 369 if (dqblk.dqb_bsoftlimit == 0 && dqblk.dqb_bhardlimit == 0 && 370 dqblk.dqb_fsoftlimit == 0 && dqblk.dqb_fhardlimit == 0) 371 continue; 372 if (vflag) 373 prquota(&mnt, &dqblk); 374 else 375 warn(&mnt, &dqblk); 376 } 377 378 /* 379 * Free list of failed servers 380 */ 381 while (failed_srv_list != NULL) { 382 struct failed_srv *tmp_srv = failed_srv_list; 383 384 failed_srv_list = failed_srv_list->next; 385 free(tmp_srv->serv_name); 386 free(tmp_srv); 387 } 388 389 fclose(mtab); 390 } 391 392 static void 393 warn(struct mnttab *mntp, struct dqblk *dqp) 394 { 395 struct timeval tv; 396 397 time(&(tv.tv_sec)); 398 tv.tv_usec = 0; 399 if (dqp->dqb_bhardlimit && 400 dqp->dqb_curblocks >= dqp->dqb_bhardlimit) { 401 printf("Block limit reached on %s\n", mntp->mnt_mountp); 402 } else if (dqp->dqb_bsoftlimit && 403 dqp->dqb_curblocks >= dqp->dqb_bsoftlimit) { 404 if (dqp->dqb_btimelimit == 0) { 405 printf("Over disk quota on %s, remove %luK\n", 406 mntp->mnt_mountp, 407 kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1)); 408 } else if (dqp->dqb_btimelimit > tv.tv_sec) { 409 char btimeleft[80]; 410 411 fmttime(btimeleft, dqp->dqb_btimelimit - tv.tv_sec); 412 printf("Over disk quota on %s, remove %luK within %s\n", 413 mntp->mnt_mountp, 414 kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1), 415 btimeleft); 416 } else { 417 printf( 418 "Over disk quota on %s, time limit has expired, remove %luK\n", 419 mntp->mnt_mountp, 420 kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1)); 421 } 422 } 423 if (dqp->dqb_fhardlimit && 424 dqp->dqb_curfiles >= dqp->dqb_fhardlimit) { 425 printf("File count limit reached on %s\n", mntp->mnt_mountp); 426 } else if (dqp->dqb_fsoftlimit && 427 dqp->dqb_curfiles >= dqp->dqb_fsoftlimit) { 428 if (dqp->dqb_ftimelimit == 0) { 429 printf("Over file quota on %s, remove %lu file%s\n", 430 mntp->mnt_mountp, 431 dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1, 432 ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ? 433 "s" : "")); 434 } else if (dqp->dqb_ftimelimit > tv.tv_sec) { 435 char ftimeleft[80]; 436 437 fmttime(ftimeleft, dqp->dqb_ftimelimit - tv.tv_sec); 438 printf( 439 "Over file quota on %s, remove %lu file%s within %s\n", 440 mntp->mnt_mountp, 441 dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1, 442 ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ? 443 "s" : ""), ftimeleft); 444 } else { 445 printf( 446 "Over file quota on %s, time limit has expired, remove %lu file%s\n", 447 mntp->mnt_mountp, 448 dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1, 449 ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ? 450 "s" : "")); 451 } 452 } 453 } 454 455 static void 456 heading(uid_t uid, char *name) 457 { 458 printf("Disk quotas for %s (uid %ld):\n", name, (long)uid); 459 printf("%-12s %7s%7s%7s%12s%7s%7s%7s%12s\n", 460 "Filesystem", 461 "usage", 462 "quota", 463 "limit", 464 "timeleft", 465 "files", 466 "quota", 467 "limit", 468 "timeleft"); 469 } 470 471 static void 472 prquota(struct mnttab *mntp, struct dqblk *dqp) 473 { 474 struct timeval tv; 475 char ftimeleft[80], btimeleft[80]; 476 char *cp; 477 478 time(&(tv.tv_sec)); 479 tv.tv_usec = 0; 480 if (dqp->dqb_bsoftlimit && dqp->dqb_curblocks >= dqp->dqb_bsoftlimit) { 481 if (dqp->dqb_btimelimit == 0) { 482 strcpy(btimeleft, "NOT STARTED"); 483 } else if (dqp->dqb_btimelimit > tv.tv_sec) { 484 fmttime(btimeleft, dqp->dqb_btimelimit - tv.tv_sec); 485 } else { 486 strcpy(btimeleft, "EXPIRED"); 487 } 488 } else { 489 btimeleft[0] = '\0'; 490 } 491 if (dqp->dqb_fsoftlimit && dqp->dqb_curfiles >= dqp->dqb_fsoftlimit) { 492 if (dqp->dqb_ftimelimit == 0) { 493 strcpy(ftimeleft, "NOT STARTED"); 494 } else if (dqp->dqb_ftimelimit > tv.tv_sec) { 495 fmttime(ftimeleft, dqp->dqb_ftimelimit - tv.tv_sec); 496 } else { 497 strcpy(ftimeleft, "EXPIRED"); 498 } 499 } else { 500 ftimeleft[0] = '\0'; 501 } 502 if (strlen(mntp->mnt_mountp) > 12) { 503 printf("%s\n", mntp->mnt_mountp); 504 cp = ""; 505 } else { 506 cp = mntp->mnt_mountp; 507 } 508 printf("%-12.12s %7d %6d %6d %11s %6d %6d %6d %11s\n", 509 cp, 510 kb(dqp->dqb_curblocks), 511 kb(dqp->dqb_bsoftlimit), 512 kb(dqp->dqb_bhardlimit), 513 btimeleft, 514 dqp->dqb_curfiles, 515 dqp->dqb_fsoftlimit, 516 dqp->dqb_fhardlimit, 517 ftimeleft); 518 } 519 520 static void 521 fmttime(char *buf, long time) 522 { 523 int i; 524 static struct { 525 int c_secs; /* conversion units in secs */ 526 char *c_str; /* unit string */ 527 } cunits [] = { 528 {60*60*24*28, "months"}, 529 {60*60*24*7, "weeks"}, 530 {60*60*24, "days"}, 531 {60*60, "hours"}, 532 {60, "mins"}, 533 {1, "secs"} 534 }; 535 536 if (time <= 0) { 537 strcpy(buf, "EXPIRED"); 538 return; 539 } 540 for (i = 0; i < sizeof (cunits)/sizeof (cunits[0]); i++) { 541 if (time >= cunits[i].c_secs) 542 break; 543 } 544 sprintf(buf, "%.1f %s", (double)time/cunits[i].c_secs, cunits[i].c_str); 545 } 546 547 int 548 alldigits(char *s) 549 { 550 int c; 551 552 c = *s++; 553 do { 554 if (!isdigit(c)) 555 return (0); 556 } while (c = *s++); 557 return (1); 558 } 559 560 int 561 getdiskquota(struct mnttab *mntp, uid_t uid, struct dqblk *dqp) 562 { 563 int fd; 564 dev_t fsdev; 565 struct stat64 statb; 566 char qfilename[MAXPATHLEN]; 567 568 if (stat64(mntp->mnt_special, &statb) < 0 || 569 (statb.st_mode & S_IFMT) != S_IFBLK) 570 return (0); 571 fsdev = statb.st_rdev; 572 (void) snprintf(qfilename, sizeof (qfilename), "%s/%s", 573 mntp->mnt_mountp, QFNAME); 574 if (stat64(qfilename, &statb) < 0 || statb.st_dev != fsdev) 575 return (0); 576 (void) __priv_bracket(PRIV_ON); 577 fd = open64(qfilename, O_RDONLY); 578 (void) __priv_bracket(PRIV_OFF); 579 if (fd < 0) 580 return (0); 581 (void) llseek(fd, (offset_t)dqoff(uid), L_SET); 582 switch (read(fd, dqp, sizeof (struct dqblk))) { 583 case 0: /* EOF */ 584 /* 585 * Convert implicit 0 quota (EOF) 586 * into an explicit one (zero'ed dqblk). 587 */ 588 memset((caddr_t)dqp, 0, sizeof (struct dqblk)); 589 break; 590 591 case sizeof (struct dqblk): /* OK */ 592 break; 593 594 default: /* ERROR */ 595 close(fd); 596 return (0); 597 } 598 close(fd); 599 return (1); 600 } 601 602 int 603 quotactl(int cmd, char *mountp, uid_t uid, caddr_t addr) 604 { 605 int fd; 606 int status; 607 struct quotctl quota; 608 char qfile[MAXPATHLEN]; 609 610 FILE *fstab; 611 struct mnttab mnt; 612 613 614 if ((mountp == NULL) && (cmd == Q_ALLSYNC)) { 615 /* 616 * Find the mount point of any mounted file system. This is 617 * because the ioctl that implements the quotactl call has 618 * to go to a real file, and not to the block device. 619 */ 620 if ((fstab = fopen(MNTTAB, "r")) == NULL) { 621 fprintf(stderr, "%s: ", MNTTAB); 622 perror("open"); 623 exit(32); 624 } 625 fd = -1; 626 while ((status = getmntent(fstab, &mnt)) == NULL) { 627 if (strcmp(mnt.mnt_fstype, MNTTYPE_UFS) != 0 || 628 hasopt(MNTOPT_RO, mnt.mnt_mntopts)) 629 continue; 630 if ((strlcpy(qfile, mnt.mnt_mountp, 631 sizeof (qfile)) >= sizeof (qfile)) || 632 (strlcat(qfile, "/" QFNAME, sizeof (qfile)) >= 633 sizeof (qfile))) { 634 continue; 635 } 636 (void) __priv_bracket(PRIV_ON); 637 fd = open64(qfile, O_RDONLY); 638 (void) __priv_bracket(PRIV_OFF); 639 if (fd != -1) 640 break; 641 } 642 fclose(fstab); 643 if (fd == -1) { 644 errno = ENOENT; 645 return (-1); 646 } 647 } else { 648 if (mountp == NULL || mountp[0] == '\0') { 649 errno = ENOENT; 650 return (-1); 651 } 652 if ((strlcpy(qfile, mountp, sizeof (qfile)) >= sizeof 653 (qfile)) || 654 (strlcat(qfile, "/" QFNAME, sizeof (qfile)) >= sizeof 655 (qfile))) { 656 errno = ENOENT; 657 return (-1); 658 } 659 (void) __priv_bracket(PRIV_ON); 660 fd = open64(qfile, O_RDONLY); 661 (void) __priv_bracket(PRIV_OFF); 662 if (fd < 0) 663 return (-1); 664 } /* else */ 665 quota.op = cmd; 666 quota.uid = uid; 667 quota.addr = addr; 668 status = ioctl(fd, Q_QUOTACTL, "a); 669 if (fd != 0) 670 close(fd); 671 return (status); 672 } 673 674 675 /* 676 * Return 1 if opt appears in optlist 677 */ 678 int 679 hasopt(char *opt, char *optlist) 680 { 681 char *value; 682 char *opts[2]; 683 684 opts[0] = opt; 685 opts[1] = NULL; 686 687 if (optlist == NULL) 688 return (0); 689 while (*optlist != '\0') { 690 if (getsubopt(&optlist, opts, &value) == 0) 691 return (1); 692 } 693 return (0); 694 } 695 696 /* 697 * If there are no quotas available, then getnfsquota() returns 698 * RPC_SYSTEMERROR to caller. 699 */ 700 static int 701 getnfsquota(char *hostp, char *path, uid_t uid, struct dqblk *dqp) 702 { 703 struct getquota_args gq_args; 704 struct getquota_rslt gq_rslt; 705 struct rquota *rquota; 706 extern char *strchr(); 707 int rpc_err; 708 709 gq_args.gqa_pathp = path; 710 gq_args.gqa_uid = uid; 711 rpc_err = callaurpc(hostp, RQUOTAPROG, RQUOTAVERS, 712 (vflag? RQUOTAPROC_GETQUOTA: RQUOTAPROC_GETACTIVEQUOTA), 713 xdr_getquota_args, &gq_args, xdr_getquota_rslt, &gq_rslt); 714 if (rpc_err != RPC_SUCCESS) { 715 return (rpc_err); 716 } 717 switch (gq_rslt.status) { 718 case Q_OK: 719 { 720 struct timeval tv; 721 u_longlong_t limit; 722 723 rquota = &gq_rslt.getquota_rslt_u.gqr_rquota; 724 725 if (!vflag && rquota->rq_active == FALSE) { 726 return (RPC_SYSTEMERROR); 727 } 728 gettimeofday(&tv, NULL); 729 limit = (u_longlong_t)(rquota->rq_bhardlimit) * 730 rquota->rq_bsize / DEV_BSIZE; 731 dqp->dqb_bhardlimit = limit; 732 limit = (u_longlong_t)(rquota->rq_bsoftlimit) * 733 rquota->rq_bsize / DEV_BSIZE; 734 dqp->dqb_bsoftlimit = limit; 735 limit = (u_longlong_t)(rquota->rq_curblocks) * 736 rquota->rq_bsize / DEV_BSIZE; 737 dqp->dqb_curblocks = limit; 738 dqp->dqb_fhardlimit = rquota->rq_fhardlimit; 739 dqp->dqb_fsoftlimit = rquota->rq_fsoftlimit; 740 dqp->dqb_curfiles = rquota->rq_curfiles; 741 dqp->dqb_btimelimit = 742 tv.tv_sec + rquota->rq_btimeleft; 743 dqp->dqb_ftimelimit = 744 tv.tv_sec + rquota->rq_ftimeleft; 745 return (RPC_SUCCESS); 746 } 747 748 case Q_NOQUOTA: 749 return (RPC_SYSTEMERROR); 750 751 case Q_EPERM: 752 fprintf(stderr, "quota permission error, host: %s\n", hostp); 753 return (RPC_AUTHERROR); 754 755 default: 756 fprintf(stderr, "bad rpc result, host: %s\n", hostp); 757 return (RPC_CANTDECODEARGS); 758 } 759 760 /* NOTREACHED */ 761 } 762 763 int 764 callaurpc(char *host, int prognum, int versnum, int procnum, 765 xdrproc_t inproc, char *in, xdrproc_t outproc, char *out) 766 { 767 static enum clnt_stat clnt_stat; 768 struct timeval tottimeout = {20, 0}; 769 770 static CLIENT *cl = NULL; 771 static int oldprognum, oldversnum; 772 static char oldhost[MAXHOSTNAMELEN+1]; 773 774 /* 775 * Cache the client handle in case there are lots 776 * of entries in the /etc/mnttab for the same 777 * server. If the server returns an error, don't 778 * make further calls. 779 */ 780 if (cl == NULL || oldprognum != prognum || oldversnum != versnum || 781 strcmp(oldhost, host) != 0) { 782 if (cl) { 783 clnt_destroy(cl); 784 cl = NULL; 785 } 786 cl = clnt_create_timed(host, prognum, versnum, "udp", 787 &tottimeout); 788 if (cl == NULL) 789 return ((int)RPC_TIMEDOUT); 790 if ((cl->cl_auth = authunix_create_default()) == NULL) { 791 clnt_destroy(cl); 792 return (RPC_CANTSEND); 793 } 794 oldprognum = prognum; 795 oldversnum = versnum; 796 (void) strcpy(oldhost, host); 797 clnt_stat = RPC_SUCCESS; 798 } 799 800 if (clnt_stat != RPC_SUCCESS) 801 return ((int)clnt_stat); /* don't bother retrying */ 802 803 clnt_stat = clnt_call(cl, procnum, inproc, in, 804 outproc, out, tottimeout); 805 806 return ((int)clnt_stat); 807 } 808