Annotation of src/usr.bin/patch/util.c, Revision 1.41
1.41 ! anton 1: /* $OpenBSD: util.c,v 1.40 2015/07/26 14:32:19 millert Exp $ */
1.26 otto 2:
3: /*
4: * patch - a program to apply diffs to original files
5: *
6: * Copyright 1986, Larry Wall
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following condition is met:
10: * 1. Redistributions of source code must retain the above copyright notice,
11: * this condition and the following disclaimer.
12: *
13: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
14: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
17: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23: * SUCH DAMAGE.
24: *
25: * -C option added in 1998, original code by Marc Espie, based on FreeBSD
26: * behaviour
27: */
1.1 deraadt 28:
1.16 otto 29: #include <sys/stat.h>
30:
31: #include <ctype.h>
32: #include <errno.h>
33: #include <fcntl.h>
34: #include <libgen.h>
35: #include <paths.h>
1.32 otto 36: #include <signal.h>
1.16 otto 37: #include <stdarg.h>
38: #include <stdlib.h>
1.20 otto 39: #include <stdio.h>
1.16 otto 40: #include <string.h>
41: #include <unistd.h>
42:
1.1 deraadt 43: #include "common.h"
44: #include "util.h"
45: #include "backupfile.h"
46:
47: /* Rename a file, copying it if necessary. */
48:
49: int
1.20 otto 50: move_file(const char *from, const char *to)
1.1 deraadt 51: {
1.20 otto 52: int fromfd;
53: ssize_t i;
1.1 deraadt 54:
1.13 deraadt 55: /* to stdout? */
1.1 deraadt 56:
1.13 deraadt 57: if (strEQ(to, "-")) {
1.1 deraadt 58: #ifdef DEBUGGING
1.13 deraadt 59: if (debug & 4)
60: say("Moving %s to stdout.\n", from);
1.1 deraadt 61: #endif
1.13 deraadt 62: fromfd = open(from, O_RDONLY);
63: if (fromfd < 0)
64: pfatal("internal error, can't reopen %s", from);
65: while ((i = read(fromfd, buf, sizeof buf)) > 0)
1.16 otto 66: if (write(STDOUT_FILENO, buf, i) != i)
1.13 deraadt 67: pfatal("write failed");
68: close(fromfd);
69: return 0;
1.1 deraadt 70: }
1.18 millert 71: if (backup_file(to) < 0) {
72: say("Can't backup %s, output is in %s: %s\n", to, from,
73: strerror(errno));
74: return -1;
75: }
76: #ifdef DEBUGGING
77: if (debug & 4)
78: say("Moving %s to %s.\n", from, to);
79: #endif
80: if (rename(from, to) < 0) {
81: if (errno != EXDEV || copy_file(from, to) < 0) {
82: say("Can't create %s, output is in %s: %s\n",
83: to, from, strerror(errno));
84: return -1;
85: }
86: }
87: return 0;
88: }
89:
90: /* Backup the original file. */
91:
92: int
1.20 otto 93: backup_file(const char *orig)
1.18 millert 94: {
1.20 otto 95: struct stat filestat;
1.39 deraadt 96: char bakname[PATH_MAX], *s, *simplename;
1.20 otto 97: dev_t orig_device;
98: ino_t orig_inode;
1.18 millert 99:
100: if (backup_type == none || stat(orig, &filestat) != 0)
101: return 0; /* nothing to do */
102: orig_device = filestat.st_dev;
103: orig_inode = filestat.st_ino;
104:
1.13 deraadt 105: if (origprae) {
106: if (strlcpy(bakname, origprae, sizeof(bakname)) >= sizeof(bakname) ||
1.18 millert 107: strlcat(bakname, orig, sizeof(bakname)) >= sizeof(bakname))
1.13 deraadt 108: fatal("filename %s too long for buffer\n", origprae);
109: } else {
1.18 millert 110: if ((s = find_backup_file_name(orig)) == NULL)
1.13 deraadt 111: fatal("out of memory\n");
1.18 millert 112: if (strlcpy(bakname, s, sizeof(bakname)) >= sizeof(bakname))
113: fatal("filename %s too long for buffer\n", s);
114: free(s);
1.1 deraadt 115: }
1.13 deraadt 116:
1.18 millert 117: if ((simplename = strrchr(bakname, '/')) != NULL)
118: simplename = simplename + 1;
119: else
120: simplename = bakname;
121:
122: /*
123: * Find a backup name that is not the same file. Change the
124: * first lowercase char into uppercase; if that isn't
125: * sufficient, chop off the first char and try again.
126: */
127: while (stat(bakname, &filestat) == 0 &&
128: orig_device == filestat.st_dev && orig_inode == filestat.st_ino) {
129: /* Skip initial non-lowercase chars. */
1.36 deraadt 130: for (s = simplename; *s && !islower((unsigned char)*s); s++)
1.18 millert 131: ;
132: if (*s)
1.36 deraadt 133: *s = toupper((unsigned char)*s);
1.18 millert 134: else
135: memmove(simplename, simplename + 1,
136: strlen(simplename + 1) + 1);
1.1 deraadt 137: }
138: #ifdef DEBUGGING
1.13 deraadt 139: if (debug & 4)
1.18 millert 140: say("Moving %s to %s.\n", orig, bakname);
1.1 deraadt 141: #endif
1.18 millert 142: if (rename(orig, bakname) < 0) {
143: if (errno != EXDEV || copy_file(orig, bakname) < 0)
1.13 deraadt 144: return -1;
145: }
146: return 0;
147: }
148:
149: /*
150: * Copy a file.
151: */
1.18 millert 152: int
1.20 otto 153: copy_file(const char *from, const char *to)
1.13 deraadt 154: {
1.20 otto 155: int tofd, fromfd;
156: ssize_t i;
1.12 deraadt 157:
1.18 millert 158: tofd = open(to, O_CREAT|O_TRUNC|O_WRONLY, 0666);
1.13 deraadt 159: if (tofd < 0)
1.18 millert 160: return -1;
161: fromfd = open(from, O_RDONLY, 0);
1.1 deraadt 162: if (fromfd < 0)
1.13 deraadt 163: pfatal("internal error, can't reopen %s", from);
164: while ((i = read(fromfd, buf, sizeof buf)) > 0)
165: if (write(tofd, buf, i) != i)
166: pfatal("write to %s failed", to);
1.12 deraadt 167: close(fromfd);
168: close(tofd);
1.18 millert 169: return 0;
1.1 deraadt 170: }
171:
1.13 deraadt 172: /*
173: * Allocate a unique area for a string.
174: */
1.1 deraadt 175: char *
1.20 otto 176: savestr(const char *s)
1.1 deraadt 177: {
1.20 otto 178: char *rv;
1.1 deraadt 179:
1.13 deraadt 180: if (!s)
181: s = "Oops";
1.20 otto 182: rv = strdup(s);
1.16 otto 183: if (rv == NULL) {
1.13 deraadt 184: if (using_plan_a)
1.25 otto 185: out_of_mem = true;
1.13 deraadt 186: else
187: fatal("out of memory\n");
188: }
1.38 tobias 189: return rv;
190: }
191:
192: /*
193: * Allocate a unique area for a string. Call fatal if out of memory.
194: */
195: char *
196: xstrdup(const char *s)
197: {
198: char *rv;
199:
200: if (!s)
201: s = "Oops";
202: rv = strdup(s);
203: if (rv == NULL)
204: fatal("out of memory\n");
1.13 deraadt 205: return rv;
1.1 deraadt 206: }
207:
1.13 deraadt 208: /*
209: * Vanilla terminal output (buffered).
210: */
1.1 deraadt 211: void
1.20 otto 212: say(const char *fmt, ...)
1.1 deraadt 213: {
1.13 deraadt 214: va_list ap;
1.12 deraadt 215:
1.13 deraadt 216: va_start(ap, fmt);
1.35 ray 217: vfprintf(stdout, fmt, ap);
1.13 deraadt 218: va_end(ap);
1.35 ray 219: fflush(stdout);
1.1 deraadt 220: }
221:
1.13 deraadt 222: /*
223: * Terminal output, pun intended.
224: */
1.12 deraadt 225: void
1.20 otto 226: fatal(const char *fmt, ...)
1.1 deraadt 227: {
1.13 deraadt 228: va_list ap;
1.12 deraadt 229:
1.13 deraadt 230: va_start(ap, fmt);
231: fprintf(stderr, "patch: **** ");
232: vfprintf(stderr, fmt, ap);
233: va_end(ap);
1.19 millert 234: my_exit(2);
1.1 deraadt 235: }
236:
1.13 deraadt 237: /*
238: * Say something from patch, something from the system, then silence . . .
239: */
1.12 deraadt 240: void
1.20 otto 241: pfatal(const char *fmt, ...)
1.1 deraadt 242: {
1.13 deraadt 243: va_list ap;
244: int errnum = errno;
1.1 deraadt 245:
1.13 deraadt 246: fprintf(stderr, "patch: **** ");
247: va_start(ap, fmt);
248: vfprintf(stderr, fmt, ap);
249: va_end(ap);
250: fprintf(stderr, ": %s\n", strerror(errnum));
1.19 millert 251: my_exit(2);
1.1 deraadt 252: }
253:
1.13 deraadt 254: /*
1.23 millert 255: * Get a response from the user via /dev/tty
1.13 deraadt 256: */
1.1 deraadt 257: void
1.20 otto 258: ask(const char *fmt, ...)
1.1 deraadt 259: {
1.13 deraadt 260: va_list ap;
1.23 millert 261: ssize_t nr;
262: static int ttyfd = -1;
1.13 deraadt 263:
264: va_start(ap, fmt);
1.23 millert 265: vfprintf(stdout, fmt, ap);
1.13 deraadt 266: va_end(ap);
1.23 millert 267: fflush(stdout);
268: if (ttyfd < 0)
269: ttyfd = open(_PATH_TTY, O_RDONLY);
270: if (ttyfd >= 0) {
271: if ((nr = read(ttyfd, buf, sizeof(buf))) > 0 &&
272: buf[nr - 1] == '\n')
273: buf[nr - 1] = '\0';
274: }
275: if (ttyfd < 0 || nr <= 0) {
276: /* no tty or error reading, pretend user entered 'return' */
277: putchar('\n');
278: buf[0] = '\0';
1.13 deraadt 279: }
1.1 deraadt 280: }
281:
1.13 deraadt 282: /*
283: * How to handle certain events when not in a critical region.
284: */
1.1 deraadt 285: void
1.13 deraadt 286: set_signals(int reset)
1.1 deraadt 287: {
1.13 deraadt 288: static sig_t hupval, intval;
1.1 deraadt 289:
1.13 deraadt 290: if (!reset) {
291: hupval = signal(SIGHUP, SIG_IGN);
292: if (hupval != SIG_IGN)
293: hupval = (sig_t) my_exit;
294: intval = signal(SIGINT, SIG_IGN);
295: if (intval != SIG_IGN)
296: intval = (sig_t) my_exit;
297: }
298: signal(SIGHUP, hupval);
299: signal(SIGINT, intval);
1.1 deraadt 300: }
301:
1.13 deraadt 302: /*
303: * How to handle certain events when in a critical region.
304: */
1.1 deraadt 305: void
1.13 deraadt 306: ignore_signals(void)
1.1 deraadt 307: {
1.13 deraadt 308: signal(SIGHUP, SIG_IGN);
309: signal(SIGINT, SIG_IGN);
1.1 deraadt 310: }
311:
1.13 deraadt 312: /*
313: * Make sure we'll have the directories to create a file. If `striplast' is
1.25 otto 314: * true, ignore the last element of `filename'.
1.13 deraadt 315: */
1.1 deraadt 316:
317: void
1.20 otto 318: makedirs(const char *filename, bool striplast)
1.1 deraadt 319: {
1.13 deraadt 320: char *tmpbuf;
1.9 provos 321:
1.13 deraadt 322: if ((tmpbuf = strdup(filename)) == NULL)
323: fatal("out of memory\n");
1.9 provos 324:
1.13 deraadt 325: if (striplast) {
326: char *s = strrchr(tmpbuf, '/');
1.34 oga 327: if (s == NULL) {
328: free(tmpbuf);
1.13 deraadt 329: return; /* nothing to be done */
1.34 oga 330: }
1.13 deraadt 331: *s = '\0';
332: }
1.31 otto 333: if (mkpath(tmpbuf) != 0)
1.30 espie 334: pfatal("creation of %s failed", tmpbuf);
335: free(tmpbuf);
1.1 deraadt 336: }
337:
1.13 deraadt 338: /*
339: * Make filenames more reasonable.
340: */
341: char *
1.27 millert 342: fetchname(const char *at, bool *exists, int strip_leading)
1.13 deraadt 343: {
1.27 millert 344: char *fullname, *name, *t;
1.29 otto 345: int sleading, tab;
1.20 otto 346: struct stat filestat;
1.1 deraadt 347:
1.20 otto 348: if (at == NULL || *at == '\0')
1.16 otto 349: return NULL;
1.36 deraadt 350: while (isspace((unsigned char)*at))
1.13 deraadt 351: at++;
1.1 deraadt 352: #ifdef DEBUGGING
1.13 deraadt 353: if (debug & 128)
1.27 millert 354: say("fetchname %s %d\n", at, strip_leading);
1.1 deraadt 355: #endif
1.22 millert 356: /* So files can be created by diffing against /dev/null. */
357: if (strnEQ(at, _PATH_DEVNULL, sizeof(_PATH_DEVNULL) - 1))
358: return NULL;
1.13 deraadt 359: name = fullname = t = savestr(at);
360:
1.29 otto 361: tab = strchr(t, '\t') != NULL;
1.21 millert 362: /* Strip off up to `strip_leading' path components and NUL terminate. */
1.29 otto 363: for (sleading = strip_leading; *t != '\0' && ((tab && *t != '\t') ||
1.36 deraadt 364: !isspace((unsigned char)*t)); t++) {
1.21 millert 365: if (t[0] == '/' && t[1] != '/' && t[1] != '\0')
1.24 otto 366: if (--sleading >= 0)
1.13 deraadt 367: name = t + 1;
1.21 millert 368: }
1.13 deraadt 369: *t = '\0';
370:
371: /*
372: * If no -p option was given (957 is the default value!), we were
373: * given a relative pathname, and the leading directories that we
374: * just stripped off all exist, put them back on.
375: */
376: if (strip_leading == 957 && name != fullname && *fullname != '/') {
377: name[-1] = '\0';
378: if (stat(fullname, &filestat) == 0 && S_ISDIR(filestat.st_mode)) {
379: name[-1] = '/';
380: name = fullname;
381: }
1.1 deraadt 382: }
1.13 deraadt 383: name = savestr(name);
384: free(fullname);
1.1 deraadt 385:
1.27 millert 386: *exists = stat(name, &filestat) == 0;
387: return name;
1.12 deraadt 388: }
389:
390: void
1.13 deraadt 391: version(void)
1.12 deraadt 392: {
1.13 deraadt 393: fprintf(stderr, "Patch version 2.0-12u8-OpenBSD\n");
1.19 millert 394: my_exit(EXIT_SUCCESS);
1.16 otto 395: }
396:
397: /*
398: * Exit with cleanup.
399: */
400: void
401: my_exit(int status)
402: {
403: unlink(TMPINNAME);
404: if (!toutkeep)
405: unlink(TMPOUTNAME);
406: if (!trejkeep)
407: unlink(TMPREJNAME);
408: unlink(TMPPATNAME);
409: exit(status);
1.1 deraadt 410: }