Annotation of src/usr.bin/patch/util.c, Revision 1.13
1.13 ! deraadt 1: /* $OpenBSD: util.c,v 1.12 2003/07/18 02:00:09 deraadt Exp $ */
1.2 niklas 2:
1.1 deraadt 3: #ifndef lint
1.13 ! deraadt 4: static char rcsid[] = "$OpenBSD: util.c,v 1.12 2003/07/18 02:00:09 deraadt Exp $";
! 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: ;
! 169: rv = malloc((MEM) (t - s));
! 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: }