/usr.bin/quota/quota.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 701 lines · 565 code · 56 blank · 80 comment · 153 complexity · fdf626d9a8512c05e69cd7c8c24fd11d MD5 · raw file

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