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