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