Annotation of src/usr.bin/patch/util.c, Revision 1.14
1.14 ! deraadt 1: /* $OpenBSD: util.c,v 1.13 2003/07/21 14:00:41 deraadt Exp $ */
1.2 niklas 2:
1.1 deraadt 3: #ifndef lint
1.14 ! deraadt 4: static char rcsid[] = "$OpenBSD: util.c,v 1.13 2003/07/21 14:00:41 deraadt Exp $";
1.13 deraadt 5: #endif /* not lint */
1.1 deraadt 6:
7: #include "EXTERN.h"
8: #include "common.h"
9: #include "INTERN.h"
10: #include "util.h"
11: #include "backupfile.h"
12:
1.13 deraadt 13: void my_exit(int) __attribute__((noreturn));
1.1 deraadt 14:
15: /* Rename a file, copying it if necessary. */
16:
17: int
1.13 deraadt 18: move_file(char *from, char *to)
1.1 deraadt 19: {
1.13 deraadt 20: char bakname[MAXPATHLEN], *s;
21: int i, fromfd;
1.1 deraadt 22:
1.13 deraadt 23: /* to stdout? */
1.1 deraadt 24:
1.13 deraadt 25: if (strEQ(to, "-")) {
1.1 deraadt 26: #ifdef DEBUGGING
1.13 deraadt 27: if (debug & 4)
28: say("Moving %s to stdout.\n", from);
1.1 deraadt 29: #endif
1.13 deraadt 30: fromfd = open(from, O_RDONLY);
31: if (fromfd < 0)
32: pfatal("internal error, can't reopen %s", from);
33: while ((i = read(fromfd, buf, sizeof buf)) > 0)
34: if (write(1, buf, i) != 1)
35: pfatal("write failed");
36: close(fromfd);
37: return 0;
1.1 deraadt 38: }
1.13 deraadt 39: if (origprae) {
40: if (strlcpy(bakname, origprae, sizeof(bakname)) >= sizeof(bakname) ||
41: strlcat(bakname, to, sizeof(bakname)) >= sizeof(bakname))
42: fatal("filename %s too long for buffer\n", origprae);
43: } else {
44: char *backupname = find_backup_file_name(to);
45: if (backupname == (char *) 0)
46: fatal("out of memory\n");
47: if (strlcpy(bakname, backupname, sizeof(bakname)) >= sizeof(bakname))
48: fatal("filename %s too long for buffer\n", backupname);
49: free(backupname);
1.1 deraadt 50: }
1.13 deraadt 51:
52: if (stat(to, &filestat) == 0) { /* output file exists */
53: dev_t to_device = filestat.st_dev;
54: ino_t to_inode = filestat.st_ino;
55: char *simplename = bakname;
56:
57: for (s = bakname; *s; s++) {
58: if (*s == '/')
59: simplename = s + 1;
60: }
61:
62: /*
63: * Find a backup name that is not the same file. Change the
64: * first lowercase char into uppercase; if that isn't
65: * sufficient, chop off the first char and try again.
66: */
67: while (stat(bakname, &filestat) == 0 &&
68: to_device == filestat.st_dev && to_inode == filestat.st_ino) {
69: /* Skip initial non-lowercase chars. */
70: for (s = simplename; *s && !islower(*s); s++)
71: ;
72: if (*s)
73: *s = toupper(*s);
74: else
75: memmove(simplename, simplename + 1,
76: strlen(simplename + 1) + 1);
77: }
78: unlink(bakname);
79:
1.1 deraadt 80: #ifdef DEBUGGING
1.13 deraadt 81: if (debug & 4)
82: say("Moving %s to %s.\n", to, bakname);
1.1 deraadt 83: #endif
1.13 deraadt 84: if (link(to, bakname) < 0) {
85: /*
86: * Maybe `to' is a symlink into a different file
87: * system. Copying replaces the symlink with a file;
88: * using rename would be better.
89: */
90: int tofd, bakfd;
91:
92: bakfd = creat(bakname, 0666);
93: if (bakfd < 0) {
94: say("Can't backup %s, output is in %s: %s\n",
95: to, from, strerror(errno));
96: return -1;
97: }
98: tofd = open(to, O_RDONLY);
99: if (tofd < 0)
100: pfatal("internal error, can't open %s", to);
101: while ((i = read(tofd, buf, sizeof buf)) > 0)
102: if (write(bakfd, buf, i) != i)
103: pfatal("write failed");
104: close(tofd);
105: close(bakfd);
106: }
107: unlink(to);
1.1 deraadt 108: }
109: #ifdef DEBUGGING
1.13 deraadt 110: if (debug & 4)
111: say("Moving %s to %s.\n", from, to);
1.1 deraadt 112: #endif
1.13 deraadt 113: if (link(from, to) < 0) { /* different file system? */
114: int tofd;
115:
116: tofd = creat(to, 0666);
117: if (tofd < 0) {
118: say("Can't create %s, output is in %s: %s\n",
119: to, from, strerror(errno));
120: return -1;
121: }
122: fromfd = open(from, O_RDONLY);
123: if (fromfd < 0)
124: pfatal("internal error, can't reopen %s", from);
125: while ((i = read(fromfd, buf, sizeof buf)) > 0)
126: if (write(tofd, buf, i) != i)
127: pfatal("write failed");
128: close(fromfd);
129: close(tofd);
130: }
131: unlink(from);
132: return 0;
133: }
134:
135: /*
136: * Copy a file.
137: */
138: void
139: copy_file(char *from, char *to)
140: {
141: int tofd, fromfd, i;
1.12 deraadt 142:
1.1 deraadt 143: tofd = creat(to, 0666);
1.13 deraadt 144: if (tofd < 0)
145: pfatal("can't create %s", to);
1.4 millert 146: fromfd = open(from, O_RDONLY);
1.1 deraadt 147: if (fromfd < 0)
1.13 deraadt 148: pfatal("internal error, can't reopen %s", from);
149: while ((i = read(fromfd, buf, sizeof buf)) > 0)
150: if (write(tofd, buf, i) != i)
151: pfatal("write to %s failed", to);
1.12 deraadt 152: close(fromfd);
153: close(tofd);
1.1 deraadt 154: }
155:
1.13 deraadt 156: /*
157: * Allocate a unique area for a string.
158: */
1.1 deraadt 159: char *
1.13 deraadt 160: savestr(char *s)
1.1 deraadt 161: {
1.13 deraadt 162: char *rv, *t;
1.1 deraadt 163:
1.13 deraadt 164: if (!s)
165: s = "Oops";
166: t = s;
167: while (*t++)
168: ;
1.14 ! deraadt 169: rv = malloc((size_t) (t - s));
1.13 deraadt 170: if (rv == Nullch) {
171: if (using_plan_a)
172: out_of_mem = TRUE;
173: else
174: fatal("out of memory\n");
175: } else {
176: t = rv;
177: while ((*t++ = *s++))
178: ;
179: }
180: return rv;
1.1 deraadt 181: }
182:
1.13 deraadt 183: /*
184: * Vanilla terminal output (buffered).
185: */
1.1 deraadt 186: void
1.12 deraadt 187: say(char *fmt, ...)
1.1 deraadt 188: {
1.13 deraadt 189: va_list ap;
1.12 deraadt 190:
1.13 deraadt 191: va_start(ap, fmt);
192: vfprintf(stderr, fmt, ap);
193: va_end(ap);
194: fflush(stderr);
1.1 deraadt 195: }
196:
1.13 deraadt 197: /*
198: * Terminal output, pun intended.
199: */
1.12 deraadt 200: void
201: fatal(char *fmt, ...)
1.1 deraadt 202: {
1.13 deraadt 203: va_list ap;
1.12 deraadt 204:
1.13 deraadt 205: va_start(ap, fmt);
206: fprintf(stderr, "patch: **** ");
207: vfprintf(stderr, fmt, ap);
208: va_end(ap);
209: my_exit(1);
1.1 deraadt 210: }
211:
1.13 deraadt 212: /*
213: * Say something from patch, something from the system, then silence . . .
214: */
1.12 deraadt 215: void
216: pfatal(char *fmt, ...)
1.1 deraadt 217: {
1.13 deraadt 218: va_list ap;
219: int errnum = errno;
1.1 deraadt 220:
1.13 deraadt 221: fprintf(stderr, "patch: **** ");
222: va_start(ap, fmt);
223: vfprintf(stderr, fmt, ap);
224: va_end(ap);
225: fprintf(stderr, ": %s\n", strerror(errnum));
226: my_exit(1);
1.1 deraadt 227: }
228:
1.13 deraadt 229: /*
230: * Get a response from the user, somehow or other.
231: */
1.1 deraadt 232: void
1.12 deraadt 233: ask(char *fmt, ...)
1.1 deraadt 234: {
1.13 deraadt 235: va_list ap;
236: int ttyfd, r;
237: bool tty2 = isatty(2);
238:
239: va_start(ap, fmt);
240: vsnprintf(buf, sizeof buf, fmt, ap);
241: va_end(ap);
242: fflush(stderr);
243: write(2, buf, strlen(buf));
244: if (tty2) {
245: /* might be redirected to a file */
246: r = read(2, buf, sizeof buf);
247: } else if (isatty(1)) { /* this may be new file output */
248: fflush(stdout);
249: write(1, buf, strlen(buf));
250: r = read(1, buf, sizeof buf);
251: } else if ((ttyfd = open(_PATH_TTY, O_RDWR)) >= 0 && isatty(ttyfd)) {
252: /* might be deleted or unwriteable */
253: write(ttyfd, buf, strlen(buf));
254: r = read(ttyfd, buf, sizeof buf);
255: close(ttyfd);
256: } else if (isatty(0)) { /* this is probably patch input */
257: fflush(stdin);
258: write(0, buf, strlen(buf));
259: r = read(0, buf, sizeof buf);
260: } else { /* no terminal at all--default it */
261: buf[0] = '\n';
262: r = 1;
263: }
264: if (r <= 0)
265: buf[0] = 0;
266: else
267: buf[r] = '\0';
268: if (!tty2)
269: say(buf);
1.1 deraadt 270: }
271:
1.13 deraadt 272: /*
273: * How to handle certain events when not in a critical region.
274: */
1.1 deraadt 275: void
1.13 deraadt 276: set_signals(int reset)
1.1 deraadt 277: {
278: #ifndef lint
1.13 deraadt 279: static sig_t hupval, intval;
1.1 deraadt 280:
1.13 deraadt 281: if (!reset) {
282: hupval = signal(SIGHUP, SIG_IGN);
283: if (hupval != SIG_IGN)
284: hupval = (sig_t) my_exit;
285: intval = signal(SIGINT, SIG_IGN);
286: if (intval != SIG_IGN)
287: intval = (sig_t) my_exit;
288: }
289: signal(SIGHUP, hupval);
290: signal(SIGINT, intval);
1.1 deraadt 291: #endif
292: }
293:
1.13 deraadt 294: /*
295: * How to handle certain events when in a critical region.
296: */
1.1 deraadt 297: void
1.13 deraadt 298: ignore_signals(void)
1.1 deraadt 299: {
300: #ifndef lint
1.13 deraadt 301: signal(SIGHUP, SIG_IGN);
302: signal(SIGINT, SIG_IGN);
1.1 deraadt 303: #endif
304: }
305:
1.13 deraadt 306: /*
307: * Make sure we'll have the directories to create a file. If `striplast' is
308: * TRUE, ignore the last element of `filename'.
309: */
1.1 deraadt 310:
311: void
1.13 deraadt 312: makedirs(char *filename, bool striplast)
1.1 deraadt 313: {
1.13 deraadt 314: char *tmpbuf;
1.9 provos 315:
1.13 deraadt 316: if ((tmpbuf = strdup(filename)) == NULL)
317: fatal("out of memory\n");
1.9 provos 318:
1.13 deraadt 319: if (striplast) {
320: char *s = strrchr(tmpbuf, '/');
321: if (s == NULL)
322: return; /* nothing to be done */
323: *s = '\0';
324: }
325: strlcpy(buf, "/bin/mkdir -p ", sizeof buf);
326: if (strlcat(buf, tmpbuf, sizeof(buf)) >= sizeof(buf))
327: fatal("buffer too small to hold %.20s...\n", tmpbuf);
1.9 provos 328:
1.13 deraadt 329: if (system(buf))
330: pfatal("%.40s failed", buf);
1.1 deraadt 331: }
332:
1.13 deraadt 333: /*
334: * Make filenames more reasonable.
335: */
336: char *
337: fetchname(char *at, int strip_leading, int assume_exists)
338: {
339: char *fullname, *name, *t, tmpbuf[200];
340: int sleading = strip_leading;
1.1 deraadt 341:
1.13 deraadt 342: if (!at || *at == '\0')
343: return Nullch;
344: while (isspace(*at))
345: at++;
1.1 deraadt 346: #ifdef DEBUGGING
1.13 deraadt 347: if (debug & 128)
348: say("fetchname %s %d %d\n", at, strip_leading, assume_exists);
1.1 deraadt 349: #endif
1.13 deraadt 350: if (strnEQ(at, "/dev/null", 9)) /* so files can be created by diffing */
351: return Nullch; /* against /dev/null. */
352: name = fullname = t = savestr(at);
353:
354: /* Strip off up to `sleading' leading slashes and null terminate. */
355: for (; *t && !isspace(*t); t++)
356: if (*t == '/')
357: if (--sleading >= 0)
358: name = t + 1;
359: *t = '\0';
360:
361: /*
362: * If no -p option was given (957 is the default value!), we were
363: * given a relative pathname, and the leading directories that we
364: * just stripped off all exist, put them back on.
365: */
366: if (strip_leading == 957 && name != fullname && *fullname != '/') {
367: name[-1] = '\0';
368: if (stat(fullname, &filestat) == 0 && S_ISDIR(filestat.st_mode)) {
369: name[-1] = '/';
370: name = fullname;
371: }
1.1 deraadt 372: }
1.13 deraadt 373: name = savestr(name);
374: free(fullname);
1.1 deraadt 375:
1.13 deraadt 376: if (stat(name, &filestat) && !assume_exists) {
377: char *filebase = basename(name);
378: char *filedir = dirname(name);
379:
380: #define try(f, a1, a2, a3) \
381: (snprintf(tmpbuf, sizeof tmpbuf, f, a1, a2, a3), stat(tmpbuf, &filestat) == 0)
382:
383: if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) ||
384: try("%s/RCS/%s%s", filedir, filebase, "") ||
385: try("%s/%s%s", filedir, filebase, RCSSUFFIX) ||
386: try("%s/SCCS/%s%s", filedir, SCCSPREFIX, filebase) ||
387: try("%s/%s%s", filedir, SCCSPREFIX, filebase))
388: return name;
389: free(name);
390: name = Nullch;
391: }
392: return name;
1.12 deraadt 393: }
394:
395: void
1.13 deraadt 396: version(void)
1.12 deraadt 397: {
1.13 deraadt 398: fprintf(stderr, "Patch version 2.0-12u8-OpenBSD\n");
399: my_exit(0);
1.1 deraadt 400: }