Home | History | Annotate | Download | only in shutdown
      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