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