Annotation of src/usr.bin/quota/quota.c, Revision 1.15
1.15 ! pjanzen 1: /* $OpenBSD: quota.c,v 1.14 2000/02/01 03:23:36 deraadt 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.15 ! pjanzen 47: static char rcsid[] = "$OpenBSD: quota.c,v 1.14 2000/02/01 03:23:36 deraadt 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: }
373: printf("%15s%8d%c%7d%8d%8s"
1.15 ! pjanzen 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) ? ""
! 383: : timeprt(qup->dqblk.dqb_btime));
1.1 deraadt 384: printf("%8d%c%7d%8d%8s\n"
1.15 ! pjanzen 385: , qup->dqblk.dqb_curinodes
! 386: , (msgi == (char *)0) ? ' ' : '*'
! 387: , qup->dqblk.dqb_isoftlimit
! 388: , qup->dqblk.dqb_ihardlimit
! 389: , (msgi == (char *)0) ? ""
! 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') {
409: printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n"
1.15 ! pjanzen 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: /*
424: * Calculate the grace period and return a printable string for it.
425: */
426: char *
427: timeprt(seconds)
428: time_t seconds;
429: {
430: time_t hours, minutes;
431: static char buf[20];
432: static time_t now;
433:
434: if (now == 0)
435: time(&now);
436: if (now > seconds)
437: return ("none");
438: seconds -= now;
439: minutes = (seconds + 30) / 60;
440: hours = (minutes + 30) / 60;
441: if (hours >= 36) {
1.15 ! pjanzen 442: (void)snprintf(buf, sizeof buf, "%ddays",
! 443: (int)((hours + 12) / 24));
1.1 deraadt 444: return (buf);
445: }
446: if (minutes >= 60) {
1.15 ! pjanzen 447: (void)snprintf(buf, sizeof buf, "%2d:%d",
! 448: (int)(minutes / 60), (int)(minutes % 60));
1.1 deraadt 449: return (buf);
450: }
1.15 ! pjanzen 451: (void)snprintf(buf, sizeof buf, "%2d", (int)minutes);
1.1 deraadt 452: return (buf);
453: }
454:
455: /*
456: * Collect the requested quota information.
457: */
458: struct quotause *
459: getprivs(id, quotatype)
1.15 ! pjanzen 460: long id;
1.1 deraadt 461: int quotatype;
462: {
1.15 ! pjanzen 463: struct quotause *qup, *quptail;
! 464: struct fstab *fs;
1.1 deraadt 465: struct quotause *quphead;
466: struct statfs *fst;
467: int nfst, i;
468:
1.15 ! pjanzen 469: qup = quphead = NULL;
1.1 deraadt 470:
471: nfst = getmntinfo(&fst, MNT_WAIT);
1.15 ! pjanzen 472: if (nfst == 0)
! 473: errx(2, "no filesystems mounted!");
1.1 deraadt 474: setfsent();
1.15 ! pjanzen 475: for (i = 0; i < nfst; i++) {
1.1 deraadt 476: if (qup == NULL) {
1.15 ! pjanzen 477: if ((qup = (struct quotause *)malloc(sizeof *qup)) == NULL)
! 478: errx(2, "out of memory");
1.1 deraadt 479: }
480: if (strncmp(fst[i].f_fstypename, "nfs", MFSNAMELEN) == 0) {
481: if (getnfsquota(&fst[i], NULL, qup, id, quotatype) == 0)
482: continue;
1.4 deraadt 483: } else if (!strncmp(fst[i].f_fstypename, "ffs", MFSNAMELEN) ||
484: !strncmp(fst[i].f_fstypename, "ufs", MFSNAMELEN) ||
485: !strncmp(fst[i].f_fstypename, "mfs", MFSNAMELEN)) {
1.1 deraadt 486: /*
487: * XXX
488: * UFS filesystems must be in /etc/fstab, and must
489: * indicate that they have quotas on (?!) This is quite
490: * unlike SunOS where quotas can be enabled/disabled
491: * on a filesystem independent of /etc/fstab, and it
492: * will still print quotas for them.
493: */
494: if ((fs = getfsspec(fst[i].f_mntfromname)) == NULL)
495: continue;
496: if (getufsquota(&fst[i], fs, qup, id, quotatype) == 0)
497: continue;
498: } else
499: continue;
1.10 deraadt 500: strncpy(qup->fsname, fst[i].f_mntonname, sizeof qup->fsname-1);
501: qup->fsname[sizeof qup->fsname-1] = '\0';
1.1 deraadt 502: if (quphead == NULL)
503: quphead = qup;
504: else
505: quptail->next = qup;
506: quptail = qup;
507: quptail->next = 0;
508: qup = NULL;
509: }
510: if (qup)
511: free(qup);
512: endfsent();
513: return (quphead);
514: }
515:
516: /*
517: * Check to see if a particular quota is to be enabled.
518: */
1.15 ! pjanzen 519: int
1.1 deraadt 520: ufshasquota(fs, type, qfnamep)
1.15 ! pjanzen 521: struct fstab *fs;
1.1 deraadt 522: int type;
523: char **qfnamep;
524: {
525: static char initname, usrname[100], grpname[100];
526: static char buf[BUFSIZ];
527: char *opt, *cp;
528:
1.15 ! pjanzen 529: cp = NULL;
1.1 deraadt 530: if (!initname) {
1.15 ! pjanzen 531: (void)snprintf(usrname, sizeof usrname, "%s%s",
1.6 deraadt 532: qfextension[USRQUOTA], qfname);
1.15 ! pjanzen 533: (void)snprintf(grpname, sizeof grpname, "%s%s",
1.6 deraadt 534: qfextension[GRPQUOTA], qfname);
1.1 deraadt 535: initname = 1;
536: }
1.7 etheisen 537: strncpy(buf, fs->fs_mntops, sizeof buf);
1.15 ! pjanzen 538: buf[sizeof(buf) - 1] = '\0';
1.1 deraadt 539: for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
1.15 ! pjanzen 540: if ((cp = strchr(opt, '=')))
1.1 deraadt 541: *cp++ = '\0';
542: if (type == USRQUOTA && strcmp(opt, usrname) == 0)
543: break;
544: if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
545: break;
546: }
547: if (!opt)
548: return (0);
549: if (cp) {
550: *qfnamep = cp;
551: return (1);
552: }
1.15 ! pjanzen 553: (void)snprintf(buf, sizeof buf, "%s/%s.%s",
1.6 deraadt 554: fs->fs_file, qfname, qfextension[type]);
1.1 deraadt 555: *qfnamep = buf;
556: return (1);
557: }
558:
559: int
560: getufsquota(fst, fs, qup, id, quotatype)
561: struct statfs *fst;
562: struct fstab *fs;
563: struct quotause *qup;
564: long id;
565: int quotatype;
566: {
567: char *qfpathname;
568: int fd, qcmd;
569:
570: qcmd = QCMD(Q_GETQUOTA, quotatype);
571: if (!ufshasquota(fs, quotatype, &qfpathname))
572: return (0);
573:
574: if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) {
575: if ((fd = open(qfpathname, O_RDONLY)) < 0) {
1.15 ! pjanzen 576: warn("%s", qfpathname);
1.1 deraadt 577: return (0);
578: }
1.15 ! pjanzen 579: (void)lseek(fd, (off_t)(id * sizeof(struct dqblk)), SEEK_SET);
1.1 deraadt 580: switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) {
581: case 0: /* EOF */
582: /*
583: * Convert implicit 0 quota (EOF)
584: * into an explicit one (zero'ed dqblk)
585: */
1.11 deraadt 586: memset((caddr_t)&qup->dqblk, 0, sizeof(struct dqblk));
1.1 deraadt 587: break;
588: case sizeof(struct dqblk): /* OK */
589: break;
590: default: /* ERROR */
1.15 ! pjanzen 591: warn("read error `%s'", qfpathname);
1.1 deraadt 592: close(fd);
593: return (0);
594: }
595: close(fd);
596: }
597: return (1);
598: }
599:
600: int
601: getnfsquota(fst, fs, qup, id, quotatype)
602: struct statfs *fst;
603: struct fstab *fs;
604: struct quotause *qup;
605: long id;
606: int quotatype;
607: {
608: struct getquota_args gq_args;
609: struct getquota_rslt gq_rslt;
610: struct dqblk *dqp = &qup->dqblk;
611: struct timeval tv;
612: char *cp;
613:
614: if (fst->f_flags & MNT_LOCAL)
615: return (0);
616:
617: /*
618: * rpc.rquotad does not support group quotas
619: */
620: if (quotatype != USRQUOTA)
621: return (0);
622:
623: /*
624: * must be some form of "hostname:/path"
625: */
626: cp = strchr(fst->f_mntfromname, ':');
627: if (cp == NULL) {
1.15 ! pjanzen 628: warnx("cannot find hostname for %s", fst->f_mntfromname);
1.1 deraadt 629: return (0);
630: }
631:
632: *cp = '\0';
1.11 deraadt 633: if (cp[1] != '/') {
1.1 deraadt 634: *cp = ':';
635: return (0);
636: }
637:
1.11 deraadt 638: gq_args.gqa_pathp = &cp[1];
1.1 deraadt 639: gq_args.gqa_uid = id;
640: if (callaurpc(fst->f_mntfromname, RQUOTAPROG, RQUOTAVERS,
641: RQUOTAPROC_GETQUOTA, xdr_getquota_args, &gq_args,
642: xdr_getquota_rslt, &gq_rslt) != 0) {
643: *cp = ':';
644: return (0);
645: }
646:
647: switch (gq_rslt.status) {
648: case Q_NOQUOTA:
649: break;
650: case Q_EPERM:
1.15 ! pjanzen 651: warnx("permission error, host: %s", fst->f_mntfromname);
1.1 deraadt 652: break;
653: case Q_OK:
654: gettimeofday(&tv, NULL);
655: /* blocks*/
656: dqp->dqb_bhardlimit =
657: gq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit *
658: gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE;
659: dqp->dqb_bsoftlimit =
660: gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit *
661: gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE;
662: dqp->dqb_curblocks =
663: gq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks *
664: gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE;
665: /* inodes */
666: dqp->dqb_ihardlimit =
667: gq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit;
668: dqp->dqb_isoftlimit =
669: gq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit;
670: dqp->dqb_curinodes =
671: gq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles;
672: /* grace times */
673: dqp->dqb_btime =
674: tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft;
675: dqp->dqb_itime =
676: tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft;
677: *cp = ':';
678: return (1);
679: default:
1.15 ! pjanzen 680: warnx("bad rpc result, host: %s", fst->f_mntfromname);
1.1 deraadt 681: break;
682: }
683: *cp = ':';
684: return (0);
685: }
686:
687: int
688: callaurpc(host, prognum, versnum, procnum, inproc, in, outproc, out)
689: char *host;
1.15 ! pjanzen 690: int prognum, versnum, procnum;
! 691: xdrproc_t inproc;
! 692: void *in;
! 693: xdrproc_t outproc;
! 694: void *out;
1.1 deraadt 695: {
696: struct sockaddr_in server_addr;
697: enum clnt_stat clnt_stat;
698: struct hostent *hp;
699: struct timeval timeout, tottimeout;
700:
701: CLIENT *client = NULL;
702: int socket = RPC_ANYSOCK;
703:
704: if ((hp = gethostbyname(host)) == NULL)
705: return ((int) RPC_UNKNOWNHOST);
706: timeout.tv_usec = 0;
707: timeout.tv_sec = 6;
1.11 deraadt 708:
709: memset(&server_addr, 0, sizeof server_addr);
710: memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
1.1 deraadt 711: server_addr.sin_family = AF_INET;
712: server_addr.sin_port = 0;
713:
714: if ((client = clntudp_create(&server_addr, prognum,
715: versnum, timeout, &socket)) == NULL)
716: return ((int) rpc_createerr.cf_stat);
717:
718: client->cl_auth = authunix_create_default();
719: tottimeout.tv_sec = 25;
720: tottimeout.tv_usec = 0;
721: clnt_stat = clnt_call(client, procnum, inproc, in,
722: outproc, out, tottimeout);
723:
724: return ((int) clnt_stat);
725: }
726:
1.15 ! pjanzen 727: int
1.1 deraadt 728: alldigits(s)
1.15 ! pjanzen 729: char *s;
1.1 deraadt 730: {
1.15 ! pjanzen 731: int c;
1.1 deraadt 732:
733: c = *s++;
734: do {
735: if (!isdigit(c))
736: return (0);
1.15 ! pjanzen 737: } while ((c = *s++));
1.1 deraadt 738: return (1);
739: }