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