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