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