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