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