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