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