1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
34 *
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
38 */
39
40 #include <stdio.h>
41 #include <ctype.h>
42 #include <setjmp.h>
43 #include <utmpx.h>
44 #include <pwd.h>
45 #include <time.h>
46 #include <sys/time.h>
47 #include <sys/resource.h>
48 #include <sys/param.h>
49 #include <sys/types.h>
50 #include <sys/errno.h>
51 #include <rpc/rpc.h>
52 #include <rpc/pmap_clnt.h>
53 #include <rpcsvc/mount.h>
54 #include <rpcsvc/rwall.h>
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <netdb.h>
58 #include <locale.h>
59 #include <sys/syslog.h>
60 #include <zone.h>
61 #include <signal.h>
62
63 /*
64 * /usr/etc/shutdown when [messages]
65 *
66 * allow super users to tell users and remind users
67 * of iminent shutdown of unix
68 * and shut it down automatically
69 * and even reboot or halt the machine if they desire
70 */
71
72 #define EPATH "PATH=/usr/ucb:/usr/bin:/usr/sbin:"
73 #define REBOOT "/usr/sbin/reboot"
74 #define HALT "/usr/sbin/halt"
75 #define MAXINTS 20
76 #define HOURS *3600
77 #define MINUTES *60
78 #define SECONDS
79 #define NLOG 600 /* no of bytes possible for message */
80 #define NOLOGTIME 5 MINUTES
81 #define IGNOREUSER "sleeper"
82
83 struct hostlist {
84 char *host;
85 struct hostlist *nxt;
86 } *hostlist;
87
88 char hostname[MAXHOSTNAMELEN];
89 char mbuf[BUFSIZ];
90
91 extern char *malloc();
92
93 extern char *ctime();
94 extern struct tm *localtime();
95
96 extern char *strcpy();
97 extern char *strncat();
98 extern off_t lseek();
99
100 struct utmpx *utmpx;
101
102 int sint;
103 int stogo;
104 char tpath[] = "/dev/";
105 int nlflag = 1; /* nolog yet to be done */
106 int killflg = 1;
107 int doreboot = 0;
108 int halt = 0;
109 int fast = 0;
110 char *nosync = NULL;
111 char nosyncflag[] = "-n";
112 char term[sizeof tpath + sizeof (utmpx->ut_line)];
113 char tbuf[BUFSIZ];
114 char nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n";
115 char mesg[NLOG+1];
116 #ifdef DEBUG
117 char fastboot[] = "fastboot";
118 #else
119 char fastboot[] = "/fastboot";
120 #endif
121 char nologin[] = "/etc/nologin";
122 time_t nowtime;
123 jmp_buf alarmbuf;
124
125 struct interval {
126 int stogo;
127 int sint;
128 } interval[] = {
129 4 HOURS, 1 HOURS,
130 2 HOURS, 30 MINUTES,
131 1 HOURS, 15 MINUTES,
132 30 MINUTES, 10 MINUTES,
133 15 MINUTES, 5 MINUTES,
134 10 MINUTES, 5 MINUTES,
135 5 MINUTES, 3 MINUTES,
136 2 MINUTES, 1 MINUTES,
137 1 MINUTES, 30 SECONDS,
138 0 SECONDS, 0 SECONDS
139 };
140
141 char *msg1 = "shutdown: '%c' - unknown flag\n";
142 char *msg2 = "Usage: shutdown [ -krhfn ] shutdowntime [ message ]\n";
143 char *msg3 = "Usage: shutdown [ -krhfn ] shutdowntime [ message ]";
144 char *msg4 = "Usage: shutdown [ -krhfn ] shutdowntime [ message ]\n";
145 char *msg5 = "Usage: shutdown [ -krhfn ] shutdowntime [ message ]";
146 char *msg6 = "\n\007\007System shutdown time has arrived\007\007\n";
147 char *msg7 = "but you'll have to do it yourself\n";
148 char *msg8 = "but you'll have to do it yourself";
149 char *msg9 = "-l (without fsck's)\n";
150 char *msg10 = "-l %s\n";
151 char *msg11 = " (without fsck's)\n";
152 char *msg12 = "That must be tomorrow\nCan't you wait till then?\n";
153 char *msg13 = "That must be tomorrow";
154 char *msg14 = "Can't you wait till then?";
155 char *msg15 = "\007\007\t*** %sSystem shutdown message from %s@%s ***\r\n\n";
156 char *msg16 = "System going down at %5.5s\r\n";
157 char *msg17 = "System going down in %d minute%s\r\n";
158 char *msg18 = "System going down in %d second%s\r\n";
159 char *msg19 = "System going down IMMEDIATELY\r\n";
160 char *msg20 = "Can't get PID for init\n";
161
162 char *shutter, *getlogin();
163
164 static void timeout(void);
165 static void gethostlist(void);
166 static void finish(char *, char *, int);
167 static void nolog(time_t);
168 static void rprintf(char *, char *);
169 static void rwarn(char *, time_t, time_t, char *, int);
170 static void doitfast(void);
171 static void warn(FILE *, time_t, time_t, char *, int);
172 static time_t getsdt(char *);
173
174 pid_t
get_initpid(void)175 get_initpid(void)
176 {
177 pid_t init_pid;
178
179 if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid,
180 sizeof (init_pid)) != sizeof (init_pid)) {
181 (void) fprintf(stderr, gettext(msg20));
182 exit(1);
183 }
184 return (init_pid);
185 }
186
187 int
main(int argc,char ** argv)188 main(int argc, char **argv)
189 {
190 int i;
191 char *f;
192 char *ts;
193 time_t sdt;
194 int h, m;
195 int first;
196 void finish_sig();
197 FILE *termf;
198 struct passwd *pw, *getpwuid();
199 extern char *strcat();
200 extern uid_t geteuid();
201 struct hostlist *hl;
202 char *shutdown_program;
203 char *shutdown_action;
204 int fd;
205
206 (void) setlocale(LC_ALL, "");
207
208 #if !defined(TEXT_DOMAIN)
209 #define TEXT_DOMAIN "SYS_TEST"
210 #endif
211 (void) textdomain(TEXT_DOMAIN);
212
213 audit_shutdown_setup(argc, argv);
214
215 shutter = getlogin();
216 if (shutter == 0 && (pw = getpwuid(getuid())))
217 shutter = pw->pw_name;
218 if (shutter == 0)
219 shutter = "???";
220 (void) gethostname(hostname, sizeof (hostname));
221 openlog("shutdown", 0, LOG_AUTH);
222 argc--, argv++;
223 while (argc > 0 && (f = argv[0], *f++ == '-')) {
224 while (i = *f++) {
225 switch (i) {
226 case 'k':
227 killflg = 0;
228 continue;
229 case 'n':
230 nosync = nosyncflag;
231 continue;
232 case 'f':
233 fast = 1;
234 continue;
235 case 'r':
236 doreboot = 1;
237 continue;
238 case 'h':
239 halt = 1;
240 continue;
241 default:
242 (void) fprintf(stderr, gettext(msg1),
243 i);
244 (void) fprintf(stderr, gettext(msg2));
245 finish(gettext(msg3), "", 1);
246 }
247 }
248 argc--, argv++;
249 }
250 if (argc < 1) {
251 (void) fprintf(stderr, gettext(msg4));
252 finish(gettext(msg5), "", 1);
253 }
254 if (doreboot && halt) {
255 (void) fprintf(stderr,
256 gettext("shutdown: Incompatible switches '-r' & '-h'\n"));
257 finish(gettext("shutdown: Incompatible switches '-r' & '-h'"),
258 "", 1);
259 }
260 if (fast && (nosync == nosyncflag)) {
261 (void) fprintf(stderr,
262 gettext("shutdown: Incompatible switches '-f' & '-n'\n"));
263 finish(gettext("shutdown: Incompatible switches '-f' & '-n'"),
264 "", 1);
265 }
266 if (geteuid()) {
267 (void) fprintf(stderr, gettext("shutdown: NOT super-user\n"));
268 finish(gettext("shutdown: NOT super-user"), "", 1);
269 }
270 gethostlist();
271 nowtime = time((time_t *)NULL);
272 sdt = getsdt(argv[0]);
273 argc--, argv++;
274 mesg[0] = '\0';
275 i = 0;
276 while (argc-- > 0) {
277 if (i + strlen(*argv) > NLOG)
278 break; /* no more room for the message */
279 i += strlen(*argv) + 1;
280 (void) strcat(mesg, *argv++);
281 (void) strcat(mesg, " ");
282 }
283 if (i != 0)
284 mesg[i - 1] = '\0'; /* remove trailing blank */
285 m = ((stogo = sdt - nowtime) + 30)/60;
286 h = m/60;
287 m %= 60;
288 ts = ctime(&sdt);
289 (void) printf(gettext("Shutdown at %5.5s (in "), ts+11);
290 if (h > 0)
291 (void) printf("%d hour%s ", h, h != 1 ? "s" : "");
292 (void) printf("%d minute%s) ", m, m != 1 ? "s" : "");
293 #ifndef DEBUG
294 (void) signal(SIGHUP, SIG_IGN);
295 (void) signal(SIGQUIT, SIG_IGN);
296 (void) signal(SIGINT, SIG_IGN);
297 #endif
298 (void) signal(SIGTTOU, SIG_IGN);
299 (void) signal(SIGINT, finish_sig);
300 (void) signal(SIGALRM, (void(*)())timeout);
301 (void) setpriority(PRIO_PROCESS, 0, PRIO_MIN);
302 (void) fflush(stdout);
303 #ifndef DEBUG
304 if (i = fork()) {
305 (void) printf(gettext("[pid %d]\n"), i);
306 exit(0);
307 }
308 #else
309 (void) putc('\n', stdout);
310 #endif
311 sint = 1 HOURS;
312 f = "";
313 first = 1;
314 if (doreboot) {
315 shutdown_program = REBOOT;
316 shutdown_action = "reboot";
317 } else if (halt) {
318 shutdown_program = HALT;
319 shutdown_action = "halt";
320 } else {
321 shutdown_program = NULL;
322 shutdown_action = "shutdown";
323 }
324 for (;;) {
325 for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++)
326 sint = interval[i].sint;
327 if (stogo > 0 && (stogo-sint) < interval[i].stogo)
328 sint = stogo - interval[i].stogo;
329 if (stogo <= NOLOGTIME && nlflag) {
330 nlflag = 0;
331 nolog(sdt);
332 }
333 if (sint >= stogo || sint == 0)
334 f = "FINAL ";
335 nowtime = time((time_t *)NULL);
336
337 setutxent();
338
339 while ((utmpx = getutxent()) != NULL) {
340 if (utmpx->ut_name[0] &&
341 strncmp(utmpx->ut_name, IGNOREUSER,
342 sizeof (utmpx->ut_name))) {
343 /*
344 * don't write to pty's unless they're rlogin sessions
345 */
346 if (utmpx->ut_type != USER_PROCESS &&
347 utmpx->ut_user[0] != '\0')
348 continue;
349
350 if (setjmp(alarmbuf))
351 continue;
352 (void) strcpy(term, tpath);
353 (void) strncat(term, utmpx->ut_line,
354 sizeof (utmpx->ut_line));
355 (void) alarm(5);
356
357 /* check if device is really a tty */
358 if ((fd = open(term, O_WRONLY|O_NOCTTY)) == -1) {
359 fprintf(stderr, gettext("Cannot open %s.\n"),
360 term);
361 (void) alarm(0);
362 continue;
363 } else {
364 if (!isatty(fd)) {
365 fprintf(stderr,
366 gettext("%.*s in utmpx is not a tty\n"),
367 sizeof (utmpx->ut_line), utmpx->ut_line);
368 syslog(LOG_CRIT, "%.*s in utmpx is not "
369 "a tty\n", sizeof (utmpx->ut_line),
370 utmpx->ut_line);
371 close(fd);
372 (void) alarm(0);
373 continue;
374 }
375 }
376 close(fd);
377 #ifdef DEBUG
378 if ((termf = stdout) != NULL)
379 #else
380 if ((termf = fopen(term, "w")) != NULL)
381 #endif
382 {
383 (void) alarm(0);
384 setbuf(termf, tbuf);
385 (void) fprintf(termf, "\n\r\n");
386 warn(termf, sdt, nowtime, f, first);
387 (void) alarm(5);
388 #ifdef DEBUG
389 (void) fflush(termf);
390 #else
391 (void) fclose(termf);
392 #endif
393 (void) alarm(0);
394 }
395 }
396 } /* while */
397
398 endutxent();
399
400 for (hl = hostlist; hl != NULL; hl = hl->nxt)
401 rwarn(hl->host, sdt, nowtime, f, first);
402 if (stogo <= 0) {
403 (void) printf(gettext(msg6));
404 if (*mesg)
405 syslog(LOG_CRIT, "%s by %s: %s",
406 shutdown_action, shutter, mesg);
407 else
408 syslog(LOG_CRIT, "%s by %s",
409 shutdown_action, shutter);
410 sleep(2);
411 (void) unlink(nologin);
412 if (!killflg) {
413 (void) printf(gettext(msg7));
414 finish(gettext(msg8), "", 0);
415 }
416 if (fast)
417 doitfast();
418 #ifndef DEBUG
419 (void) putenv(EPATH);
420 if (shutdown_program != NULL) {
421 audit_shutdown_success();
422 execlp(shutdown_program, shutdown_program,
423 "-l", nosync, (char *)0);
424 } else {
425 if (geteuid() == 0) {
426 audit_shutdown_success();
427 sleep(5);
428 }
429 if (getzoneid() == GLOBAL_ZONEID) {
430 (void) system(
431 "/sbin/bootadm -a update_all");
432 }
433
434 (void) kill(get_initpid(), SIGINT); /* sync */
435 (void) kill(get_initpid(), SIGINT); /* sync */
436 sleep(20);
437 }
438 #else
439 if (shutdown_program) {
440 (void) printf("%s ", shutdown_program);
441 if (fast)
442 (void) printf(gettext(msg9));
443 else if (nosync != NULL)
444 (void) printf(gettext(msg10), nosync);
445 else
446 (void) printf(gettext("-l\n"));
447 } else {
448 (void) printf("/sbin/bootadm -a update_all");
449 (void) printf("kill -INT 1");
450 if (fast)
451 (void) printf(gettext(msg11));
452 else
453 (void) printf("\n");
454 }
455 #endif
456 finish("", "", 0);
457 }
458 stogo = sdt - time((time_t *)NULL);
459 if (stogo > 0 && sint > 0)
460 sleep((unsigned)(sint < stogo ? sint : stogo));
461 stogo -= sint;
462 first = 0;
463 }
464 /* NOTREACHED */
465 }
466
467 static time_t
getsdt(char * s)468 getsdt(char *s)
469 {
470 time_t t, t1, tim;
471 char c;
472 struct tm *lt;
473 int c_count;
474
475 if (strcmp(s, "now") == 0)
476 return (nowtime);
477 if (*s == '+') {
478 ++s;
479 t = 0;
480 for (c_count = 1; ; c_count++) {
481 c = *s++;
482 if (!isdigit(c)) {
483 if (c_count == 1) {
484 goto badform;
485 } else {
486 break;
487 }
488 }
489 t = t * 10 + c - '0';
490 }
491 if (t <= 0)
492 t = 5;
493 t *= 60;
494 tim = time((time_t *)NULL) + t;
495 return (tim);
496 }
497 t = 0;
498 while (strlen(s) > 2 && isdigit(*s))
499 t = t * 10 + *s++ - '0';
500 if (*s == ':')
501 s++;
502 if (t > 23)
503 goto badform;
504 tim = t*60;
505 t = 0;
506 while (isdigit(*s))
507 t = t * 10 + *s++ - '0';
508 if (t > 59)
509 goto badform;
510 tim += t;
511 tim *= 60;
512 t1 = time((time_t *)NULL);
513 lt = localtime(&t1);
514 t = lt->tm_sec + lt->tm_min*60 + lt->tm_hour*3600;
515 if (tim < t || tim >= (24*3600)) {
516 /* before now or after midnight */
517 (void) printf(gettext(msg12));
518 finish(gettext(msg13), gettext(msg14), 0);
519 }
520 return (t1 + tim - t);
521 badform:
522 (void) printf(gettext("Bad time format\n"));
523 finish(gettext("Bad time format"), "", 0);
524 return (0);
525 /* NOTREACHED */
526 }
527
528 static void
warn(FILE * termf,time_t sdt,time_t now,char * type,int first)529 warn(FILE *termf, time_t sdt, time_t now, char *type, int first)
530 {
531 char *ts;
532 time_t delay = sdt - now;
533
534 if (delay > 8)
535 while (delay % 5)
536 delay++;
537
538 (void) fprintf(termf, gettext(msg15), type, shutter, hostname);
539
540 ts = ctime(&sdt);
541 if (delay > 10 MINUTES)
542 (void) fprintf(termf, gettext(msg16), ts+11);
543 else if (delay > 95 SECONDS) {
544 (void) fprintf(termf, gettext(msg17), (delay+30)/60,
545 (delay+30)/60 != 1 ? "s" : "");
546 } else if (delay > 0) {
547 (void) fprintf(termf, gettext(msg18), delay,
548 delay != 1 ? "s" : "");
549 } else
550 (void) fprintf(termf, gettext(msg19));
551
552 if (first || sdt - now > 1 MINUTES) {
553 if (*mesg)
554 (void) fprintf(termf, "\t...%s\r\n", mesg);
555 }
556 }
557
558 static void
doitfast(void)559 doitfast(void)
560 {
561 FILE *fastd;
562
563 if ((fastd = fopen(fastboot, "w")) != NULL) {
564 (void) putc('\n', fastd);
565 (void) fclose(fastd);
566 }
567 }
568
569 static void
rwarn(char * host,time_t sdt,time_t now,char * type,int first)570 rwarn(char *host, time_t sdt, time_t now, char *type, int first)
571 {
572 char *ts;
573 time_t delay = sdt - now;
574 char *bufp;
575
576 if (delay > 8)
577 while (delay % 5)
578 delay++;
579
580 (void) sprintf(mbuf,
581 "\007\007\t*** %sShutdown message for %s from %s@%s ***\r\n\n",
582 type, hostname, shutter, hostname);
583 ts = ctime(&sdt);
584 bufp = mbuf + strlen(mbuf);
585 if (delay > 10 MINUTES) {
586 (void) sprintf(bufp, "%s going down at %5.5s\r\n", hostname,
587 ts+11);
588 } else if (delay > 95 SECONDS) {
589 (void) sprintf(bufp, "%s going down in %d minute%s\r\n",
590 hostname, (delay+30)/60, (delay+30)/60 != 1 ? "s" : "");
591 } else if (delay > 0) {
592 (void) sprintf(bufp, "%s going down in %d second%s\r\n",
593 hostname, delay, delay != 1 ? "s" : "");
594 } else {
595 (void) sprintf(bufp, "%s going down IMMEDIATELY\r\n",
596 hostname);
597 }
598 bufp = mbuf + strlen(mbuf);
599 if (first || sdt - now > 1 MINUTES) {
600 if (*mesg)
601 (void) sprintf(bufp, "\t...%s\r\n", mesg);
602 }
603 rprintf(host, mbuf);
604 }
605
606 static void
rprintf(char * host,char * bufp)607 rprintf(char *host, char *bufp)
608 {
609 int err;
610
611 #ifdef DEBUG
612 (void) fprintf(stderr, gettext("about to call %s\n"), host);
613 #endif
614 if (err = callrpcfast(host, (rpcprog_t)WALLPROG, (rpcvers_t)WALLVERS,
615 (rpcproc_t)WALLPROC_WALL, xdr_dirpath, (char *)&bufp, xdr_void,
616 (char *)NULL)) {
617 #ifdef DEBUG
618 (void) fprintf(stderr, gettext("couldn't make rpc call: "));
619 clnt_perrno(err);
620 (void) fprintf(stderr, "\n");
621 #endif
622 }
623 }
624
625 static void
nolog(time_t sdt)626 nolog(time_t sdt)
627 {
628 FILE *nologf;
629
630 (void) unlink(nologin); /* in case linked to std file */
631 if ((nologf = fopen(nologin, "w")) != NULL) {
632 (void) fprintf(nologf, nolog1, (ctime(&sdt)) + 11);
633 if (*mesg)
634 (void) fprintf(nologf, "\t%s\n", mesg);
635 (void) fclose(nologf);
636 }
637 }
638
639 void
finish_sig(void)640 finish_sig(void)
641 {
642 finish("SIGINT", "", 1);
643 }
644
645 static void
finish(char * s1,char * s2,int exitcode)646 finish(char *s1, char *s2, int exitcode)
647 {
648 (void) signal(SIGINT, SIG_IGN);
649 exit(exitcode);
650 }
651
652 static void
timeout(void)653 timeout(void)
654 {
655 (void) signal(SIGALRM, (void(*)())timeout);
656 longjmp(alarmbuf, 1);
657 }
658
659 static void
gethostlist(void)660 gethostlist(void)
661 {
662 int s;
663 struct mountbody *ml;
664 struct hostlist *hl;
665 struct sockaddr_in addr;
666 CLIENT *cl;
667 static struct timeval TIMEOUT = { 25, 0 };
668
669 /*
670 * check for portmapper
671 */
672 get_myaddress(&addr);
673 s = socket(AF_INET, SOCK_STREAM, 0);
674 if (s < 0)
675 return;
676 if (connect(s, (struct sockaddr *)&addr, sizeof (addr)) < 0)
677 return;
678 (void) close(s);
679
680 /*
681 * First try tcp, then drop back to udp if
682 * tcp is unavailable (an old version of mountd perhaps)
683 * Using tcp is preferred because it can handle
684 * arbitrarily long export lists.
685 */
686 cl = clnt_create(hostname, (ulong_t)MOUNTPROG, (ulong_t)MOUNTVERS,
687 "tcp");
688 if (cl == NULL) {
689 cl = clnt_create(hostname, (ulong_t)MOUNTPROG,
690 (ulong_t)MOUNTVERS, "udp");
691 if (cl == NULL) {
692 if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED) {
693 clnt_pcreateerror("shutdown warning");
694 }
695 return;
696 }
697 }
698
699 ml = NULL;
700 if (clnt_call(cl, MOUNTPROC_DUMP,
701 xdr_void, 0, xdr_mountlist, (char *)&ml, TIMEOUT) != RPC_SUCCESS) {
702 clnt_perror(cl, "shutdown warning");
703 return;
704 }
705 for (; ml != NULL; ml = ml->ml_next) {
706 for (hl = hostlist; hl != NULL; hl = hl->nxt)
707 if (strcmp(ml->ml_hostname, hl->host) == 0)
708 goto again;
709 hl = (struct hostlist *)malloc(sizeof (struct hostlist));
710 hl->host = ml->ml_hostname;
711 hl->nxt = hostlist;
712 hostlist = hl;
713 again:;
714 }
715 }
716
717 /*
718 * Don't want to wait for usual portmapper timeout you get with
719 * callrpc or clnt_call, so use rmtcall instead. Use timeout
720 * of 8 secs, based on the per try timeout of 3 secs for rmtcall
721 */
722 int
callrpcfast(char * host,rpcprog_t prognum,rpcprog_t versnum,rpcprog_t procnum,xdrproc_t inproc,xdrproc_t outproc,char * in,char * out)723 callrpcfast(char *host, rpcprog_t prognum, rpcprog_t versnum,
724 rpcprog_t procnum, xdrproc_t inproc, xdrproc_t outproc,
725 char *in, char *out)
726 {
727 struct sockaddr_in server_addr;
728 struct hostent *hp;
729 struct timeval rpctimeout;
730 rpcport_t port;
731
732 if ((hp = gethostbyname(host)) == NULL)
733 return ((int)RPC_UNKNOWNHOST);
734 bcopy(hp->h_addr, (char *)&server_addr.sin_addr, hp->h_length);
735 server_addr.sin_family = AF_INET;
736 server_addr.sin_port = 0;
737 rpctimeout.tv_sec = 8;
738 rpctimeout.tv_usec = 0;
739 return ((int)pmap_rmtcall(&server_addr, prognum, versnum, procnum,
740 inproc, in, outproc, out, rpctimeout, &port));
741 }
742