Annotation of src/usr.bin/patch/patch.c, Revision 1.73
1.73 ! florian 1: /* $OpenBSD: patch.c,v 1.72 2023/07/12 11:26:13 tb Exp $ */
1.2 niklas 2:
1.20 deraadt 3: /*
4: * patch - a program to apply diffs to original files
5: *
1.1 deraadt 6: * Copyright 1986, Larry Wall
1.20 deraadt 7: *
1.14 niklas 8: * Redistribution and use in source and binary forms, with or without
1.20 deraadt 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
1.14 niklas 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.
1.20 deraadt 24: *
25: * -C option added in 1998, original code by Marc Espie, based on FreeBSD
26: * behaviour
1.1 deraadt 27: */
28:
1.23 otto 29: #include <sys/types.h>
30: #include <sys/stat.h>
31: #include <unistd.h>
32:
33: #include <ctype.h>
1.24 millert 34: #include <getopt.h>
1.25 millert 35: #include <limits.h>
1.65 anton 36: #include <paths.h>
1.29 otto 37: #include <stdio.h>
1.23 otto 38: #include <string.h>
39: #include <stdlib.h>
40:
1.1 deraadt 41: #include "common.h"
42: #include "util.h"
43: #include "pch.h"
44: #include "inp.h"
45: #include "backupfile.h"
1.60 tobias 46: #include "ed.h"
1.1 deraadt 47:
1.44 otto 48: mode_t filemode = 0644;
1.29 otto 49:
1.69 jca 50: char *buf; /* general purpose buffer */
51: size_t bufsz; /* general purpose buffer size */
1.29 otto 52:
1.35 otto 53: bool using_plan_a = true; /* try to keep everything in memory */
54: bool out_of_mem = false; /* ran out of memory in plan a */
1.29 otto 55:
56: #define MAXFILEC 2
57:
58: char *filearg[MAXFILEC];
1.35 otto 59: bool ok_to_create_file = false;
1.29 otto 60: char *outname = NULL;
61: char *origprae = NULL;
62: char *TMPOUTNAME;
63: char *TMPINNAME;
64: char *TMPREJNAME;
65: char *TMPPATNAME;
1.35 otto 66: bool toutkeep = false;
67: bool trejkeep = false;
1.33 otto 68: bool warn_on_invalid_line;
1.37 otto 69: bool last_line_missing_eol;
1.29 otto 70:
71: #ifdef DEBUGGING
1.30 deraadt 72: int debug = 0;
1.29 otto 73: #endif
74:
1.35 otto 75: bool force = false;
76: bool batch = false;
77: bool verbose = true;
78: bool reverse = false;
79: bool noreverse = false;
80: bool skip_rest_of_patch = false;
1.29 otto 81: int strippath = 957;
1.35 otto 82: bool canonicalize = false;
83: bool check_only = false;
1.29 otto 84: int diff_type = 0;
85: char *revision = NULL; /* prerequisite revision, if any */
86: LINENUM input_lines = 0; /* how long is input file in lines */
1.38 millert 87: int posix = 0; /* strict POSIX mode? */
1.23 otto 88:
89: static void reinitialize_almost_everything(void);
90: static void get_some_switches(void);
91: static LINENUM locate_hunk(LINENUM);
1.43 otto 92: static void abort_context_hunk(void);
93: static void rej_line(int, LINENUM);
1.23 otto 94: static void abort_hunk(void);
95: static void apply_hunk(LINENUM);
1.29 otto 96: static void init_output(const char *);
97: static void init_reject(const char *);
1.37 otto 98: static void copy_till(LINENUM, bool);
1.23 otto 99: static void spew_output(void);
1.37 otto 100: static void dump_line(LINENUM, bool);
1.23 otto 101: static bool patch_match(LINENUM, LINENUM, LINENUM);
1.72 tb 102: static bool similar(const char *, const char *, ssize_t);
1.24 millert 103: static __dead void usage(void);
1.1 deraadt 104:
1.35 otto 105: /* true if -E was specified on command line. */
106: static bool remove_empty_files = false;
1.1 deraadt 107:
1.35 otto 108: /* true if -R was specified on command line. */
109: static bool reverse_flag_specified = false;
1.1 deraadt 110:
1.25 millert 111: /* buffer holding the name of the rejected patch file. */
1.64 deraadt 112: static char rejname[PATH_MAX];
1.25 millert 113:
1.29 otto 114: /* how many input lines have been irretractibly output */
115: static LINENUM last_frozen_line = 0;
116:
117: static int Argc; /* guess */
118: static char **Argv;
119: static int Argc_last; /* for restarting plan_b */
120: static char **Argv_last;
121:
122: static FILE *ofp = NULL; /* output file pointer */
123: static FILE *rejfp = NULL; /* reject file pointer */
124:
125: static int filec = 0; /* how many file arguments? */
126: static LINENUM last_offset = 0;
127: static LINENUM maxfuzz = 2;
128:
129: /* patch using ifdef, ifndef, etc. */
1.35 otto 130: static bool do_defines = false;
1.29 otto 131: /* #ifdef xyzzy */
132: static char if_defined[128];
133: /* #ifndef xyzzy */
134: static char not_defined[128];
135: /* #else */
136: static const char else_defined[] = "#else\n";
137: /* #endif xyzzy */
138: static char end_defined[128];
139:
1.11 espie 140:
1.1 deraadt 141: /* Apply a set of diffs as appropriate. */
142:
143: int
1.19 deraadt 144: main(int argc, char *argv[])
1.1 deraadt 145: {
1.42 deraadt 146: int error = 0, hunk, failed, i, fd;
1.47 stsp 147: bool patch_seen;
1.35 otto 148: LINENUM where = 0, newwhere, fuzz, mymaxfuzz;
1.31 millert 149: const char *tmpdir;
150: char *v;
1.55 deraadt 151:
1.73 ! florian 152: if (pledge("stdio rpath wpath cpath tmppath fattr unveil", NULL) == -1) {
1.59 deraadt 153: perror("pledge");
1.62 gsoares 154: my_exit(2);
1.61 deraadt 155: }
1.69 jca 156:
157: bufsz = INITLINELEN;
158: if ((buf = malloc(bufsz)) == NULL)
159: pfatal("allocating input buffer");
160: buf[0] = '\0';
1.20 deraadt 161:
1.52 millert 162: setvbuf(stdout, NULL, _IOLBF, 0);
163: setvbuf(stderr, NULL, _IOLBF, 0);
1.20 deraadt 164: for (i = 0; i < MAXFILEC; i++)
1.23 otto 165: filearg[i] = NULL;
1.20 deraadt 166:
167: /* Cons up the names of the temporary files. */
1.31 millert 168: if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')
169: tmpdir = _PATH_TMP;
170: for (i = strlen(tmpdir) - 1; i > 0 && tmpdir[i] == '/'; i--)
171: ;
172: i++;
173: if (asprintf(&TMPOUTNAME, "%.*s/patchoXXXXXXXXXX", i, tmpdir) == -1)
1.20 deraadt 174: fatal("cannot allocate memory");
1.67 deraadt 175: if ((fd = mkstemp(TMPOUTNAME)) == -1)
1.20 deraadt 176: pfatal("can't create %s", TMPOUTNAME);
1.31 millert 177: close(fd);
1.20 deraadt 178:
1.31 millert 179: if (asprintf(&TMPINNAME, "%.*s/patchiXXXXXXXXXX", i, tmpdir) == -1)
1.20 deraadt 180: fatal("cannot allocate memory");
1.67 deraadt 181: if ((fd = mkstemp(TMPINNAME)) == -1)
1.20 deraadt 182: pfatal("can't create %s", TMPINNAME);
1.31 millert 183: close(fd);
1.20 deraadt 184:
1.31 millert 185: if (asprintf(&TMPREJNAME, "%.*s/patchrXXXXXXXXXX", i, tmpdir) == -1)
1.20 deraadt 186: fatal("cannot allocate memory");
1.67 deraadt 187: if ((fd = mkstemp(TMPREJNAME)) == -1)
1.20 deraadt 188: pfatal("can't create %s", TMPREJNAME);
1.31 millert 189: close(fd);
1.20 deraadt 190:
1.31 millert 191: if (asprintf(&TMPPATNAME, "%.*s/patchpXXXXXXXXXX", i, tmpdir) == -1)
1.20 deraadt 192: fatal("cannot allocate memory");
1.67 deraadt 193: if ((fd = mkstemp(TMPPATNAME)) == -1)
1.20 deraadt 194: pfatal("can't create %s", TMPPATNAME);
1.31 millert 195: close(fd);
1.20 deraadt 196:
197: v = getenv("SIMPLE_BACKUP_SUFFIX");
198: if (v)
199: simple_backup_suffix = v;
200: else
201: simple_backup_suffix = ORIGEXT;
202:
203: /* parse switches */
204: Argc = argc;
205: Argv = argv;
206: get_some_switches();
1.73 ! florian 207: if (unveil(tmpdir, "rwc") == -1) {
! 208: perror("unveil");
! 209: my_exit(2);
! 210: }
! 211: if (outname != NULL)
! 212: if (unveil(outname, "rwc") == -1) {
! 213: perror("unveil");
! 214: my_exit(2);
! 215: }
! 216: if (filearg[0] != NULL)
! 217: if (unveil(filearg[0], "rwc") == -1) {
! 218: perror("unveil");
! 219: my_exit(2);
! 220: }
! 221: if (filearg[1] != NULL)
! 222: if (unveil(filearg[1], "r") == -1) {
! 223: perror("unveil");
! 224: my_exit(2);
! 225: }
! 226: if (unveil(".", "rwc") == -1) {
! 227: perror("unveil");
! 228: my_exit(2);
! 229: }
! 230: if (*rejname != '\0')
! 231: if (unveil(rejname, "rwc") == -1) {
! 232: perror("unveil");
! 233: my_exit(2);
! 234: }
! 235: if (pledge("stdio rpath wpath cpath tmppath fattr", NULL) == -1) {
! 236: perror("pledge");
! 237: my_exit(2);
! 238: }
1.20 deraadt 239:
1.27 millert 240: if (backup_type == none) {
1.38 millert 241: if ((v = getenv("PATCH_VERSION_CONTROL")) == NULL)
242: v = getenv("VERSION_CONTROL");
243: if (v != NULL || !posix)
1.27 millert 244: backup_type = get_version(v); /* OK to pass NULL. */
245: }
246:
1.20 deraadt 247: /* make sure we clean up /tmp in case of disaster */
248: set_signals(0);
249:
1.47 stsp 250: patch_seen = false;
1.20 deraadt 251: for (open_patch_file(filearg[1]); there_is_another_patch();
252: reinitialize_almost_everything()) {
253: /* for each patch in patch file */
1.53 deraadt 254:
1.47 stsp 255: patch_seen = true;
1.20 deraadt 256:
1.35 otto 257: warn_on_invalid_line = true;
1.20 deraadt 258:
1.23 otto 259: if (outname == NULL)
1.54 tobias 260: outname = xstrdup(filearg[0]);
1.1 deraadt 261:
1.20 deraadt 262: /* initialize the patched file */
263: if (!skip_rest_of_patch)
264: init_output(TMPOUTNAME);
265:
266: /* initialize reject file */
267: init_reject(TMPREJNAME);
268:
269: /* find out where all the lines are */
270: if (!skip_rest_of_patch)
271: scan_input(filearg[0]);
1.60 tobias 272:
273: /* for ed script just up and do it and exit */
274: if (diff_type == ED_DIFF) {
275: do_ed_script();
276: continue;
277: }
1.20 deraadt 278:
279: /* from here on, open no standard i/o files, because malloc */
280: /* might misfire and we can't catch it easily */
281:
282: /* apply each hunk of patch */
283: hunk = 0;
284: failed = 0;
1.35 otto 285: out_of_mem = false;
1.20 deraadt 286: while (another_hunk()) {
287: hunk++;
1.29 otto 288: fuzz = 0;
1.20 deraadt 289: mymaxfuzz = pch_context();
290: if (maxfuzz < mymaxfuzz)
291: mymaxfuzz = maxfuzz;
292: if (!skip_rest_of_patch) {
293: do {
294: where = locate_hunk(fuzz);
1.70 op 295: if ((hunk == 1 && where == 0 && !force) ||
296: (where == 1 && pch_ptrn_lines() == 0 && !force)) {
1.1 deraadt 297: /* dwim for reversed patch? */
1.20 deraadt 298: if (!pch_swap()) {
1.29 otto 299: if (fuzz == 0)
1.20 deraadt 300: say("Not enough memory to try swapped hunk! Assuming unswapped.\n");
301: continue;
302: }
303: reverse = !reverse;
304: /* try again */
305: where = locate_hunk(fuzz);
1.29 otto 306: if (where == 0) {
1.20 deraadt 307: /* didn't find it swapped */
308: if (!pch_swap())
309: /* put it back to normal */
310: fatal("lost hunk on alloc error!\n");
311: reverse = !reverse;
1.70 op 312:
313: /* restore position if this patch creates a file */
314: if (pch_ptrn_lines() == 0)
315: where = 1;
1.20 deraadt 316: } else if (noreverse) {
317: if (!pch_swap())
318: /* put it back to normal */
319: fatal("lost hunk on alloc error!\n");
320: reverse = !reverse;
321: say("Ignoring previously applied (or reversed) patch.\n");
1.35 otto 322: skip_rest_of_patch = true;
1.20 deraadt 323: } else if (batch) {
324: if (verbose)
325: say("%seversed (or previously applied) patch detected! %s -R.",
326: reverse ? "R" : "Unr",
327: reverse ? "Assuming" : "Ignoring");
328: } else {
329: ask("%seversed (or previously applied) patch detected! %s -R? [y] ",
330: reverse ? "R" : "Unr",
331: reverse ? "Assume" : "Ignore");
332: if (*buf == 'n') {
333: ask("Apply anyway? [n] ");
334: if (*buf != 'y')
1.35 otto 335: skip_rest_of_patch = true;
1.29 otto 336: where = 0;
1.20 deraadt 337: reverse = !reverse;
338: if (!pch_swap())
339: /* put it back to normal */
340: fatal("lost hunk on alloc error!\n");
341: }
342: }
343: }
1.29 otto 344: } while (!skip_rest_of_patch && where == 0 &&
1.30 deraadt 345: ++fuzz <= mymaxfuzz);
1.20 deraadt 346:
347: if (skip_rest_of_patch) { /* just got decided */
348: fclose(ofp);
1.23 otto 349: ofp = NULL;
1.20 deraadt 350: }
351: }
352: newwhere = pch_newfirst() + last_offset;
353: if (skip_rest_of_patch) {
354: abort_hunk();
355: failed++;
356: if (verbose)
357: say("Hunk #%d ignored at %ld.\n",
358: hunk, newwhere);
1.29 otto 359: } else if (where == 0) {
1.20 deraadt 360: abort_hunk();
361: failed++;
362: if (verbose)
363: say("Hunk #%d failed at %ld.\n",
364: hunk, newwhere);
365: } else {
366: apply_hunk(where);
367: if (verbose) {
368: say("Hunk #%d succeeded at %ld",
369: hunk, newwhere);
1.29 otto 370: if (fuzz != 0)
1.20 deraadt 371: say(" with fuzz %ld", fuzz);
372: if (last_offset)
373: say(" (offset %ld line%s)",
374: last_offset,
375: last_offset == 1L ? "" : "s");
376: say(".\n");
377: }
378: }
379: }
380:
381: if (out_of_mem && using_plan_a) {
382: Argc = Argc_last;
383: Argv = Argv_last;
384: say("\n\nRan out of memory using Plan A--trying again...\n\n");
385: if (ofp)
386: fclose(ofp);
1.23 otto 387: ofp = NULL;
1.20 deraadt 388: if (rejfp)
389: fclose(rejfp);
1.23 otto 390: rejfp = NULL;
1.20 deraadt 391: continue;
1.11 espie 392: }
1.35 otto 393: if (hunk == 0)
394: fatal("Internal error: hunk should not be 0\n");
1.1 deraadt 395:
1.20 deraadt 396: /* finish spewing out the new file */
397: if (!skip_rest_of_patch)
398: spew_output();
399:
400: /* and put the output where desired */
401: ignore_signals();
402: if (!skip_rest_of_patch) {
403: struct stat statbuf;
404: char *realout = outname;
405:
406: if (!check_only) {
407: if (move_file(TMPOUTNAME, outname) < 0) {
1.35 otto 408: toutkeep = true;
1.20 deraadt 409: realout = TMPOUTNAME;
410: chmod(TMPOUTNAME, filemode);
411: } else
412: chmod(outname, filemode);
413:
414: if (remove_empty_files &&
415: stat(realout, &statbuf) == 0 &&
416: statbuf.st_size == 0) {
417: if (verbose)
418: say("Removing %s (empty after patching).\n",
419: realout);
420: unlink(realout);
421: }
422: }
423: }
424: fclose(rejfp);
1.23 otto 425: rejfp = NULL;
1.20 deraadt 426: if (failed) {
1.28 millert 427: error = 1;
1.29 otto 428: if (*rejname == '\0') {
1.20 deraadt 429: if (strlcpy(rejname, outname,
430: sizeof(rejname)) >= sizeof(rejname))
431: fatal("filename %s is too long\n", outname);
432: if (strlcat(rejname, REJEXT,
433: sizeof(rejname)) >= sizeof(rejname))
434: fatal("filename %s is too long\n", outname);
435: }
1.50 millert 436: if (!check_only)
437: say("%d out of %d hunks %s--saving rejects to %s\n",
438: failed, hunk, skip_rest_of_patch ? "ignored" : "failed", rejname);
439: else
440: say("%d out of %d hunks %s\n",
441: failed, hunk, skip_rest_of_patch ? "ignored" : "failed");
1.20 deraadt 442: if (!check_only && move_file(TMPREJNAME, rejname) < 0)
1.35 otto 443: trejkeep = true;
1.20 deraadt 444: }
445: set_signals(1);
446: }
1.53 deraadt 447:
1.47 stsp 448: if (!patch_seen)
449: error = 2;
450:
1.28 millert 451: my_exit(error);
1.20 deraadt 452: /* NOTREACHED */
1.1 deraadt 453: }
454:
455: /* Prepare to find the next patch to do in the patch file. */
456:
1.23 otto 457: static void
1.20 deraadt 458: reinitialize_almost_everything(void)
1.1 deraadt 459: {
1.20 deraadt 460: re_patch();
461: re_input();
1.1 deraadt 462:
1.20 deraadt 463: input_lines = 0;
464: last_frozen_line = 0;
1.1 deraadt 465:
1.20 deraadt 466: filec = 0;
1.35 otto 467: if (!out_of_mem) {
1.20 deraadt 468: free(filearg[0]);
1.23 otto 469: filearg[0] = NULL;
1.20 deraadt 470: }
1.35 otto 471:
472: free(outname);
473: outname = NULL;
474:
1.20 deraadt 475: last_offset = 0;
1.35 otto 476: diff_type = 0;
1.1 deraadt 477:
1.35 otto 478: free(revision);
479: revision = NULL;
1.1 deraadt 480:
1.20 deraadt 481: reverse = reverse_flag_specified;
1.35 otto 482: skip_rest_of_patch = false;
1.1 deraadt 483:
1.20 deraadt 484: get_some_switches();
1.1 deraadt 485: }
486:
1.24 millert 487: /* Process switches and filenames. */
1.1 deraadt 488:
1.23 otto 489: static void
1.20 deraadt 490: get_some_switches(void)
1.1 deraadt 491: {
1.34 millert 492: const char *options = "b::B:cCd:D:eEfF:i:lnNo:p:r:RstuvV:x:z:";
1.24 millert 493: static struct option longopts[] = {
1.27 millert 494: {"backup", no_argument, 0, 'b'},
1.24 millert 495: {"batch", no_argument, 0, 't'},
496: {"check", no_argument, 0, 'C'},
497: {"context", no_argument, 0, 'c'},
498: {"debug", required_argument, 0, 'x'},
499: {"directory", required_argument, 0, 'd'},
1.66 zhuk 500: {"dry-run", no_argument, 0, 'C'},
1.24 millert 501: {"ed", no_argument, 0, 'e'},
502: {"force", no_argument, 0, 'f'},
503: {"forward", no_argument, 0, 'N'},
504: {"fuzz", required_argument, 0, 'F'},
505: {"ifdef", required_argument, 0, 'D'},
1.32 millert 506: {"input", required_argument, 0, 'i'},
1.24 millert 507: {"ignore-whitespace", no_argument, 0, 'l'},
508: {"normal", no_argument, 0, 'n'},
509: {"output", required_argument, 0, 'o'},
510: {"prefix", required_argument, 0, 'B'},
511: {"quiet", no_argument, 0, 's'},
512: {"reject-file", required_argument, 0, 'r'},
513: {"remove-empty-files", no_argument, 0, 'E'},
514: {"reverse", no_argument, 0, 'R'},
515: {"silent", no_argument, 0, 's'},
1.34 millert 516: {"strip", required_argument, 0, 'p'},
1.27 millert 517: {"suffix", required_argument, 0, 'z'},
1.24 millert 518: {"unified", no_argument, 0, 'u'},
519: {"version", no_argument, 0, 'v'},
520: {"version-control", required_argument, 0, 'V'},
1.38 millert 521: {"posix", no_argument, &posix, 1},
1.24 millert 522: {NULL, 0, 0, 0}
523: };
524: int ch;
1.1 deraadt 525:
1.20 deraadt 526: rejname[0] = '\0';
527: Argc_last = Argc;
528: Argv_last = Argv;
529: if (!Argc)
530: return;
1.24 millert 531: optreset = optind = 1;
532: while ((ch = getopt_long(Argc, Argv, options, longopts, NULL)) != -1) {
533: switch (ch) {
534: case 'b':
1.27 millert 535: if (backup_type == none)
536: backup_type = numbered_existing;
537: if (optarg == NULL)
538: break;
539: if (verbose)
540: say("Warning, the ``-b suffix'' option has been"
541: " obsoleted by the -z option.\n");
542: /* FALLTHROUGH */
543: case 'z':
544: /* must directly follow 'b' case for backwards compat */
1.54 tobias 545: simple_backup_suffix = xstrdup(optarg);
1.24 millert 546: break;
547: case 'B':
1.54 tobias 548: origprae = xstrdup(optarg);
1.24 millert 549: break;
550: case 'c':
551: diff_type = CONTEXT_DIFF;
552: break;
553: case 'C':
1.35 otto 554: check_only = true;
1.24 millert 555: break;
556: case 'd':
1.68 deraadt 557: if (chdir(optarg) == -1)
1.24 millert 558: pfatal("can't cd to %s", optarg);
559: break;
560: case 'D':
1.35 otto 561: do_defines = true;
1.51 deraadt 562: if (!isalpha((unsigned char)*optarg) && *optarg != '_')
1.24 millert 563: fatal("argument to -D is not an identifier\n");
564: snprintf(if_defined, sizeof if_defined,
565: "#ifdef %s\n", optarg);
566: snprintf(not_defined, sizeof not_defined,
567: "#ifndef %s\n", optarg);
568: snprintf(end_defined, sizeof end_defined,
569: "#endif /* %s */\n", optarg);
570: break;
571: case 'e':
572: diff_type = ED_DIFF;
573: break;
574: case 'E':
1.35 otto 575: remove_empty_files = true;
1.24 millert 576: break;
577: case 'f':
1.35 otto 578: force = true;
1.24 millert 579: break;
580: case 'F':
581: maxfuzz = atoi(optarg);
582: break;
1.32 millert 583: case 'i':
584: if (++filec == MAXFILEC)
585: fatal("too many file arguments\n");
1.54 tobias 586: filearg[filec] = xstrdup(optarg);
1.32 millert 587: break;
1.24 millert 588: case 'l':
1.35 otto 589: canonicalize = true;
1.24 millert 590: break;
591: case 'n':
592: diff_type = NORMAL_DIFF;
593: break;
594: case 'N':
1.35 otto 595: noreverse = true;
1.24 millert 596: break;
597: case 'o':
1.54 tobias 598: outname = xstrdup(optarg);
1.24 millert 599: break;
600: case 'p':
1.34 millert 601: strippath = atoi(optarg);
1.24 millert 602: break;
603: case 'r':
604: if (strlcpy(rejname, optarg,
605: sizeof(rejname)) >= sizeof(rejname))
606: fatal("argument for -r is too long\n");
607: break;
608: case 'R':
1.35 otto 609: reverse = true;
610: reverse_flag_specified = true;
1.24 millert 611: break;
612: case 's':
1.35 otto 613: verbose = false;
1.24 millert 614: break;
615: case 't':
1.35 otto 616: batch = true;
1.24 millert 617: break;
618: case 'u':
619: diff_type = UNI_DIFF;
620: break;
621: case 'v':
622: version();
623: break;
624: case 'V':
625: backup_type = get_version(optarg);
626: break;
1.1 deraadt 627: #ifdef DEBUGGING
1.24 millert 628: case 'x':
629: debug = atoi(optarg);
630: break;
1.1 deraadt 631: #endif
1.24 millert 632: default:
1.38 millert 633: if (ch != '\0')
634: usage();
1.24 millert 635: break;
1.20 deraadt 636: }
1.1 deraadt 637: }
1.24 millert 638: Argc -= optind;
639: Argv += optind;
640:
1.32 millert 641: if (Argc > 0) {
1.54 tobias 642: filearg[0] = xstrdup(*Argv++);
1.24 millert 643: Argc--;
1.32 millert 644: while (Argc > 0) {
645: if (++filec == MAXFILEC)
646: fatal("too many file arguments\n");
1.54 tobias 647: filearg[filec] = xstrdup(*Argv++);
1.32 millert 648: Argc--;
649: }
1.24 millert 650: }
1.38 millert 651:
652: if (getenv("POSIXLY_CORRECT") != NULL)
653: posix = 1;
1.24 millert 654: }
655:
656: static __dead void
657: usage(void)
658: {
659: fprintf(stderr,
1.45 sobrado 660: "usage: patch [-bCcEeflNnRstuv] [-B backup-prefix] [-D symbol] [-d directory]\n"
1.34 millert 661: " [-F max-fuzz] [-i patchfile] [-o out-file] [-p strip-count]\n"
1.45 sobrado 662: " [-r rej-name] [-V t | nil | never] [-x number] [-z backup-ext]\n"
663: " [--posix] [origfile [patchfile]]\n"
664: " patch <patchfile\n");
1.63 gsoares 665: my_exit(2);
1.1 deraadt 666: }
667:
1.20 deraadt 668: /*
669: * Attempt to find the right place to apply this hunk of patch.
670: */
1.23 otto 671: static LINENUM
1.20 deraadt 672: locate_hunk(LINENUM fuzz)
1.1 deraadt 673: {
1.20 deraadt 674: LINENUM first_guess = pch_first() + last_offset;
675: LINENUM offset;
676: LINENUM pat_lines = pch_ptrn_lines();
677: LINENUM max_pos_offset = input_lines - first_guess - pat_lines + 1;
678: LINENUM max_neg_offset = first_guess - last_frozen_line - 1 + pch_context();
679:
1.36 otto 680: if (pat_lines == 0) { /* null range matches always */
1.39 otto 681: if (verbose && fuzz == 0 && (diff_type == CONTEXT_DIFF
1.36 otto 682: || diff_type == NEW_CONTEXT_DIFF
683: || diff_type == UNI_DIFF)) {
684: say("Empty context always matches.\n");
685: }
1.71 op 686: if (first_guess == 0)
687: return 1;
1.46 otto 688: return (first_guess);
1.36 otto 689: }
1.20 deraadt 690: if (max_neg_offset >= first_guess) /* do not try lines < 0 */
691: max_neg_offset = first_guess - 1;
1.29 otto 692: if (first_guess <= input_lines && patch_match(first_guess, 0, fuzz))
1.20 deraadt 693: return first_guess;
694: for (offset = 1; ; offset++) {
695: bool check_after = (offset <= max_pos_offset);
696: bool check_before = (offset <= max_neg_offset);
1.1 deraadt 697:
1.20 deraadt 698: if (check_after && patch_match(first_guess, offset, fuzz)) {
1.1 deraadt 699: #ifdef DEBUGGING
1.20 deraadt 700: if (debug & 1)
701: say("Offset changing from %ld to %ld\n",
702: last_offset, offset);
1.1 deraadt 703: #endif
1.20 deraadt 704: last_offset = offset;
705: return first_guess + offset;
706: } else if (check_before && patch_match(first_guess, -offset, fuzz)) {
1.1 deraadt 707: #ifdef DEBUGGING
1.20 deraadt 708: if (debug & 1)
709: say("Offset changing from %ld to %ld\n",
710: last_offset, -offset);
1.1 deraadt 711: #endif
1.20 deraadt 712: last_offset = -offset;
713: return first_guess - offset;
714: } else if (!check_before && !check_after)
1.29 otto 715: return 0;
1.1 deraadt 716: }
717: }
718:
719: /* We did not find the pattern, dump out the hunk so they can handle it. */
720:
1.23 otto 721: static void
1.43 otto 722: abort_context_hunk(void)
1.1 deraadt 723: {
1.20 deraadt 724: LINENUM i;
1.29 otto 725: const LINENUM pat_end = pch_end();
1.20 deraadt 726: /*
727: * add in last_offset to guess the same as the previous successful
728: * hunk
729: */
1.29 otto 730: const LINENUM oldfirst = pch_first() + last_offset;
731: const LINENUM newfirst = pch_newfirst() + last_offset;
732: const LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
733: const LINENUM newlast = newfirst + pch_repl_lines() - 1;
734: const char *stars = (diff_type >= NEW_CONTEXT_DIFF ? " ****" : "");
735: const char *minuses = (diff_type >= NEW_CONTEXT_DIFF ? " ----" : " -----");
1.20 deraadt 736:
737: fprintf(rejfp, "***************\n");
738: for (i = 0; i <= pat_end; i++) {
739: switch (pch_char(i)) {
740: case '*':
741: if (oldlast < oldfirst)
742: fprintf(rejfp, "*** 0%s\n", stars);
743: else if (oldlast == oldfirst)
744: fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
745: else
746: fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst,
747: oldlast, stars);
748: break;
749: case '=':
750: if (newlast < newfirst)
751: fprintf(rejfp, "--- 0%s\n", minuses);
752: else if (newlast == newfirst)
753: fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
754: else
755: fprintf(rejfp, "--- %ld,%ld%s\n", newfirst,
756: newlast, minuses);
757: break;
758: case '\n':
759: fprintf(rejfp, "%s", pfetch(i));
760: break;
761: case ' ':
762: case '-':
763: case '+':
764: case '!':
765: fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
766: break;
767: default:
1.43 otto 768: fatal("fatal internal error in abort_context_hunk\n");
769: }
770: }
771: }
772:
773: static void
774: rej_line(int ch, LINENUM i)
775: {
776: size_t len;
777: const char *line = pfetch(i);
778:
779: len = strlen(line);
780:
781: fprintf(rejfp, "%c%s", ch, line);
782: if (len == 0 || line[len-1] != '\n')
783: fprintf(rejfp, "\n\\ No newline at end of file\n");
784: }
785:
786: static void
787: abort_hunk(void)
788: {
789: LINENUM i, j, split;
790: int ch1, ch2;
791: const LINENUM pat_end = pch_end();
792: const LINENUM oldfirst = pch_first() + last_offset;
793: const LINENUM newfirst = pch_newfirst() + last_offset;
794:
795: if (diff_type != UNI_DIFF) {
796: abort_context_hunk();
797: return;
798: }
799: split = -1;
800: for (i = 0; i <= pat_end; i++) {
801: if (pch_char(i) == '=') {
802: split = i;
803: break;
804: }
805: }
806: if (split == -1) {
807: fprintf(rejfp, "malformed hunk: no split found\n");
808: return;
809: }
810: i = 0;
811: j = split + 1;
812: fprintf(rejfp, "@@ -%ld,%ld +%ld,%ld @@\n",
813: pch_ptrn_lines() ? oldfirst : 0,
814: pch_ptrn_lines(), newfirst, pch_repl_lines());
815: while (i < split || j <= pat_end) {
816: ch1 = i < split ? pch_char(i) : -1;
817: ch2 = j <= pat_end ? pch_char(j) : -1;
818: if (ch1 == '-') {
819: rej_line('-', i);
820: i++;
821: } else if (ch1 == ' ' && ch2 == ' ') {
822: rej_line(' ', i);
823: i++;
824: j++;
825: } else if (ch1 == '!' && ch2 == '!') {
826: while (i < split && ch1 == '!') {
827: rej_line('-', i);
828: i++;
829: ch1 = i < split ? pch_char(i) : -1;
830: }
831: while (j <= pat_end && ch2 == '!') {
832: rej_line('+', j);
833: j++;
834: ch2 = j <= pat_end ? pch_char(j) : -1;
835: }
836: } else if (ch1 == '*') {
837: i++;
838: } else if (ch2 == '+' || ch2 == ' ') {
839: rej_line(ch2, j);
840: j++;
841: } else {
842: fprintf(rejfp, "internal error on (%ld %ld %ld)\n",
843: i, split, j);
844: rej_line(ch1, i);
845: rej_line(ch2, j);
846: return;
1.20 deraadt 847: }
1.1 deraadt 848: }
849: }
850:
851: /* We found where to apply it (we hope), so do it. */
852:
1.23 otto 853: static void
1.20 deraadt 854: apply_hunk(LINENUM where)
1.1 deraadt 855: {
1.29 otto 856: LINENUM old = 1;
857: const LINENUM lastline = pch_ptrn_lines();
858: LINENUM new = lastline + 1;
1.1 deraadt 859: #define OUTSIDE 0
860: #define IN_IFNDEF 1
861: #define IN_IFDEF 2
862: #define IN_ELSE 3
1.29 otto 863: int def_state = OUTSIDE;
864: const LINENUM pat_end = pch_end();
1.20 deraadt 865:
866: where--;
867: while (pch_char(new) == '=' || pch_char(new) == '\n')
868: new++;
869:
870: while (old <= lastline) {
871: if (pch_char(old) == '-') {
1.37 otto 872: copy_till(where + old - 1, false);
1.29 otto 873: if (do_defines) {
1.20 deraadt 874: if (def_state == OUTSIDE) {
875: fputs(not_defined, ofp);
876: def_state = IN_IFNDEF;
877: } else if (def_state == IN_IFDEF) {
878: fputs(else_defined, ofp);
879: def_state = IN_ELSE;
880: }
881: fputs(pfetch(old), ofp);
882: }
883: last_frozen_line++;
884: old++;
885: } else if (new > pat_end) {
886: break;
887: } else if (pch_char(new) == '+') {
1.37 otto 888: copy_till(where + old - 1, false);
1.29 otto 889: if (do_defines) {
1.20 deraadt 890: if (def_state == IN_IFNDEF) {
891: fputs(else_defined, ofp);
892: def_state = IN_ELSE;
893: } else if (def_state == OUTSIDE) {
894: fputs(if_defined, ofp);
895: def_state = IN_IFDEF;
896: }
897: }
898: fputs(pfetch(new), ofp);
899: new++;
900: } else if (pch_char(new) != pch_char(old)) {
901: say("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
902: pch_hunk_beg() + old,
903: pch_hunk_beg() + new);
1.1 deraadt 904: #ifdef DEBUGGING
1.20 deraadt 905: say("oldchar = '%c', newchar = '%c'\n",
906: pch_char(old), pch_char(new));
1.1 deraadt 907: #endif
1.28 millert 908: my_exit(2);
1.20 deraadt 909: } else if (pch_char(new) == '!') {
1.37 otto 910: copy_till(where + old - 1, false);
1.29 otto 911: if (do_defines) {
1.20 deraadt 912: fputs(not_defined, ofp);
913: def_state = IN_IFNDEF;
914: }
915: while (pch_char(old) == '!') {
1.29 otto 916: if (do_defines) {
1.20 deraadt 917: fputs(pfetch(old), ofp);
918: }
919: last_frozen_line++;
920: old++;
921: }
1.29 otto 922: if (do_defines) {
1.20 deraadt 923: fputs(else_defined, ofp);
924: def_state = IN_ELSE;
925: }
926: while (pch_char(new) == '!') {
927: fputs(pfetch(new), ofp);
928: new++;
929: }
930: } else {
1.35 otto 931: if (pch_char(new) != ' ')
932: fatal("Internal error: expected ' '\n");
1.20 deraadt 933: old++;
934: new++;
1.29 otto 935: if (do_defines && def_state != OUTSIDE) {
1.20 deraadt 936: fputs(end_defined, ofp);
937: def_state = OUTSIDE;
938: }
939: }
1.1 deraadt 940: }
1.20 deraadt 941: if (new <= pat_end && pch_char(new) == '+') {
1.37 otto 942: copy_till(where + old - 1, false);
1.29 otto 943: if (do_defines) {
1.20 deraadt 944: if (def_state == OUTSIDE) {
945: fputs(if_defined, ofp);
946: def_state = IN_IFDEF;
947: } else if (def_state == IN_IFNDEF) {
948: fputs(else_defined, ofp);
949: def_state = IN_ELSE;
950: }
951: }
952: while (new <= pat_end && pch_char(new) == '+') {
953: fputs(pfetch(new), ofp);
954: new++;
1.1 deraadt 955: }
956: }
1.29 otto 957: if (do_defines && def_state != OUTSIDE) {
1.1 deraadt 958: fputs(end_defined, ofp);
959: }
960: }
961:
1.20 deraadt 962: /*
963: * Open the new file.
964: */
1.23 otto 965: static void
1.29 otto 966: init_output(const char *name)
1.1 deraadt 967: {
1.20 deraadt 968: ofp = fopen(name, "w");
1.23 otto 969: if (ofp == NULL)
1.20 deraadt 970: pfatal("can't create %s", name);
1.1 deraadt 971: }
972:
1.20 deraadt 973: /*
974: * Open a file to put hunks we can't locate.
975: */
1.23 otto 976: static void
1.29 otto 977: init_reject(const char *name)
1.1 deraadt 978: {
1.20 deraadt 979: rejfp = fopen(name, "w");
1.23 otto 980: if (rejfp == NULL)
1.20 deraadt 981: pfatal("can't create %s", name);
1.1 deraadt 982: }
983:
1.20 deraadt 984: /*
985: * Copy input file to output, up to wherever hunk is to be applied.
1.37 otto 986: * If endoffile is true, treat the last line specially since it may
987: * lack a newline.
1.20 deraadt 988: */
1.23 otto 989: static void
1.37 otto 990: copy_till(LINENUM lastline, bool endoffile)
1.1 deraadt 991: {
1.29 otto 992: if (last_frozen_line > lastline)
1.20 deraadt 993: fatal("misordered hunks! output would be garbled\n");
1.37 otto 994: while (last_frozen_line < lastline) {
995: if (++last_frozen_line == lastline && endoffile)
996: dump_line(last_frozen_line, !last_line_missing_eol);
997: else
998: dump_line(last_frozen_line, true);
999: }
1.1 deraadt 1000: }
1001:
1.20 deraadt 1002: /*
1003: * Finish copying the input file to the output file.
1004: */
1.23 otto 1005: static void
1.20 deraadt 1006: spew_output(void)
1.1 deraadt 1007: {
1008: #ifdef DEBUGGING
1.20 deraadt 1009: if (debug & 256)
1010: say("il=%ld lfl=%ld\n", input_lines, last_frozen_line);
1.1 deraadt 1011: #endif
1.20 deraadt 1012: if (input_lines)
1.37 otto 1013: copy_till(input_lines, true); /* dump remainder of file */
1.20 deraadt 1014: fclose(ofp);
1.23 otto 1015: ofp = NULL;
1.1 deraadt 1016: }
1017:
1.20 deraadt 1018: /*
1019: * Copy one line from input to output.
1020: */
1.23 otto 1021: static void
1.37 otto 1022: dump_line(LINENUM line, bool write_newline)
1.1 deraadt 1023: {
1.29 otto 1024: char *s;
1.1 deraadt 1025:
1.26 otto 1026: s = ifetch(line, 0);
1027: if (s == NULL)
1028: return;
1.30 deraadt 1029: /* Note: string is not NUL terminated. */
1.37 otto 1030: for (; *s != '\n'; s++)
1031: putc(*s, ofp);
1032: if (write_newline)
1033: putc('\n', ofp);
1.1 deraadt 1034: }
1035:
1.20 deraadt 1036: /*
1037: * Does the patch pattern match at line base+offset?
1038: */
1.23 otto 1039: static bool
1.20 deraadt 1040: patch_match(LINENUM base, LINENUM offset, LINENUM fuzz)
1041: {
1.29 otto 1042: LINENUM pline = 1 + fuzz;
1043: LINENUM iline;
1044: LINENUM pat_lines = pch_ptrn_lines() - fuzz;
1045: const char *ilineptr;
1.30 deraadt 1046: const char *plineptr;
1.72 tb 1047: ssize_t plinelen;
1.20 deraadt 1048:
1049: for (iline = base + offset + fuzz; pline <= pat_lines; pline++, iline++) {
1.26 otto 1050: ilineptr = ifetch(iline, offset >= 0);
1051: if (ilineptr == NULL)
1.35 otto 1052: return false;
1.26 otto 1053: plineptr = pfetch(pline);
1054: plinelen = pch_line_len(pline);
1.20 deraadt 1055: if (canonicalize) {
1.26 otto 1056: if (!similar(ilineptr, plineptr, plinelen))
1.35 otto 1057: return false;
1.26 otto 1058: } else if (strnNE(ilineptr, plineptr, plinelen))
1.35 otto 1059: return false;
1.41 otto 1060: if (iline == input_lines) {
1061: /*
1062: * We are looking at the last line of the file.
1063: * If the file has no eol, the patch line should
1064: * not have one either and vice-versa. Note that
1065: * plinelen > 0.
1066: */
1067: if (last_line_missing_eol) {
1068: if (plineptr[plinelen - 1] == '\n')
1069: return false;
1070: } else {
1071: if (plineptr[plinelen - 1] != '\n')
1072: return false;
1073: }
1074: }
1.1 deraadt 1075: }
1.35 otto 1076: return true;
1.1 deraadt 1077: }
1078:
1.20 deraadt 1079: /*
1080: * Do two lines match with canonicalized white space?
1081: */
1.23 otto 1082: static bool
1.72 tb 1083: similar(const char *a, const char *b, ssize_t len)
1.20 deraadt 1084: {
1085: while (len) {
1.51 deraadt 1086: if (isspace((unsigned char)*b)) { /* whitespace (or \n) to match? */
1087: if (!isspace((unsigned char)*a))
1088: return false; /* no corresponding whitespace */
1089: while (len && isspace((unsigned char)*b) && *b != '\n')
1.20 deraadt 1090: b++, len--; /* skip pattern whitespace */
1.51 deraadt 1091: while (isspace((unsigned char)*a) && *a != '\n')
1.20 deraadt 1092: a++; /* skip target whitespace */
1093: if (*a == '\n' || *b == '\n')
1094: return (*a == *b); /* should end in sync */
1095: } else if (*a++ != *b++) /* match non-whitespace chars */
1.35 otto 1096: return false;
1.20 deraadt 1097: else
1098: len--; /* probably not necessary */
1.1 deraadt 1099: }
1.35 otto 1100: return true; /* actually, this is not reached */
1.20 deraadt 1101: /* since there is always a \n */
1.1 deraadt 1102: }