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
85struct hostlist {
86    char *host;
87    struct hostlist *nxt;
88} *hostlist;
89
90char	hostname[MAXHOSTNAMELEN];
91char	mbuf[BUFSIZ];
92
93extern	char *malloc();
94
95extern	char *ctime();
96extern	struct tm *localtime();
97
98extern	char *strcpy();
99extern	char *strncat();
100extern	off_t lseek();
101
102struct	utmpx *utmpx;
103
104int	sint;
105int	stogo;
106char	tpath[] =	"/dev/";
107int	nlflag = 1;		/* nolog yet to be done */
108int	killflg = 1;
109int	doreboot = 0;
110int	halt = 0;
111int	fast = 0;
112char	*nosync = NULL;
113char	nosyncflag[] = "-n";
114char	term[sizeof tpath + sizeof (utmpx->ut_line)];
115char	tbuf[BUFSIZ];
116char    nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n";
117char	mesg[NLOG+1];
118#ifdef	DEBUG
119char	fastboot[] = "fastboot";
120#else
121char	fastboot[] = "/fastboot";
122#endif
123char    nologin[] = "/etc/nologin";
124time_t	nowtime;
125jmp_buf	alarmbuf;
126
127struct 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
143char	*msg1 = "shutdown: '%c' - unknown flag\n";
144char	*msg2 = "Usage: shutdown [ -krhfn ] shutdowntime [ message ]\n";
145char	*msg3 = "Usage: shutdown [ -krhfn ] shutdowntime [ message ]";
146char	*msg4 = "Usage: shutdown [ -krhfn ] shutdowntime [ message ]\n";
147char	*msg5 = "Usage: shutdown [ -krhfn ] shutdowntime [ message ]";
148char	*msg6 = "\n\007\007System shutdown time has arrived\007\007\n";
149char	*msg7 = "but you'll have to do it yourself\n";
150char	*msg8 = "but you'll have to do it yourself";
151char	*msg9 = "-l (without fsck's)\n";
152char	*msg10 = "-l %s\n";
153char	*msg11 = " (without fsck's)\n";
154char	*msg12 = "That must be tomorrow\nCan't you wait till then?\n";
155char	*msg13 = "That must be tomorrow";
156char	*msg14 = "Can't you wait till then?";
157char	*msg15 = "\007\007\t*** %sSystem shutdown message from %s@%s ***\r\n\n";
158char	*msg16 = "System going down at %5.5s\r\n";
159char	*msg17 = "System going down in %d minute%s\r\n";
160char	*msg18 = "System going down in %d second%s\r\n";
161char	*msg19 = "System going down IMMEDIATELY\r\n";
162char	*msg20 = "Can't get PID for init\n";
163
164char *shutter, *getlogin();
165
166static void timeout(void);
167static void gethostlist(void);
168static void finish(char *, char *, int);
169static void nolog(time_t);
170static void rprintf(char *, char *);
171static void rwarn(char *, time_t, time_t, char *, int);
172static void doitfast(void);
173static void warn(FILE *, time_t, time_t, char *, int);
174static time_t getsdt(char *);
175
176pid_t
177get_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
189int
190main(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
469static time_t
470getsdt(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);
523badform:
524	(void) printf(gettext("Bad time format\n"));
525	finish(gettext("Bad time format"), "", 0);
526	return (0);
527	/* NOTREACHED */
528}
529
530static void
531warn(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
560static void
561doitfast(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
571static void
572rwarn(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
608static void
609rprintf(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
627static void
628nolog(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
641void
642finish_sig(void)
643{
644	finish("SIGINT", "", 1);
645}
646
647static void
648finish(char *s1, char *s2, int exitcode)
649{
650	(void) signal(SIGINT, SIG_IGN);
651	exit(exitcode);
652}
653
654static void
655timeout(void)
656{
657	(void) signal(SIGALRM, (void(*)())timeout);
658	longjmp(alarmbuf, 1);
659}
660
661static void
662gethostlist(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 */
724int
725callrpcfast(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