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