xref: /illumos-gate/usr/src/ucbcmd/shutdown/shutdown.c (revision 1e56f352c1c208679012bca47d552e127f5b1072)
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
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
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
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
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
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
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
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
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
640 finish_sig(void)
641 {
642 	finish("SIGINT", "", 1);
643 }
644 
645 static void
646 finish(char *s1, char *s2, int exitcode)
647 {
648 	(void) signal(SIGINT, SIG_IGN);
649 	exit(exitcode);
650 }
651 
652 static void
653 timeout(void)
654 {
655 	(void) signal(SIGALRM, (void(*)())timeout);
656 	longjmp(alarmbuf, 1);
657 }
658 
659 static 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
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