quota.c revision 1.33.2.1 1 /* $NetBSD: quota.c,v 1.33.2.1 2011/01/20 14:25:05 bouyer Exp $ */
2
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. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 #ifndef lint
37 __COPYRIGHT("@(#) Copyright (c) 1980, 1990, 1993\
38 The Regents of the University of California. All rights reserved.");
39 #endif /* not lint */
40
41 #ifndef lint
42 #if 0
43 static char sccsid[] = "@(#)quota.c 8.4 (Berkeley) 4/28/95";
44 #else
45 __RCSID("$NetBSD: quota.c,v 1.33.2.1 2011/01/20 14:25:05 bouyer Exp $");
46 #endif
47 #endif /* not lint */
48
49 /*
50 * Disk quota reporting program.
51 */
52 #include <sys/param.h>
53 #include <sys/types.h>
54 #include <sys/file.h>
55 #include <sys/stat.h>
56 #include <sys/mount.h>
57 #include <sys/socket.h>
58 #include <sys/queue.h>
59 #include <prop/proplib.h>
60 #include <sys/quota.h>
61
62 #include <ufs/ufs/quota2_prop.h>
63 #include <ctype.h>
64 #include <err.h>
65 #include <errno.h>
66 #include <fstab.h>
67 #include <grp.h>
68 #include <netdb.h>
69 #include <pwd.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <time.h>
74 #include <unistd.h>
75
76 #include <rpc/rpc.h>
77 #include <rpc/pmap_prot.h>
78 #include <rpcsvc/rquota.h>
79
80 const char *qfextension[] = INITQFNAMES;
81
82 struct quotause {
83 struct quotause *next;
84 long flags;
85 struct quota2_entry q2e;
86 char fsname[MAXPATHLEN + 1];
87 };
88 #define FOUND 0x01
89
90 int alldigits(char *);
91 int callaurpc(char *, int, int, int, xdrproc_t, void *, xdrproc_t, void *);
92 int main(int, char **);
93 int getnfsquota(struct statvfs *, struct fstab *, struct quotause *,
94 long, int);
95 struct quotause *getprivs(long id, int quotatype);
96 int getufsquota(struct statvfs *, struct quotause *, long, int);
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 const char *intprt(uint64_t, int);
104 const char *timeprt(time_t seconds);
105 void usage(void);
106
107 int qflag = 0;
108 int vflag = 0;
109 int hflag = 0;
110 int dflag = 0;
111 int Dflag = 0;
112 uid_t myuid;
113
114 int
115 main(argc, argv)
116 int argc;
117 char *argv[];
118 {
119 int ngroups;
120 gid_t mygid, gidset[NGROUPS];
121 int i, gflag = 0, uflag = 0;
122 int ch;
123
124 myuid = getuid();
125 while ((ch = getopt(argc, argv, "Ddhugvq")) != -1) {
126 switch(ch) {
127 case 'g':
128 gflag++;
129 break;
130 case 'u':
131 uflag++;
132 break;
133 case 'v':
134 vflag++;
135 break;
136 case 'q':
137 qflag++;
138 break;
139 case 'h':
140 hflag++;
141 break;
142 case 'd':
143 dflag++;
144 break;
145 case 'D':
146 Dflag++;
147 break;
148 default:
149 usage();
150 }
151 }
152 argc -= optind;
153 argv += optind;
154 if (!uflag && !gflag)
155 uflag++;
156 if (dflag) {
157 #if 0
158 if (myuid != 0) {
159 printf("quota: -d: permission denied\n");
160 exit(1);
161 }
162 #endif
163 if (uflag)
164 showquotas(USRQUOTA, 0, "");
165 if (gflag)
166 showquotas(GRPQUOTA, 0, "");
167 exit(0);
168 }
169 if (argc == 0) {
170 if (uflag)
171 showuid(myuid);
172 if (gflag) {
173 if (dflag)
174 showgid(0);
175 else {
176 mygid = getgid();
177 ngroups = getgroups(NGROUPS, gidset);
178 if (ngroups < 0)
179 err(1, "getgroups");
180 showgid(mygid);
181 for (i = 0; i < ngroups; i++)
182 if (gidset[i] != mygid)
183 showgid(gidset[i]);
184 }
185 }
186 exit(0);
187 }
188 if (uflag && gflag)
189 usage();
190 if (uflag) {
191 for (; argc > 0; argc--, argv++) {
192 if (alldigits(*argv))
193 showuid(atoi(*argv));
194 else
195 showusrname(*argv);
196 }
197 exit(0);
198 }
199 if (gflag) {
200 for (; argc > 0; argc--, argv++) {
201 if (alldigits(*argv))
202 showgid(atoi(*argv));
203 else
204 showgrpname(*argv);
205 }
206 exit(0);
207 }
208 /* NOTREACHED */
209 return (0);
210 }
211
212 void
213 usage()
214 {
215
216 fprintf(stderr, "%s\n%s\n%s\n%s\n",
217 "usage: quota [-Dhguqv]",
218 "\tquota [-Dhqv] -u username ...",
219 "\tquota [-Dhqv] -g groupname ...",
220 "\tquota -d [-Dhguqv]");
221 exit(1);
222 }
223
224 /*
225 * Print out quotas for a specified user identifier.
226 */
227 void
228 showuid(uid)
229 uid_t uid;
230 {
231 struct passwd *pwd = getpwuid(uid);
232 const char *name;
233
234 if (pwd == NULL)
235 name = "(no account)";
236 else
237 name = pwd->pw_name;
238 if (uid != myuid && myuid != 0) {
239 printf("quota: %s (uid %d): permission denied\n", name, uid);
240 return;
241 }
242 showquotas(USRQUOTA, uid, name);
243 }
244
245 /*
246 * Print out quotas for a specified user name.
247 */
248 void
249 showusrname(name)
250 const char *name;
251 {
252 struct passwd *pwd = getpwnam(name);
253
254 if (pwd == NULL) {
255 warnx("%s: unknown user", name);
256 return;
257 }
258 if (pwd->pw_uid != myuid && myuid != 0) {
259 warnx("%s (uid %d): permission denied", name, pwd->pw_uid);
260 return;
261 }
262 showquotas(USRQUOTA, pwd->pw_uid, name);
263 }
264
265 /*
266 * Print out quotas for a specified group identifier.
267 */
268 void
269 showgid(gid)
270 gid_t gid;
271 {
272 struct group *grp = getgrgid(gid);
273 int ngroups;
274 gid_t mygid, gidset[NGROUPS];
275 int i;
276 const char *name;
277
278 if (grp == NULL)
279 name = "(no entry)";
280 else
281 name = grp->gr_name;
282 mygid = getgid();
283 ngroups = getgroups(NGROUPS, gidset);
284 if (ngroups < 0) {
285 warn("getgroups");
286 return;
287 }
288 if (gid != mygid) {
289 for (i = 0; i < ngroups; i++)
290 if (gid == gidset[i])
291 break;
292 if (i >= ngroups && myuid != 0) {
293 warnx("%s (gid %d): permission denied", name, gid);
294 return;
295 }
296 }
297 showquotas(GRPQUOTA, gid, name);
298 }
299
300 /*
301 * Print out quotas for a specified group name.
302 */
303 void
304 showgrpname(name)
305 const char *name;
306 {
307 struct group *grp = getgrnam(name);
308 int ngroups;
309 gid_t mygid, gidset[NGROUPS];
310 int i;
311
312 if (grp == NULL) {
313 warnx("%s: unknown group", name);
314 return;
315 }
316 mygid = getgid();
317 ngroups = getgroups(NGROUPS, gidset);
318 if (ngroups < 0) {
319 warn("getgroups");
320 return;
321 }
322 if (grp->gr_gid != mygid) {
323 for (i = 0; i < ngroups; i++)
324 if (grp->gr_gid == gidset[i])
325 break;
326 if (i >= ngroups && myuid != 0) {
327 warnx("%s (gid %d): permission denied",
328 name, grp->gr_gid);
329 return;
330 }
331 }
332 showquotas(GRPQUOTA, grp->gr_gid, name);
333 }
334
335 void
336 showquotas(type, id, name)
337 int type;
338 u_long id;
339 const char *name;
340 {
341 struct quotause *qup;
342 struct quotause *quplist;
343 const char *msgi, *msgb, *nam;
344 int lines = 0;
345 static time_t now;
346
347 if (now == 0)
348 time(&now);
349 quplist = getprivs(id, type);
350 for (qup = quplist; qup; qup = qup->next) {
351 if (!vflag &&
352 qup->q2e.q2e_val[Q2V_BLOCK].q2v_softlimit == UQUAD_MAX &&
353 qup->q2e.q2e_val[Q2V_BLOCK].q2v_hardlimit == UQUAD_MAX &&
354 qup->q2e.q2e_val[Q2V_FILE].q2v_softlimit == UQUAD_MAX &&
355 qup->q2e.q2e_val[Q2V_FILE].q2v_hardlimit == UQUAD_MAX)
356 continue;
357 msgi = NULL;
358 if (qup->q2e.q2e_val[Q2V_FILE].q2v_hardlimit &&
359 qup->q2e.q2e_val[Q2V_FILE].q2v_cur >=
360 qup->q2e.q2e_val[Q2V_FILE].q2v_hardlimit)
361 msgi = "File limit reached on";
362 else if (qup->q2e.q2e_val[Q2V_FILE].q2v_softlimit &&
363 qup->q2e.q2e_val[Q2V_FILE].q2v_cur >=
364 qup->q2e.q2e_val[Q2V_FILE].q2v_softlimit) {
365 if (qup->q2e.q2e_val[Q2V_FILE].q2v_time > now)
366 msgi = "In file grace period on";
367 else
368 msgi = "Over file quota on";
369 }
370 msgb = NULL;
371 if (qup->q2e.q2e_val[Q2V_BLOCK].q2v_hardlimit &&
372 qup->q2e.q2e_val[Q2V_BLOCK].q2v_cur >=
373 qup->q2e.q2e_val[Q2V_BLOCK].q2v_hardlimit)
374 msgb = "Block limit reached on";
375 else if (qup->q2e.q2e_val[Q2V_BLOCK].q2v_softlimit &&
376 qup->q2e.q2e_val[Q2V_BLOCK].q2v_cur >=
377 qup->q2e.q2e_val[Q2V_BLOCK].q2v_softlimit) {
378 if (qup->q2e.q2e_val[Q2V_BLOCK].q2v_time > now)
379 msgb = "In block grace period on";
380 else
381 msgb = "Over block quota on";
382 }
383 if (qflag) {
384 if ((msgi != NULL || msgb != NULL) &&
385 lines++ == 0)
386 heading(type, id, name, "");
387 if (msgi != NULL)
388 printf("\t%s %s\n", msgi, qup->fsname);
389 if (msgb != NULL)
390 printf("\t%s %s\n", msgb, qup->fsname);
391 continue;
392 }
393 if (vflag || dflag ||
394 qup->q2e.q2e_val[Q2V_BLOCK].q2v_cur ||
395 qup->q2e.q2e_val[Q2V_FILE].q2v_cur) {
396 if (lines++ == 0)
397 heading(type, id, name, "");
398 nam = qup->fsname;
399 if (strlen(qup->fsname) > 4) {
400 printf("%s\n", qup->fsname);
401 nam = "";
402 }
403 printf("%12s%9s%c%8s%9s%8s"
404 , nam
405 , intprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_cur
406 ,HN_B)
407 , (msgb == NULL) ? ' ' : '*'
408 , intprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_softlimit
409 , HN_B)
410 , intprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_hardlimit
411 , HN_B)
412 , (msgb == NULL) ? ""
413 : timeprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_time));
414 printf("%8s%c%7s%8s%8s\n"
415 , intprt(qup->q2e.q2e_val[Q2V_FILE].q2v_cur, 0)
416 , (msgi == NULL) ? ' ' : '*'
417 , intprt(qup->q2e.q2e_val[Q2V_FILE].q2v_softlimit
418 , 0)
419 , intprt(qup->q2e.q2e_val[Q2V_FILE].q2v_hardlimit
420 , 0)
421 , (msgi == NULL) ? ""
422 : timeprt(qup->q2e.q2e_val[Q2V_FILE].q2v_time)
423 );
424 continue;
425 }
426 }
427 if (!qflag && lines == 0)
428 heading(type, id, name, "none");
429 }
430
431 void
432 heading(type, id, name, tag)
433 int type;
434 u_long id;
435 const char *name, *tag;
436 {
437 if (dflag)
438 printf("Default %s disk quotas: %s\n",
439 qfextension[type], tag);
440 else
441 printf("Disk quotas for %s %s (%cid %ld): %s\n",
442 qfextension[type], name, *qfextension[type],
443 (u_long)id, tag);
444
445 if (!qflag && tag[0] == '\0') {
446 printf("%12s%9s %8s%9s%8s%8s %7s%8s%8s\n"
447 , "Filesystem"
448 , "blocks"
449 , "quota"
450 , "limit"
451 , "grace"
452 , "files"
453 , "quota"
454 , "limit"
455 , "grace"
456 );
457 }
458 }
459
460 /*
461 * convert 64bit value to a printable string
462 */
463 const char *
464 intprt(uint64_t val, int flags)
465 {
466 static char buf[21];
467
468 if (val == UQUAD_MAX)
469 return("-");
470
471 if (flags & HN_B)
472 val = dbtob(val);
473
474 if (hflag) {
475 humanize_number(buf, 6, val, "", HN_AUTOSCALE, flags);
476 return buf;
477 }
478 if (flags & HN_B) {
479 /* traditionnal display: blocks are in kilobytes */
480 val = val / 1024;
481 }
482 snprintf(buf, sizeof(buf), "%" PRIu64, val);
483 return buf;
484 }
485
486 /*
487 * Calculate the grace period and return a printable string for it.
488 */
489 const char *
490 timeprt(time_t seconds)
491 {
492 time_t hours, minutes;
493 static char buf[20];
494 static time_t now;
495
496 if (now == 0)
497 time(&now);
498 if (now > seconds)
499 return ("none");
500 seconds -= now;
501 minutes = (seconds + 30) / 60;
502 hours = (minutes + 30) / 60;
503 if (hours >= 36) {
504 (void)snprintf(buf, sizeof buf, "%ddays",
505 (int)((hours + 12) / 24));
506 return (buf);
507 }
508 if (minutes >= 60) {
509 (void)snprintf(buf, sizeof buf, "%2d:%d",
510 (int)(minutes / 60), (int)(minutes % 60));
511 return (buf);
512 }
513 (void)snprintf(buf, sizeof buf, "%2d", (int)minutes);
514 return (buf);
515 }
516
517 /*
518 * Collect the requested quota information.
519 */
520 struct quotause *
521 getprivs(id, quotatype)
522 long id;
523 int quotatype;
524 {
525 struct quotause *qup, *quptail;
526 struct quotause *quphead;
527 struct statvfs *fst;
528 int nfst, i;
529
530 qup = quphead = quptail = NULL;
531
532 nfst = getmntinfo(&fst, MNT_WAIT);
533 if (nfst == 0)
534 errx(2, "no filesystems mounted!");
535 setfsent();
536 for (i = 0; i < nfst; i++) {
537 if (qup == NULL) {
538 if ((qup =
539 (struct quotause *)malloc(sizeof *qup)) == NULL)
540 errx(2, "out of memory");
541 }
542 if (strncmp(fst[i].f_fstypename, "nfs",
543 sizeof(fst[i].f_fstypename)) == 0) {
544 if (getnfsquota(&fst[i], NULL, qup, id, quotatype) == 0)
545 continue;
546 } else if (strncmp(fst[i].f_fstypename, "ffs",
547 sizeof(fst[i].f_fstypename)) == 0 &&
548 (fst[i].f_flag &ST_QUOTA) != 0) {
549 if (getufsquota(&fst[i], qup, id, quotatype) == 0)
550 continue;
551 } else
552 continue;
553 (void)strncpy(qup->fsname, fst[i].f_mntonname,
554 sizeof(qup->fsname) - 1);
555 if (quphead == NULL)
556 quphead = qup;
557 else
558 quptail->next = qup;
559 quptail = qup;
560 quptail->next = 0;
561 qup = NULL;
562 }
563 if (qup)
564 free(qup);
565 endfsent();
566 return (quphead);
567 }
568
569
570 int
571 getufsquota(struct statvfs *fst, struct quotause *qup, long id, int type)
572 {
573 prop_dictionary_t dict, data, cmd;
574 prop_array_t cmds, datas;
575 struct plistref pref;
576 int error;
577 int8_t error8;
578 bool ret;
579
580 dict = quota2_prop_create();
581 cmds = prop_array_create();
582 datas = prop_array_create();
583 data = prop_dictionary_create();
584
585 if (dict == NULL || cmds == NULL || datas == NULL || data == NULL)
586 errx(1, "can't allocate proplist");
587
588 if (dflag)
589 ret = prop_dictionary_set_cstring(data, "id", "default");
590 else
591 ret = prop_dictionary_set_uint32(data, "id", id);
592 if (!ret)
593 err(1, "prop_dictionary_set(id)");
594
595 if (!prop_array_add(datas, data))
596 err(1, "prop_array_add(data)");
597 prop_object_release(data);
598 if (!quota2_prop_add_command(cmds, "get", qfextension[type], datas))
599 err(1, "prop_add_command");
600 if (!prop_dictionary_set(dict, "commands", cmds))
601 err(1, "prop_dictionary_set(command)");
602 if (Dflag)
603 printf("message to kernel:\n%s\n",
604 prop_dictionary_externalize(dict));
605
606 if (!prop_dictionary_send_syscall(dict, &pref))
607 err(1, "prop_dictionary_send_syscall");
608 prop_object_release(dict);
609
610 if (quotactl(fst->f_mntonname, &pref) != 0)
611 err(1, "quotactl");
612
613 if ((error = prop_dictionary_recv_syscall(&pref, &dict)) != 0) {
614 errx(1, "prop_dictionary_recv_syscall: %s\n",
615 strerror(error));
616 }
617 if (Dflag)
618 printf("reply from kernel:\n%s\n",
619 prop_dictionary_externalize(dict));
620 if ((error = quota2_get_cmds(dict, &cmds)) != 0) {
621 errx(1, "quota2_get_cmds: %s\n",
622 strerror(error));
623 }
624 /* only one command, no need to iter */
625 cmd = prop_array_get(cmds, 0);
626 if (cmd == NULL)
627 err(1, "prop_array_get(cmd)");
628
629 if (!prop_dictionary_get_int8(cmd, "return", &error8))
630 err(1, "prop_get(return)");
631
632 if (error8) {
633 if (error8 != ENOENT && error8 != ENODEV) {
634 if (dflag)
635 fprintf(stderr, "get default %s quota: %s\n",
636 qfextension[type], strerror(error8));
637 else
638 fprintf(stderr, "get %s quota for %ld: %s\n",
639 qfextension[type], id, strerror(error8));
640 }
641 prop_object_release(dict);
642 return (0);
643 }
644 datas = prop_dictionary_get(cmd, "data");
645 if (datas == NULL)
646 err(1, "prop_dict_get(datas)");
647
648 /* only one data, no need to iter */
649 if (prop_array_count(datas) == 0) {
650 /* no quota for this user/group */
651 prop_object_release(dict);
652 return (0);
653 }
654
655 data = prop_array_get(datas, 0);
656 if (data == NULL)
657 err(1, "prop_array_get(data)");
658
659 error = quota2_dict_get_q2e_usage(data, &qup->q2e);
660 if (error) {
661 errx(1, "quota2_dict_get_q2e_usage: %s\n",
662 strerror(error));
663 }
664 return (1);
665 }
666
667 int
668 getnfsquota(fst, fs, qup, id, quotatype)
669 struct statvfs *fst;
670 struct fstab *fs;
671 struct quotause *qup;
672 long id;
673 int quotatype;
674 {
675 struct getquota_args gq_args;
676 struct ext_getquota_args ext_gq_args;
677 struct getquota_rslt gq_rslt;
678 struct quota2_entry *q2e = &qup->q2e;
679 struct timeval tv;
680 char *cp;
681 int ret;
682
683 if (fst->f_flag & MNT_LOCAL)
684 return (0);
685
686 /*
687 * must be some form of "hostname:/path"
688 */
689 cp = strchr(fst->f_mntfromname, ':');
690 if (cp == NULL) {
691 warnx("cannot find hostname for %s", fst->f_mntfromname);
692 return (0);
693 }
694
695 *cp = '\0';
696 if (*(cp+1) != '/') {
697 *cp = ':';
698 return (0);
699 }
700
701 ext_gq_args.gqa_pathp = cp + 1;
702 ext_gq_args.gqa_id = id;
703 ext_gq_args.gqa_type =
704 (quotatype == USRQUOTA) ? RQUOTA_USRQUOTA : RQUOTA_GRPQUOTA;
705 ret = callaurpc(fst->f_mntfromname, RQUOTAPROG, EXT_RQUOTAVERS,
706 RQUOTAPROC_GETQUOTA, xdr_ext_getquota_args, &ext_gq_args,
707 xdr_getquota_rslt, &gq_rslt);
708 if (ret == RPC_PROGVERSMISMATCH) {
709 if (quotatype != USRQUOTA) {
710 *cp = ':';
711 return (0);
712 }
713 /* try RQUOTAVERS */
714 gq_args.gqa_pathp = cp + 1;
715 gq_args.gqa_uid = id;
716 ret = callaurpc(fst->f_mntfromname, RQUOTAPROG, RQUOTAVERS,
717 RQUOTAPROC_GETQUOTA, xdr_getquota_args, &gq_args,
718 xdr_getquota_rslt, &gq_rslt);
719 }
720 if (ret != RPC_SUCCESS) {
721 *cp = ':';
722 return (0);
723 }
724
725 switch (gq_rslt.status) {
726 case Q_NOQUOTA:
727 break;
728 case Q_EPERM:
729 warnx("quota permission error, host: %s", fst->f_mntfromname);
730 break;
731 case Q_OK:
732 gettimeofday(&tv, NULL);
733 /* blocks*/
734 q2e->q2e_val[Q2V_BLOCK].q2v_hardlimit =
735 gq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit *
736 (gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE);
737 q2e->q2e_val[Q2V_BLOCK].q2v_softlimit =
738 gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit *
739 (gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE);
740 q2e->q2e_val[Q2V_BLOCK].q2v_cur =
741 gq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks *
742 (gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE);
743 /* inodes */
744 q2e->q2e_val[Q2V_FILE].q2v_hardlimit =
745 gq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit;
746 q2e->q2e_val[Q2V_FILE].q2v_softlimit =
747 gq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit;
748 q2e->q2e_val[Q2V_FILE].q2v_cur =
749 gq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles;
750 /* grace times */
751 q2e->q2e_val[Q2V_BLOCK].q2v_time =
752 tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft;
753 q2e->q2e_val[Q2V_FILE].q2v_time =
754 tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft;
755 *cp = ':';
756 return (1);
757 default:
758 warnx("bad rpc result, host: %s", fst->f_mntfromname);
759 break;
760 }
761 *cp = ':';
762 return (0);
763 }
764
765 int
766 callaurpc(host, prognum, versnum, procnum, inproc, in, outproc, out)
767 char *host;
768 int prognum, versnum, procnum;
769 xdrproc_t inproc;
770 void *in;
771 xdrproc_t outproc;
772 void *out;
773 {
774 struct sockaddr_in server_addr;
775 enum clnt_stat clnt_stat;
776 struct hostent *hp;
777 struct timeval timeout, tottimeout;
778
779 CLIENT *client = NULL;
780 int sock = RPC_ANYSOCK;
781
782 if ((hp = gethostbyname(host)) == NULL)
783 return ((int) RPC_UNKNOWNHOST);
784 timeout.tv_usec = 0;
785 timeout.tv_sec = 6;
786 memmove(&server_addr.sin_addr, hp->h_addr, hp->h_length);
787 server_addr.sin_family = AF_INET;
788 server_addr.sin_port = 0;
789
790 if ((client = clntudp_create(&server_addr, prognum,
791 versnum, timeout, &sock)) == NULL)
792 return ((int) rpc_createerr.cf_stat);
793
794 client->cl_auth = authunix_create_default();
795 tottimeout.tv_sec = 25;
796 tottimeout.tv_usec = 0;
797 clnt_stat = clnt_call(client, procnum, inproc, in,
798 outproc, out, tottimeout);
799
800 return ((int) clnt_stat);
801 }
802
803 int
804 alldigits(s)
805 char *s;
806 {
807 int c;
808
809 c = *s++;
810 do {
811 if (!isdigit(c))
812 return (0);
813 } while ((c = *s++) != 0);
814 return (1);
815 }
816