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