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