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