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