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