1 /* $OpenBSD: common.c,v 1.26 2011/04/24 02:23:57 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 1983 Regents of the University of California. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include "defs.h" 33 34 /* 35 * Things common to both the client and server. 36 */ 37 38 #if defined(NEED_UTIME_H) 39 #include <utime.h> 40 #endif /* defined(NEED_UTIME_H) */ 41 #include <sys/wait.h> 42 #include <sys/socket.h> 43 44 /* 45 * Variables common to both client and server 46 */ 47 char host[MAXHOSTNAMELEN]; /* Name of this host */ 48 UID_T userid = (UID_T)-1; /* User's UID */ 49 GID_T groupid = (GID_T)-1; /* User's GID */ 50 char *homedir = NULL; /* User's $HOME */ 51 char *locuser = NULL; /* Local User's name */ 52 int isserver = FALSE; /* We're the server */ 53 int amchild = 0; /* This PID is a child */ 54 int do_fork = 1; /* Fork child process */ 55 char *currenthost = NULL; /* Current client hostname */ 56 char *progname = NULL; /* Name of this program */ 57 int rem_r = -1; /* Client file descriptor */ 58 int rem_w = -1; /* Client file descriptor */ 59 struct passwd *pw = NULL; /* Local user's pwd entry */ 60 volatile sig_atomic_t contimedout = FALSE; /* Connection timed out */ 61 int proto_version = -1; /* Protocol version */ 62 int rtimeout = RTIMEOUT; /* Response time out */ 63 jmp_buf finish_jmpbuf; /* Finish() jmp buffer */ 64 int setjmp_ok = FALSE; /* setjmp()/longjmp() status */ 65 char **realargv; /* Real main() argv */ 66 int realargc; /* Real main() argc */ 67 opt_t options = 0; /* Global install options */ 68 char defowner[64] = "bin"; /* Default owner */ 69 char defgroup[64] = "bin"; /* Default group */ 70 71 static int sendcmdmsg(int, char *, size_t); 72 static ssize_t remread(int, u_char *, size_t); 73 static int remmore(void); 74 75 /* 76 * Front end to write() that handles partial write() requests. 77 */ 78 WRITE_RETURN_T 79 xwrite(int fd, void *buf, WRITE_AMT_T len) 80 { 81 WRITE_AMT_T nleft = len; 82 WRITE_RETURN_T nwritten; 83 char *ptr = buf; 84 85 while (nleft > 0) { 86 if ((nwritten = write(fd, ptr, nleft)) <= 0) { 87 return nwritten; 88 } 89 nleft -= nwritten; 90 ptr += nwritten; 91 } 92 93 return len; 94 } 95 96 /* 97 * Do run-time initialization 98 */ 99 int 100 init(int argc, char **argv, char **envp) 101 { 102 int i; 103 104 /* 105 * Save a copy of our argc and argv before setargs() overwrites them 106 */ 107 realargc = argc; 108 realargv = (char **) xmalloc(sizeof(char *) * (argc+1)); 109 for (i = 0; i < argc; i++) 110 realargv[i] = xstrdup(argv[i]); 111 112 #if defined(SETARGS) 113 setargs_settup(argc, argv, envp); 114 #endif /* SETARGS */ 115 116 pw = getpwuid(userid = getuid()); 117 if (pw == NULL) { 118 error("Your user id (%u) is not known to this system.", 119 getuid()); 120 return(-1); 121 } 122 123 debugmsg(DM_MISC, "UserID = %u pwname = '%s' home = '%s'\n", 124 userid, pw->pw_name, pw->pw_dir); 125 homedir = xstrdup(pw->pw_dir); 126 locuser = xstrdup(pw->pw_name); 127 groupid = pw->pw_gid; 128 gethostname(host, sizeof(host)); 129 #if 0 130 if ((cp = strchr(host, '.')) != NULL) 131 *cp = CNULL; 132 #endif 133 134 /* 135 * If we're not root, disable paranoid ownership checks 136 * since normal users cannot chown() files. 137 */ 138 if (!isserver && userid != 0) { 139 FLAG_ON(options, DO_NOCHKOWNER); 140 FLAG_ON(options, DO_NOCHKGROUP); 141 } 142 143 return(0); 144 } 145 146 /* 147 * Finish things up before ending. 148 */ 149 void 150 finish(void) 151 { 152 extern jmp_buf finish_jmpbuf; 153 154 debugmsg(DM_CALL, 155 "finish() called: do_fork = %d amchild = %d isserver = %d", 156 do_fork, amchild, isserver); 157 cleanup(0); 158 159 /* 160 * There's no valid finish_jmpbuf for the rdist master parent. 161 */ 162 if (!do_fork || amchild || isserver) { 163 164 if (!setjmp_ok) { 165 #ifdef DEBUG_SETJMP 166 error("attemping longjmp() without target"); 167 abort(); 168 #else 169 exit(1); 170 #endif 171 } 172 173 longjmp(finish_jmpbuf, 1); 174 /*NOTREACHED*/ 175 error("Unexpected failure of longjmp() in finish()"); 176 exit(2); 177 } else 178 exit(1); 179 } 180 181 /* 182 * Handle lost connections 183 */ 184 void 185 lostconn(void) 186 { 187 /* Prevent looping */ 188 (void) signal(SIGPIPE, SIG_IGN); 189 190 rem_r = rem_w = -1; /* Ensure we don't try to send to server */ 191 checkhostname(); 192 error("Lost connection to %s", 193 (currenthost) ? currenthost : "(unknown)"); 194 195 finish(); 196 } 197 198 /* 199 * General signal handler 200 */ 201 void 202 sighandler(int sig) 203 { 204 int save_errno = errno; 205 206 /* XXX signal race */ 207 debugmsg(DM_CALL, "sighandler() received signal %d\n", sig); 208 209 switch (sig) { 210 case SIGALRM: 211 contimedout = TRUE; 212 /* XXX signal race */ 213 checkhostname(); 214 error("Response time out"); 215 finish(); 216 break; 217 218 case SIGPIPE: 219 /* XXX signal race */ 220 lostconn(); 221 break; 222 223 case SIGFPE: 224 debug = !debug; 225 break; 226 227 case SIGHUP: 228 case SIGINT: 229 case SIGQUIT: 230 case SIGTERM: 231 /* XXX signal race */ 232 finish(); 233 break; 234 235 default: 236 /* XXX signal race */ 237 fatalerr("No signal handler defined for signal %d.", sig); 238 } 239 errno = save_errno; 240 } 241 242 /* 243 * Function to actually send the command char and message to the 244 * remote host. 245 */ 246 static int 247 sendcmdmsg(int cmd, char *msg, size_t msgsize) 248 { 249 int len; 250 251 if (rem_w < 0) 252 return(-1); 253 254 /* 255 * All commands except C_NONE should have a newline 256 */ 257 if (cmd != C_NONE && !strchr(msg + 1, '\n')) 258 (void) strlcat(msg + 1, "\n", msgsize - 1); 259 260 if (cmd == C_NONE) 261 len = strlen(msg); 262 else { 263 len = strlen(msg + 1) + 1; 264 msg[0] = cmd; 265 } 266 267 debugmsg(DM_PROTO, ">>> Cmd = %c (\\%3.3o) Msg = \"%.*s\"", 268 cmd, cmd, 269 (cmd == C_NONE) ? len-1 : len-2, 270 (cmd == C_NONE) ? msg : msg + 1); 271 272 return(!(xwrite(rem_w, msg, len) == len)); 273 } 274 275 /* 276 * Send a command message to the remote host. 277 * Called as sendcmd(char cmdchar, char *fmt, arg1, arg2, ...) 278 * The fmt and arg? arguments are optional. 279 */ 280 #if defined(ARG_TYPE) && ARG_TYPE == ARG_STDARG 281 /* 282 * Stdarg frontend to sendcmdmsg() 283 */ 284 int 285 sendcmd(char cmd, char *fmt, ...) 286 { 287 static char buf[BUFSIZ]; 288 va_list args; 289 290 va_start(args, fmt); 291 if (fmt) 292 (void) vsnprintf(buf + (cmd != C_NONE), 293 sizeof(buf) - (cmd != C_NONE), fmt, args); 294 else 295 buf[1] = CNULL; 296 va_end(args); 297 298 return(sendcmdmsg(cmd, buf, sizeof(buf))); 299 } 300 #endif /* ARG_TYPE == ARG_STDARG */ 301 302 #if defined(ARG_TYPE) && ARG_TYPE == ARG_VARARGS 303 /* 304 * Varargs frontend to sendcmdmsg() 305 */ 306 int 307 sendcmd(va_alist) 308 va_dcl 309 { 310 static char buf[BUFSIZ]; 311 va_list args; 312 char cmd; 313 char *fmt; 314 315 va_start(args); 316 /* XXX The "int" is necessary as a workaround for broken varargs */ 317 cmd = (char) va_arg(args, int); 318 fmt = va_arg(args, char *); 319 if (fmt) 320 (void) vsnprintf(buf + (cmd != C_NONE), 321 sizeof(buf) - (cmd != C_NONE), fmt, args); 322 else 323 buf[1] = CNULL; 324 va_end(args); 325 326 return(sendcmdmsg(cmd, buf, sizeof(buf))); 327 } 328 #endif /* ARG_TYPE == ARG_VARARGS */ 329 330 /* 331 * Internal variables and routines for reading lines from the remote. 332 */ 333 static u_char rembuf[BUFSIZ]; 334 static u_char *remptr; 335 static ssize_t remleft; 336 337 #define remc() (--remleft < 0 ? remmore() : *remptr++) 338 339 /* 340 * Back end to remote read() 341 */ 342 static ssize_t 343 remread(int fd, u_char *buf, size_t bufsiz) 344 { 345 return(read(fd, (char *)buf, bufsiz)); 346 } 347 348 static int 349 remmore(void) 350 { 351 (void) signal(SIGALRM, sighandler); 352 (void) alarm(rtimeout); 353 354 remleft = remread(rem_r, rembuf, sizeof(rembuf)); 355 356 (void) alarm(0); 357 358 if (remleft < 0) 359 return (-2); /* error */ 360 if (remleft == 0) 361 return (-1); /* EOF */ 362 remptr = rembuf; 363 remleft--; 364 return (*remptr++); 365 } 366 367 /* 368 * Read an input line from the remote. Return the number of bytes 369 * stored (equivalent to strlen(p)). If `cleanup' is set, EOF at 370 * the beginning of a line is returned as EOF (-1); other EOFs, or 371 * errors, call cleanup() or lostconn(). In other words, unless 372 * the third argument is nonzero, this routine never returns failure. 373 */ 374 int 375 remline(u_char *buffer, int space, int doclean) 376 { 377 int c, left = space; 378 u_char *p = buffer; 379 380 if (rem_r < 0) { 381 error("Cannot read remote input: Remote descriptor not open."); 382 return(-1); 383 } 384 385 while (left > 0) { 386 if ((c = remc()) < -1) { /* error */ 387 if (doclean) { 388 finish(); 389 /*NOTREACHED*/ 390 } 391 lostconn(); 392 /*NOTREACHED*/ 393 } 394 if (c == -1) { /* got EOF */ 395 if (doclean) { 396 if (left == space) 397 return (-1);/* signal proper EOF */ 398 finish(); /* improper EOF */ 399 /*NOTREACHED*/ 400 } 401 lostconn(); 402 /*NOTREACHED*/ 403 } 404 if (c == '\n') { 405 *p = CNULL; 406 407 if (debug) { 408 static char mbuf[BUFSIZ]; 409 410 (void) snprintf(mbuf, sizeof(mbuf), 411 "<<< Cmd = %c (\\%3.3o) Msg = \"%s\"", 412 buffer[0], buffer[0], 413 buffer + 1); 414 415 debugmsg(DM_PROTO, "%s", mbuf); 416 } 417 418 return (space - left); 419 } 420 *p++ = c; 421 left--; 422 } 423 424 /* this will probably blow the entire session */ 425 error("remote input line too long"); 426 p[-1] = CNULL; /* truncate */ 427 return (space); 428 } 429 430 /* 431 * Non-line-oriented remote read. 432 */ 433 ssize_t 434 readrem(char *p, ssize_t space) 435 { 436 if (remleft <= 0) { 437 /* 438 * Set remote time out alarm. 439 */ 440 (void) signal(SIGALRM, sighandler); 441 (void) alarm(rtimeout); 442 443 remleft = remread(rem_r, rembuf, sizeof(rembuf)); 444 445 (void) alarm(0); 446 remptr = rembuf; 447 } 448 449 if (remleft <= 0) 450 return (remleft); 451 if (remleft < space) 452 space = remleft; 453 454 memcpy(p, remptr, space); 455 456 remptr += space; 457 remleft -= space; 458 459 return (space); 460 } 461 462 /* 463 * Get the user name for the uid. 464 */ 465 char * 466 getusername(UID_T uid, char *file, opt_t opts) 467 { 468 static char buf[100]; 469 static UID_T lastuid = (UID_T)-1; 470 struct passwd *pwd = NULL; 471 472 /* 473 * The value of opts may have changed so we always 474 * do the opts check. 475 */ 476 if (IS_ON(opts, DO_NUMCHKOWNER)) { 477 (void) snprintf(buf, sizeof(buf), ":%u", uid); 478 return(buf); 479 } 480 481 /* 482 * Try to avoid getpwuid() call. 483 */ 484 if (lastuid == uid && buf[0] != '\0' && buf[0] != ':') 485 return(buf); 486 487 lastuid = uid; 488 489 if ((pwd = getpwuid(uid)) == NULL) { 490 if (IS_ON(opts, DO_DEFOWNER) && !isserver) 491 (void) strlcpy(buf, defowner, sizeof(buf)); 492 else { 493 message(MT_WARNING, 494 "%s: No password entry for uid %u", file, uid); 495 (void) snprintf(buf, sizeof(buf), ":%u", uid); 496 } 497 } else { 498 (void) strlcpy(buf, pwd->pw_name, sizeof(buf)); 499 } 500 501 return(buf); 502 } 503 504 /* 505 * Get the group name for the gid. 506 */ 507 char * 508 getgroupname(GID_T gid, char *file, opt_t opts) 509 { 510 static char buf[100]; 511 static GID_T lastgid = (GID_T)-1; 512 struct group *grp = NULL; 513 514 /* 515 * The value of opts may have changed so we always 516 * do the opts check. 517 */ 518 if (IS_ON(opts, DO_NUMCHKGROUP)) { 519 (void) snprintf(buf, sizeof(buf), ":%u", gid); 520 return(buf); 521 } 522 523 /* 524 * Try to avoid getgrgid() call. 525 */ 526 if (lastgid == gid && buf[0] != '\0' && buf[0] != ':') 527 return(buf); 528 529 lastgid = gid; 530 531 if ((grp = (struct group *)getgrgid(gid)) == NULL) { 532 if (IS_ON(opts, DO_DEFGROUP) && !isserver) 533 (void) strlcpy(buf, defgroup, sizeof(buf)); 534 else { 535 message(MT_WARNING, "%s: No name for group %u", 536 file, gid); 537 (void) snprintf(buf, sizeof(buf), ":%u", gid); 538 } 539 } else 540 (void) strlcpy(buf, grp->gr_name, sizeof(buf)); 541 542 return(buf); 543 } 544 545 /* 546 * Read a response from the remote host. 547 */ 548 int 549 response(void) 550 { 551 static u_char resp[BUFSIZ]; 552 u_char *s; 553 int n; 554 555 debugmsg(DM_CALL, "response() start\n"); 556 557 n = remline(s = resp, sizeof(resp), 0); 558 559 n--; 560 switch (*s++) { 561 case C_ACK: 562 debugmsg(DM_PROTO, "received ACK\n"); 563 return(0); 564 case C_LOGMSG: 565 if (n > 0) { 566 message(MT_CHANGE, "%s", s); 567 return(1); 568 } 569 debugmsg(DM_PROTO, "received EMPTY logmsg\n"); 570 return(0); 571 case C_NOTEMSG: 572 if (s) 573 message(MT_NOTICE, "%s", s); 574 return(response()); 575 576 default: 577 s--; 578 n++; 579 /* fall into... */ 580 581 case C_ERRMSG: /* Normal error message */ 582 if (s) 583 message(MT_NERROR, "%s", s); 584 return(-1); 585 586 case C_FERRMSG: /* Fatal error message */ 587 if (s) 588 message(MT_FERROR, "%s", s); 589 finish(); 590 return(-1); 591 } 592 /*NOTREACHED*/ 593 } 594 595 /* 596 * This should be in expand.c but the other routines call other modules 597 * that we don't want to load in. 598 * 599 * Expand file names beginning with `~' into the 600 * user's home directory path name. Return a pointer in buf to the 601 * part corresponding to `file'. 602 */ 603 char * 604 exptilde(char *ebuf, char *file, size_t ebufsize) 605 { 606 char *pw_dir, *rest; 607 size_t len; 608 extern char *homedir; 609 610 if (*file != '~') { 611 notilde: 612 (void) strlcpy(ebuf, file, ebufsize); 613 return(ebuf); 614 } 615 if (*++file == CNULL) { 616 pw_dir = homedir; 617 rest = NULL; 618 } else if (*file == '/') { 619 pw_dir = homedir; 620 rest = file; 621 } else { 622 rest = file; 623 while (*rest && *rest != '/') 624 rest++; 625 if (*rest == '/') 626 *rest = CNULL; 627 else 628 rest = NULL; 629 if (pw == NULL || strcmp(pw->pw_name, file) != 0) { 630 if ((pw = getpwnam(file)) == NULL) { 631 error("%s: unknown user name", file); 632 if (rest != NULL) 633 *rest = '/'; 634 return(NULL); 635 } 636 } 637 if (rest != NULL) 638 *rest = '/'; 639 pw_dir = pw->pw_dir; 640 } 641 if ((len = strlcpy(ebuf, pw_dir, ebufsize)) >= ebufsize) 642 goto notilde; 643 pw_dir = ebuf + len; 644 if (rest != NULL) { 645 pw_dir++; 646 if ((len = strlcat(ebuf, rest, ebufsize)) >= ebufsize) 647 goto notilde; 648 } 649 return(pw_dir); 650 } 651 652 #if defined(DIRECT_RCMD) 653 /* 654 * Set our effective user id to the user running us. 655 * This should be the uid we do most of our work as. 656 */ 657 int 658 becomeuser(void) 659 { 660 int r = 0; 661 662 #if defined(HAVE_SAVED_IDS) 663 r = seteuid(userid); 664 #else 665 r = setreuid(0, userid); 666 #endif /* HAVE_SAVED_IDS */ 667 668 if (r < 0) 669 error("becomeuser %u failed: %s (ruid = %u euid = %u)", 670 userid, SYSERR, getuid(), geteuid()); 671 672 return(r); 673 } 674 #endif /* DIRECT_RCMD */ 675 676 #if defined(DIRECT_RCMD) 677 /* 678 * Set our effective user id to "root" (uid = 0) 679 */ 680 int 681 becomeroot(void) 682 { 683 int r = 0; 684 685 #if defined(HAVE_SAVED_IDS) 686 r = seteuid(0); 687 #else 688 r = setreuid(userid, 0); 689 #endif /* HAVE_SAVED_IDS */ 690 691 if (r < 0) 692 error("becomeroot failed: %s (ruid = %u euid = %u)", 693 SYSERR, getuid(), geteuid()); 694 695 return(r); 696 } 697 #endif /* DIRECT_RCMD */ 698 699 /* 700 * Set access and modify times of a given file 701 */ 702 int 703 setfiletime(char *file, time_t atime, time_t mtime) 704 { 705 #if SETFTIME_TYPE == SETFTIME_UTIMES 706 struct timeval tv[2]; 707 708 if (atime != 0 && mtime != 0) { 709 tv[0].tv_sec = atime; 710 tv[1].tv_sec = mtime; 711 tv[0].tv_usec = tv[1].tv_usec = (time_t) 0; 712 return(utimes(file, tv)); 713 } else /* Set to current time */ 714 return(utimes(file, NULL)); 715 716 #endif /* SETFTIME_UTIMES */ 717 718 #if SETFTIME_TYPE == SETFTIME_UTIME 719 struct utimbuf utbuf; 720 721 if (atime != 0 && mtime != 0) { 722 utbuf.actime = atime; 723 utbuf.modtime = mtime; 724 return(utime(file, &utbuf)); 725 } else /* Set to current time */ 726 return(utime(file, NULL)); 727 #endif /* SETFTIME_UTIME */ 728 729 #if !defined(SETFTIME_TYPE) 730 There is no "SETFTIME_TYPE" defined! 731 #endif /* SETFTIME_TYPE */ 732 } 733 734 /* 735 * Get version info 736 */ 737 char * 738 getversion(void) 739 { 740 static char buff[BUFSIZ]; 741 742 (void) snprintf(buff, sizeof(buff), 743 "Version %s.%d (%s) - Protocol Version %d, Release %s, Patch level %d", 744 DISTVERSION, PATCHLEVEL, DISTSTATUS, 745 VERSION, DISTVERSION, PATCHLEVEL); 746 747 return(buff); 748 } 749 750 /* 751 * Execute a shell command to handle special cases. 752 * This is now common to both server and client 753 */ 754 void 755 runcommand(char *cmd) 756 { 757 ssize_t nread; 758 pid_t pid, wpid; 759 char *cp, *s; 760 char sbuf[BUFSIZ], buf[BUFSIZ]; 761 int fd[2], status; 762 763 if (pipe(fd) < 0) { 764 error("pipe of %s failed: %s", cmd, SYSERR); 765 return; 766 } 767 768 if ((pid = fork()) == 0) { 769 /* 770 * Return everything the shell commands print. 771 */ 772 (void) close(0); 773 (void) close(1); 774 (void) close(2); 775 (void) open(_PATH_DEVNULL, O_RDONLY); 776 (void) dup(fd[PIPE_WRITE]); 777 (void) dup(fd[PIPE_WRITE]); 778 (void) close(fd[PIPE_READ]); 779 (void) close(fd[PIPE_WRITE]); 780 (void) execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL); 781 _exit(127); 782 } 783 (void) close(fd[PIPE_WRITE]); 784 s = sbuf; 785 *s++ = C_LOGMSG; 786 while ((nread = read(fd[PIPE_READ], buf, sizeof(buf))) > 0) { 787 cp = buf; 788 do { 789 *s++ = *cp++; 790 if (cp[-1] != '\n') { 791 if (s < (char *) &sbuf[sizeof(sbuf)-1]) 792 continue; 793 *s++ = '\n'; 794 } 795 /* 796 * Throw away blank lines. 797 */ 798 if (s == &sbuf[2]) { 799 s--; 800 continue; 801 } 802 if (isserver) 803 (void) xwrite(rem_w, sbuf, s - sbuf); 804 else { 805 *s = CNULL; 806 message(MT_INFO, "%s", sbuf+1); 807 } 808 s = &sbuf[1]; 809 } while (--nread); 810 } 811 if (s > (char *) &sbuf[1]) { 812 *s++ = '\n'; 813 if (isserver) 814 (void) xwrite(rem_w, sbuf, s - sbuf); 815 else { 816 *s = CNULL; 817 message(MT_INFO, "%s", sbuf+1); 818 } 819 } 820 while ((wpid = wait(&status)) != pid && wpid != -1) 821 ; 822 if (wpid == -1) 823 status = -1; 824 (void) close(fd[PIPE_READ]); 825 if (status) 826 error("shell returned %d", status); 827 else if (isserver) 828 ack(); 829 } 830 831 /* 832 * Malloc with error checking 833 */ 834 char * 835 xmalloc(size_t amt) 836 { 837 char *ptr; 838 839 if ((ptr = (char *)malloc(amt)) == NULL) 840 fatalerr("Cannot malloc %zu bytes of memory.", amt); 841 842 return(ptr); 843 } 844 845 /* 846 * realloc with error checking 847 */ 848 char * 849 xrealloc(char *baseptr, size_t amt) 850 { 851 char *new; 852 853 if ((new = (char *)realloc(baseptr, amt)) == NULL) 854 fatalerr("Cannot realloc %zu bytes of memory.", amt); 855 856 return(new); 857 } 858 859 /* 860 * calloc with error checking 861 */ 862 char * 863 xcalloc(size_t num, size_t esize) 864 { 865 char *ptr; 866 867 if ((ptr = (char *)calloc(num, esize)) == NULL) 868 fatalerr("Cannot calloc %zu * %zu = %zu bytes of memory.", 869 num, esize, num * esize); 870 871 return(ptr); 872 } 873 874 /* 875 * Strdup with error checking 876 */ 877 char * 878 xstrdup(const char *str) 879 { 880 size_t len = strlen(str) + 1; 881 char *nstr = (char *) malloc(len); 882 883 if (nstr == NULL) 884 fatalerr("Cannot malloc %zu bytes of memory.", len); 885 886 return(memcpy(nstr, str, len)); 887 } 888 889 /* 890 * Private version of basename() 891 */ 892 char * 893 xbasename(char *path) 894 { 895 char *cp; 896 897 if ((cp = strrchr(path, '/')) != NULL) 898 return(cp+1); 899 else 900 return(path); 901 } 902 903 /* 904 * Take a colon (':') separated path to a file and 905 * search until a component of that path is found and 906 * return the found file name. 907 */ 908 char * 909 searchpath(char *path) 910 { 911 char *file; 912 char *space; 913 int found; 914 struct stat statbuf; 915 916 for (found = 0; !found && (file = strsep(&path, ":")) != NULL; ) { 917 if ((space = strchr(file, ' ')) != NULL) 918 *space = CNULL; 919 found = stat(file, &statbuf) == 0; 920 if (space) 921 *space = ' '; /* Put back what we zapped */ 922 } 923 return (file); 924 } 925 926 /* 927 * Set line buffering. 928 */ 929 int 930 mysetlinebuf(FILE *fp) 931 { 932 #if SETBUF_TYPE == SETBUF_SETLINEBUF 933 return(setlinebuf(fp)); 934 #endif /* SETBUF_SETLINEBUF */ 935 #if SETBUF_TYPE == SETBUF_SETVBUF 936 return(setvbuf(stdout, NULL, _IOLBF, BUFSIZ)); 937 #endif /* SETBUF_SETVBUF */ 938 #if !defined(SETBUF_TYPE) 939 No SETBUF_TYPE is defined! 940 #endif /* SETBUF_TYPE */ 941 } 942