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