1 /* 2 * Copyright (c) 1980, 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Robert Elz at The University of Melbourne. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 static const char copyright[] = 39 "@(#) Copyright (c) 1980, 1990, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41 #endif 42 43 #ifndef lint 44 static const char sccsid[] = "from: @(#)quota.c 8.1 (Berkeley) 6/6/93"; 45 #endif /* not lint */ 46 47 /* 48 * Disk quota reporting program. 49 */ 50 #include <sys/cdefs.h> 51 __FBSDID("$FreeBSD$"); 52 53 #include <sys/param.h> 54 #include <sys/types.h> 55 #include <sys/file.h> 56 #include <sys/stat.h> 57 #include <sys/mount.h> 58 #include <sys/socket.h> 59 60 #include <rpc/rpc.h> 61 #include <rpc/pmap_prot.h> 62 #include <rpcsvc/rquota.h> 63 64 #include <ufs/ufs/quota.h> 65 66 #include <ctype.h> 67 #include <err.h> 68 #include <fstab.h> 69 #include <grp.h> 70 #include <libutil.h> 71 #include <netdb.h> 72 #include <pwd.h> 73 #include <stdio.h> 74 #include <stdint.h> 75 #include <stdlib.h> 76 #include <string.h> 77 #include <time.h> 78 #include <unistd.h> 79 80 const char *qfname = QUOTAFILENAME; 81 const char *qfextension[] = INITQFNAMES; 82 83 struct quotause { 84 struct quotause *next; 85 long flags; 86 struct dqblk dqblk; 87 char fsname[MAXPATHLEN + 1]; 88 }; 89 90 static char *timeprt(time_t seconds); 91 static struct quotause *getprivs(long id, int quotatype); 92 static void usage(void); 93 static int showuid(u_long uid); 94 static int showgid(u_long gid); 95 static int showusrname(char *name); 96 static int showgrpname(char *name); 97 static int showquotas(int type, u_long id, const char *name); 98 static void showrawquotas(int type, u_long id, struct quotause *qup); 99 static void heading(int type, u_long id, const char *name, const char *tag); 100 static int ufshasquota(struct fstab *fs, int type, char **qfnamep); 101 static int getufsquota(struct fstab *fs, struct quotause *qup, long id, 102 int quotatype); 103 static int getnfsquota(struct statfs *fst, struct quotause *qup, long id, 104 int quotatype); 105 static int callaurpc(char *host, int prognum, int versnum, int procnum, 106 xdrproc_t inproc, char *in, xdrproc_t outproc, char *out); 107 static int alldigits(char *s); 108 109 int hflag; 110 int lflag; 111 int rflag; 112 int qflag; 113 int vflag; 114 char *filename = NULL; 115 116 int 117 main(int argc, char *argv[]) 118 { 119 int ngroups; 120 long ngroups_max; 121 gid_t mygid, *gidset; 122 int i, ch, gflag = 0, uflag = 0, errflag = 0; 123 124 while ((ch = getopt(argc, argv, "f:ghlrquv")) != -1) { 125 switch(ch) { 126 case 'f': 127 filename = optarg; 128 break; 129 case 'g': 130 gflag++; 131 break; 132 case 'h': 133 hflag++; 134 break; 135 case 'l': 136 lflag++; 137 break; 138 case 'q': 139 qflag++; 140 break; 141 case 'r': 142 rflag++; 143 break; 144 case 'u': 145 uflag++; 146 break; 147 case 'v': 148 vflag++; 149 break; 150 default: 151 usage(); 152 } 153 } 154 argc -= optind; 155 argv += optind; 156 if (!uflag && !gflag) 157 uflag++; 158 if (argc == 0) { 159 if (uflag) 160 errflag += showuid(getuid()); 161 if (gflag) { 162 mygid = getgid(); 163 ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1; 164 if ((gidset = malloc(sizeof(gid_t) * ngroups_max)) 165 == NULL) 166 err(1, "malloc"); 167 ngroups = getgroups(ngroups_max, gidset); 168 if (ngroups < 0) 169 err(1, "getgroups"); 170 errflag += showgid(mygid); 171 for (i = 0; i < ngroups; i++) 172 if (gidset[i] != mygid) 173 errflag += showgid(gidset[i]); 174 free(gidset); 175 } 176 return(errflag); 177 } 178 if (uflag && gflag) 179 usage(); 180 if (uflag) { 181 for (; argc > 0; argc--, argv++) { 182 if (alldigits(*argv)) 183 errflag += showuid(atoi(*argv)); 184 else 185 errflag += showusrname(*argv); 186 } 187 return(errflag); 188 } 189 if (gflag) { 190 for (; argc > 0; argc--, argv++) { 191 if (alldigits(*argv)) 192 errflag += showgid(atoi(*argv)); 193 else 194 errflag += showgrpname(*argv); 195 } 196 } 197 return(errflag); 198 } 199 200 static void 201 usage(void) 202 { 203 204 fprintf(stderr, "%s\n%s\n%s\n", 205 "usage: quota [-ghlu] [-f path] [-v | -q | -r]", 206 " quota [-hlu] [-f path] [-v | -q | -r] user ...", 207 " quota -g [-hl] [-f path] [-v | -q | -r] group ..."); 208 exit(1); 209 } 210 211 /* 212 * Print out quotas for a specified user identifier. 213 */ 214 static int 215 showuid(u_long uid) 216 { 217 struct passwd *pwd = getpwuid(uid); 218 const char *name; 219 220 if (pwd == NULL) 221 name = "(no account)"; 222 else 223 name = pwd->pw_name; 224 return(showquotas(USRQUOTA, uid, name)); 225 } 226 227 /* 228 * Print out quotas for a specifed user name. 229 */ 230 static int 231 showusrname(char *name) 232 { 233 struct passwd *pwd = getpwnam(name); 234 235 if (pwd == NULL) { 236 warnx("%s: unknown user", name); 237 return(1); 238 } 239 return(showquotas(USRQUOTA, pwd->pw_uid, name)); 240 } 241 242 /* 243 * Print out quotas for a specified group identifier. 244 */ 245 static int 246 showgid(u_long gid) 247 { 248 struct group *grp = getgrgid(gid); 249 const char *name; 250 251 if (grp == NULL) 252 name = "(no entry)"; 253 else 254 name = grp->gr_name; 255 return(showquotas(GRPQUOTA, gid, name)); 256 } 257 258 /* 259 * Print out quotas for a specifed group name. 260 */ 261 static int 262 showgrpname(char *name) 263 { 264 struct group *grp = getgrnam(name); 265 266 if (grp == NULL) { 267 warnx("%s: unknown group", name); 268 return(1); 269 } 270 return(showquotas(GRPQUOTA, grp->gr_gid, name)); 271 } 272 273 static void 274 prthumanval(int len, int64_t bytes) 275 { 276 char buf[len + 1]; 277 278 humanize_number(buf, sizeof(buf), bytes, "", HN_AUTOSCALE, 279 HN_B | HN_NOSPACE | HN_DECIMAL); 280 281 (void)printf(" %*s", len, buf); 282 } 283 284 static int 285 showquotas(int type, u_long id, const char *name) 286 { 287 struct quotause *qup; 288 struct quotause *quplist; 289 const char *msgi, *msgb; 290 const char *nam; 291 char *bgrace = NULL, *igrace = NULL; 292 int lines = 0, overquota = 0; 293 static time_t now; 294 295 if (now == 0) 296 time(&now); 297 quplist = getprivs(id, type); 298 for (qup = quplist; qup; qup = qup->next) { 299 msgi = (char *)0; 300 if (qup->dqblk.dqb_ihardlimit && 301 qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit) { 302 overquota++; 303 msgi = "File limit reached on"; 304 } 305 else if (qup->dqblk.dqb_isoftlimit && 306 qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) { 307 overquota++; 308 if (qup->dqblk.dqb_itime > now) 309 msgi = "In file grace period on"; 310 else 311 msgi = "Over file quota on"; 312 } 313 msgb = (char *)0; 314 if (qup->dqblk.dqb_bhardlimit && 315 qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit) { 316 overquota++; 317 msgb = "Block limit reached on"; 318 } 319 else if (qup->dqblk.dqb_bsoftlimit && 320 qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) { 321 overquota++; 322 if (qup->dqblk.dqb_btime > now) 323 msgb = "In block grace period on"; 324 else 325 msgb = "Over block quota on"; 326 } 327 if (rflag) { 328 showrawquotas(type, id, qup); 329 continue; 330 } 331 if (!vflag && 332 qup->dqblk.dqb_isoftlimit == 0 && 333 qup->dqblk.dqb_ihardlimit == 0 && 334 qup->dqblk.dqb_bsoftlimit == 0 && 335 qup->dqblk.dqb_bhardlimit == 0) 336 continue; 337 if (qflag) { 338 if ((msgi != (char *)0 || msgb != (char *)0) && 339 lines++ == 0) 340 heading(type, id, name, ""); 341 if (msgi != (char *)0) 342 printf("\t%s %s\n", msgi, qup->fsname); 343 if (msgb != (char *)0) 344 printf("\t%s %s\n", msgb, qup->fsname); 345 continue; 346 } 347 if (vflag || 348 qup->dqblk.dqb_curblocks || 349 qup->dqblk.dqb_curinodes) { 350 if (lines++ == 0) 351 heading(type, id, name, ""); 352 nam = qup->fsname; 353 if (strlen(qup->fsname) > 15) { 354 printf("%s\n", qup->fsname); 355 nam = ""; 356 } 357 printf("%15s", nam); 358 if (hflag) { 359 printf(" "); 360 prthumanval(4, dbtob(qup->dqblk.dqb_curblocks)); 361 printf("%c ", (msgb == (char *)0) ? ' ' : '*'); 362 prthumanval(4, dbtob(qup->dqblk.dqb_bsoftlimit)); 363 printf(" "); 364 prthumanval(4, dbtob(qup->dqblk.dqb_bhardlimit)); 365 } else { 366 printf(" %7ju%c %6ju %7ju", 367 (uintmax_t)(dbtob(qup->dqblk.dqb_curblocks) 368 / 1024), 369 (msgb == NULL) ? ' ' : '*', 370 (uintmax_t)(dbtob(qup->dqblk.dqb_bsoftlimit) 371 / 1024), 372 (uintmax_t)(dbtob(qup->dqblk.dqb_bhardlimit) 373 / 1024)); 374 } 375 if (msgb != NULL) 376 bgrace = timeprt(qup->dqblk.dqb_btime); 377 if (msgi != NULL) 378 igrace = timeprt(qup->dqblk.dqb_itime); 379 printf(" %7s %7ju%c %6ju %7ju %7s\n", 380 (msgb == NULL) ? "" : bgrace, 381 (uintmax_t)qup->dqblk.dqb_curinodes, 382 (msgi == NULL) ? ' ' : '*', 383 (uintmax_t)qup->dqblk.dqb_isoftlimit, 384 (uintmax_t)qup->dqblk.dqb_ihardlimit, 385 (msgi == NULL) ? "" : igrace 386 ); 387 if (msgb != NULL) 388 free(bgrace); 389 if (msgi != NULL) 390 free(igrace); 391 continue; 392 } 393 } 394 if (!qflag && !rflag && lines == 0) 395 heading(type, id, name, "none"); 396 return(overquota); 397 } 398 399 static void 400 showrawquotas(int type, u_long id, struct quotause *qup) 401 { 402 time_t tt; 403 printf("Raw %s quota information for id %lu on %s\n", 404 type == USRQUOTA ? "user" : "group", id, qup->fsname); 405 printf("block hard limit: %ju\n", (uintmax_t)qup->dqblk.dqb_bhardlimit); 406 printf("block soft limit: %ju\n", (uintmax_t)qup->dqblk.dqb_bsoftlimit); 407 printf("current block count: %ju\n", (uintmax_t)qup->dqblk.dqb_curblocks); 408 printf("i-node hard limit: %ju\n", (uintmax_t)qup->dqblk.dqb_ihardlimit); 409 printf("i-node soft limit: %ju\n", (uintmax_t)qup->dqblk.dqb_isoftlimit); 410 printf("current i-node count: %ju\n", (uintmax_t)qup->dqblk.dqb_curinodes); 411 printf("block grace time: %jd", (intmax_t)qup->dqblk.dqb_btime); 412 if (qup->dqblk.dqb_btime != 0) { 413 tt = qup->dqblk.dqb_btime; 414 printf(" %s", ctime(&tt)); 415 } else 416 printf("\n"); 417 printf("i-node grace time: %jd", (intmax_t)qup->dqblk.dqb_itime); 418 if (qup->dqblk.dqb_itime != 0) { 419 tt = qup->dqblk.dqb_itime; 420 printf(" %s", ctime(&tt)); 421 } else 422 printf("\n"); 423 } 424 425 426 static void 427 heading(int type, u_long id, const char *name, const char *tag) 428 { 429 430 printf("Disk quotas for %s %s (%cid %lu): %s\n", qfextension[type], 431 name, *qfextension[type], id, tag); 432 if (!qflag && tag[0] == '\0') { 433 printf("%15s %7s %6s %7s %7s %7s %6s %7s %7s\n" 434 , "Filesystem" 435 , "usage" 436 , "quota" 437 , "limit" 438 , "grace" 439 , "files" 440 , "quota" 441 , "limit" 442 , "grace" 443 ); 444 } 445 } 446 447 /* 448 * Calculate the grace period and return a printable string for it. 449 */ 450 static char * 451 timeprt(time_t seconds) 452 { 453 time_t hours, minutes; 454 char *buf; 455 static time_t now; 456 457 if (now == 0) 458 time(&now); 459 if (now > seconds) { 460 return strdup("none"); 461 } 462 seconds -= now; 463 minutes = (seconds + 30) / 60; 464 hours = (minutes + 30) / 60; 465 if (hours >= 36) { 466 if (asprintf(&buf, "%lddays", ((long)hours + 12) / 24) < 0) 467 errx(1, "asprintf failed in timeprt(1)"); 468 return (buf); 469 } 470 if (minutes >= 60) { 471 if (asprintf(&buf, "%2ld:%ld", (long)minutes / 60, 472 (long)minutes % 60) < 0) 473 errx(1, "asprintf failed in timeprt(2)"); 474 return (buf); 475 } 476 if (asprintf(&buf, "%2ld", (long)minutes) < 0) 477 errx(1, "asprintf failed in timeprt(3)"); 478 return (buf); 479 } 480 481 /* 482 * Collect the requested quota information. 483 */ 484 static struct quotause * 485 getprivs(long id, int quotatype) 486 { 487 struct quotause *qup, *quptail = NULL; 488 struct fstab *fs; 489 struct quotause *quphead; 490 struct statfs *fst; 491 int nfst, i; 492 struct statfs sfb; 493 494 qup = quphead = (struct quotause *)0; 495 496 if (filename != NULL && statfs(filename, &sfb) != 0) 497 err(1, "cannot statfs %s", filename); 498 nfst = getmntinfo(&fst, MNT_NOWAIT); 499 if (nfst == 0) 500 errx(2, "no filesystems mounted!"); 501 setfsent(); 502 for (i=0; i<nfst; i++) { 503 if (qup == NULL) { 504 if ((qup = (struct quotause *)malloc(sizeof *qup)) 505 == NULL) 506 errx(2, "out of memory"); 507 } 508 /* 509 * See if the user requested a specific file system 510 * or specified a file inside a mounted file system. 511 */ 512 if (filename != NULL && 513 strcmp(sfb.f_mntonname, fst[i].f_mntonname) != 0) 514 continue; 515 if (strcmp(fst[i].f_fstypename, "nfs") == 0) { 516 if (lflag) 517 continue; 518 if (getnfsquota(&fst[i], qup, id, quotatype) == 0) 519 continue; 520 } else if (strcmp(fst[i].f_fstypename, "ufs") == 0) { 521 /* 522 * XXX 523 * UFS filesystems must be in /etc/fstab, and must 524 * indicate that they have quotas on (?!) This is quite 525 * unlike SunOS where quotas can be enabled/disabled 526 * on a filesystem independent of /etc/fstab, and it 527 * will still print quotas for them. 528 */ 529 if ((fs = getfsspec(fst[i].f_mntfromname)) == NULL) 530 continue; 531 if (getufsquota(fs, qup, id, quotatype) == 0) 532 continue; 533 } else 534 continue; 535 strcpy(qup->fsname, fst[i].f_mntonname); 536 if (quphead == NULL) 537 quphead = qup; 538 else 539 quptail->next = qup; 540 quptail = qup; 541 quptail->next = 0; 542 qup = NULL; 543 } 544 if (qup) 545 free(qup); 546 endfsent(); 547 return (quphead); 548 } 549 550 /* 551 * Check to see if a particular quota is to be enabled. 552 */ 553 static int 554 ufshasquota(struct fstab *fs, int type, char **qfnamep) 555 { 556 char *opt; 557 char *cp; 558 struct statfs sfb; 559 static char initname, usrname[100], grpname[100]; 560 static char buf[BUFSIZ]; 561 562 if (!initname) { 563 (void)snprintf(usrname, sizeof(usrname), "%s%s", 564 qfextension[USRQUOTA], qfname); 565 (void)snprintf(grpname, sizeof(grpname), "%s%s", 566 qfextension[GRPQUOTA], qfname); 567 initname = 1; 568 } 569 strcpy(buf, fs->fs_mntops); 570 for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 571 if ((cp = index(opt, '='))) 572 *cp++ = '\0'; 573 if (type == USRQUOTA && strcmp(opt, usrname) == 0) 574 break; 575 if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 576 break; 577 } 578 if (!opt) 579 return (0); 580 if (cp) 581 *qfnamep = cp; 582 else { 583 (void)snprintf(buf, sizeof(buf), "%s/%s.%s", fs->fs_file, 584 qfname, qfextension[type]); 585 *qfnamep = buf; 586 } 587 if (statfs(fs->fs_file, &sfb) != 0) { 588 warn("cannot statfs mount point %s", fs->fs_file); 589 return (0); 590 } 591 if (strcmp(fs->fs_file, sfb.f_mntonname)) { 592 warnx("%s not mounted for %s quotas", fs->fs_file, 593 type == USRQUOTA ? "user" : "group"); 594 return (0); 595 } 596 return (1); 597 } 598 599 static int 600 getufsquota(struct fstab *fs, struct quotause *qup, long id, int quotatype) 601 { 602 char *qfpathname; 603 int fd, qcmd; 604 605 qcmd = QCMD(Q_GETQUOTA, quotatype); 606 if (!ufshasquota(fs, quotatype, &qfpathname)) 607 return (0); 608 609 if (quotactl(fs->fs_file, qcmd, id, (char *)&qup->dqblk) != 0) { 610 if ((fd = open(qfpathname, O_RDONLY)) < 0) { 611 warn("%s", qfpathname); 612 return (0); 613 } 614 (void) lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET); 615 switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) { 616 case 0: /* EOF */ 617 /* 618 * Convert implicit 0 quota (EOF) 619 * into an explicit one (zero'ed dqblk) 620 */ 621 bzero((caddr_t)&qup->dqblk, sizeof(struct dqblk)); 622 break; 623 case sizeof(struct dqblk): /* OK */ 624 break; 625 default: /* ERROR */ 626 warn("read error: %s", qfpathname); 627 close(fd); 628 return (0); 629 } 630 close(fd); 631 } 632 return (1); 633 } 634 635 static int 636 getnfsquota(struct statfs *fst, struct quotause *qup, long id, int quotatype) 637 { 638 struct getquota_args gq_args; 639 struct getquota_rslt gq_rslt; 640 struct dqblk *dqp = &qup->dqblk; 641 struct timeval tv; 642 char *cp; 643 644 if (fst->f_flags & MNT_LOCAL) 645 return (0); 646 647 /* 648 * rpc.rquotad does not support group quotas 649 */ 650 if (quotatype != USRQUOTA) 651 return (0); 652 653 /* 654 * must be some form of "hostname:/path" 655 */ 656 cp = strchr(fst->f_mntfromname, ':'); 657 if (cp == NULL) { 658 warnx("cannot find hostname for %s", fst->f_mntfromname); 659 return (0); 660 } 661 662 *cp = '\0'; 663 if (*(cp+1) != '/') { 664 *cp = ':'; 665 return (0); 666 } 667 668 /* Avoid attempting the RPC for special amd(8) filesystems. */ 669 if (strncmp(fst->f_mntfromname, "pid", 3) == 0 && 670 strchr(fst->f_mntfromname, '@') != NULL) { 671 *cp = ':'; 672 return (0); 673 } 674 675 gq_args.gqa_pathp = cp + 1; 676 gq_args.gqa_uid = id; 677 if (callaurpc(fst->f_mntfromname, RQUOTAPROG, RQUOTAVERS, 678 RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_getquota_args, (char *)&gq_args, 679 (xdrproc_t)xdr_getquota_rslt, (char *)&gq_rslt) != 0) { 680 *cp = ':'; 681 return (0); 682 } 683 684 switch (gq_rslt.status) { 685 case Q_NOQUOTA: 686 break; 687 case Q_EPERM: 688 warnx("quota permission error, host: %s", 689 fst->f_mntfromname); 690 break; 691 case Q_OK: 692 gettimeofday(&tv, NULL); 693 /* blocks*/ 694 dqp->dqb_bhardlimit = 695 gq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit * 696 (gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE); 697 dqp->dqb_bsoftlimit = 698 gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit * 699 (gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE); 700 dqp->dqb_curblocks = 701 gq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks * 702 (gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE); 703 /* inodes */ 704 dqp->dqb_ihardlimit = 705 gq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit; 706 dqp->dqb_isoftlimit = 707 gq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit; 708 dqp->dqb_curinodes = 709 gq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles; 710 /* grace times */ 711 dqp->dqb_btime = 712 tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft; 713 dqp->dqb_itime = 714 tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft; 715 *cp = ':'; 716 return (1); 717 default: 718 warnx("bad rpc result, host: %s", fst->f_mntfromname); 719 break; 720 } 721 *cp = ':'; 722 return (0); 723 } 724 725 static int 726 callaurpc(char *host, int prognum, int versnum, int procnum, 727 xdrproc_t inproc, char *in, xdrproc_t outproc, char *out) 728 { 729 struct sockaddr_in server_addr; 730 enum clnt_stat clnt_stat; 731 struct hostent *hp; 732 struct timeval timeout, tottimeout; 733 734 CLIENT *client = NULL; 735 int sock = RPC_ANYSOCK; 736 737 if ((hp = gethostbyname(host)) == NULL) 738 return ((int) RPC_UNKNOWNHOST); 739 timeout.tv_usec = 0; 740 timeout.tv_sec = 6; 741 bcopy(hp->h_addr, &server_addr.sin_addr, 742 MIN(hp->h_length,(int)sizeof(server_addr.sin_addr))); 743 server_addr.sin_family = AF_INET; 744 server_addr.sin_port = 0; 745 746 if ((client = clntudp_create(&server_addr, prognum, 747 versnum, timeout, &sock)) == NULL) 748 return ((int) rpc_createerr.cf_stat); 749 750 client->cl_auth = authunix_create_default(); 751 tottimeout.tv_sec = 25; 752 tottimeout.tv_usec = 0; 753 clnt_stat = clnt_call(client, procnum, inproc, in, 754 outproc, out, tottimeout); 755 756 return ((int) clnt_stat); 757 } 758 759 static int 760 alldigits(char *s) 761 { 762 int c; 763 764 c = *s++; 765 do { 766 if (!isdigit(c)) 767 return (0); 768 } while ((c = *s++)); 769 return (1); 770 } 771