15027f2b8SJohn Marino /*-
248d201a5SJoerg Sonnenberger * Copyright 1986, Larry Wall
348d201a5SJoerg Sonnenberger *
448d201a5SJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without
548d201a5SJoerg Sonnenberger * modification, are permitted provided that the following condition is met:
648d201a5SJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright notice,
748d201a5SJoerg Sonnenberger * this condition and the following disclaimer.
848d201a5SJoerg Sonnenberger *
948d201a5SJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
1048d201a5SJoerg Sonnenberger * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1148d201a5SJoerg Sonnenberger * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1248d201a5SJoerg Sonnenberger * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
1348d201a5SJoerg Sonnenberger * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1448d201a5SJoerg Sonnenberger * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1548d201a5SJoerg Sonnenberger * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
1648d201a5SJoerg Sonnenberger * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1748d201a5SJoerg Sonnenberger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1848d201a5SJoerg Sonnenberger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1948d201a5SJoerg Sonnenberger * SUCH DAMAGE.
2048d201a5SJoerg Sonnenberger *
215027f2b8SJohn Marino * patch - a program to apply diffs to original files
225027f2b8SJohn Marino *
2348d201a5SJoerg Sonnenberger * -C option added in 1998, original code by Marc Espie, based on FreeBSD
2448d201a5SJoerg Sonnenberger * behaviour
255027f2b8SJohn Marino *
265027f2b8SJohn Marino * $OpenBSD: util.c,v 1.35 2010/07/24 01:10:12 ray Exp $
27*b94b84caSDaniel Fojt * $FreeBSD: head/usr.bin/patch/util.c 354328 2019-11-04 03:07:01Z kevans $
2848d201a5SJoerg Sonnenberger */
2948d201a5SJoerg Sonnenberger
3048d201a5SJoerg Sonnenberger #include <sys/stat.h>
3148d201a5SJoerg Sonnenberger
3248d201a5SJoerg Sonnenberger #include <ctype.h>
3348d201a5SJoerg Sonnenberger #include <errno.h>
3448d201a5SJoerg Sonnenberger #include <fcntl.h>
3548d201a5SJoerg Sonnenberger #include <libgen.h>
36*b94b84caSDaniel Fojt #include <limits.h>
3748d201a5SJoerg Sonnenberger #include <paths.h>
389d62a0f9SSascha Wildner #include <signal.h>
3948d201a5SJoerg Sonnenberger #include <stdarg.h>
4048d201a5SJoerg Sonnenberger #include <stdlib.h>
4148d201a5SJoerg Sonnenberger #include <stdio.h>
4248d201a5SJoerg Sonnenberger #include <string.h>
4348d201a5SJoerg Sonnenberger #include <unistd.h>
4448d201a5SJoerg Sonnenberger
4548d201a5SJoerg Sonnenberger #include "common.h"
4648d201a5SJoerg Sonnenberger #include "util.h"
4748d201a5SJoerg Sonnenberger #include "backupfile.h"
4848d201a5SJoerg Sonnenberger #include "pathnames.h"
4948d201a5SJoerg Sonnenberger
5048d201a5SJoerg Sonnenberger /* Rename a file, copying it if necessary. */
5148d201a5SJoerg Sonnenberger
5248d201a5SJoerg Sonnenberger int
move_file(const char * from,const char * to)5348d201a5SJoerg Sonnenberger move_file(const char *from, const char *to)
5448d201a5SJoerg Sonnenberger {
5548d201a5SJoerg Sonnenberger int fromfd;
5648d201a5SJoerg Sonnenberger ssize_t i;
5748d201a5SJoerg Sonnenberger
5848d201a5SJoerg Sonnenberger /* to stdout? */
5948d201a5SJoerg Sonnenberger
6048d201a5SJoerg Sonnenberger if (strEQ(to, "-")) {
6148d201a5SJoerg Sonnenberger #ifdef DEBUGGING
6248d201a5SJoerg Sonnenberger if (debug & 4)
6348d201a5SJoerg Sonnenberger say("Moving %s to stdout.\n", from);
6448d201a5SJoerg Sonnenberger #endif
6548d201a5SJoerg Sonnenberger fromfd = open(from, O_RDONLY);
6648d201a5SJoerg Sonnenberger if (fromfd < 0)
6748d201a5SJoerg Sonnenberger pfatal("internal error, can't reopen %s", from);
685027f2b8SJohn Marino while ((i = read(fromfd, buf, buf_size)) > 0)
6948d201a5SJoerg Sonnenberger if (write(STDOUT_FILENO, buf, i) != i)
7048d201a5SJoerg Sonnenberger pfatal("write failed");
7148d201a5SJoerg Sonnenberger close(fromfd);
7248d201a5SJoerg Sonnenberger return 0;
7348d201a5SJoerg Sonnenberger }
7448d201a5SJoerg Sonnenberger if (backup_file(to) < 0) {
7548d201a5SJoerg Sonnenberger say("Can't backup %s, output is in %s: %s\n", to, from,
7648d201a5SJoerg Sonnenberger strerror(errno));
7748d201a5SJoerg Sonnenberger return -1;
7848d201a5SJoerg Sonnenberger }
7948d201a5SJoerg Sonnenberger #ifdef DEBUGGING
8048d201a5SJoerg Sonnenberger if (debug & 4)
8148d201a5SJoerg Sonnenberger say("Moving %s to %s.\n", from, to);
8248d201a5SJoerg Sonnenberger #endif
8348d201a5SJoerg Sonnenberger if (rename(from, to) < 0) {
8448d201a5SJoerg Sonnenberger if (errno != EXDEV || copy_file(from, to) < 0) {
8548d201a5SJoerg Sonnenberger say("Can't create %s, output is in %s: %s\n",
8648d201a5SJoerg Sonnenberger to, from, strerror(errno));
8748d201a5SJoerg Sonnenberger return -1;
8848d201a5SJoerg Sonnenberger }
8948d201a5SJoerg Sonnenberger }
9048d201a5SJoerg Sonnenberger return 0;
9148d201a5SJoerg Sonnenberger }
9248d201a5SJoerg Sonnenberger
9348d201a5SJoerg Sonnenberger /* Backup the original file. */
9448d201a5SJoerg Sonnenberger
9548d201a5SJoerg Sonnenberger int
backup_file(const char * orig)9648d201a5SJoerg Sonnenberger backup_file(const char *orig)
9748d201a5SJoerg Sonnenberger {
9848d201a5SJoerg Sonnenberger struct stat filestat;
99*b94b84caSDaniel Fojt char bakname[PATH_MAX], *s, *simplename;
10048d201a5SJoerg Sonnenberger dev_t orig_device;
10148d201a5SJoerg Sonnenberger ino_t orig_inode;
10248d201a5SJoerg Sonnenberger
10348d201a5SJoerg Sonnenberger if (backup_type == none || stat(orig, &filestat) != 0)
10448d201a5SJoerg Sonnenberger return 0; /* nothing to do */
105be7fdc21SSimon Schubert /*
106be7fdc21SSimon Schubert * If the user used zero prefixes or suffixes, then
107e888e232SSimon Schubert * he doesn't want backups. Yet we have to remove
108e888e232SSimon Schubert * orig to break possible hardlinks.
109be7fdc21SSimon Schubert */
110e888e232SSimon Schubert if ((origprae && *origprae == 0) || *simple_backup_suffix == 0) {
111e888e232SSimon Schubert unlink(orig);
112be7fdc21SSimon Schubert return 0;
113e888e232SSimon Schubert }
11448d201a5SJoerg Sonnenberger orig_device = filestat.st_dev;
11548d201a5SJoerg Sonnenberger orig_inode = filestat.st_ino;
11648d201a5SJoerg Sonnenberger
11748d201a5SJoerg Sonnenberger if (origprae) {
11848d201a5SJoerg Sonnenberger if (strlcpy(bakname, origprae, sizeof(bakname)) >= sizeof(bakname) ||
11948d201a5SJoerg Sonnenberger strlcat(bakname, orig, sizeof(bakname)) >= sizeof(bakname))
12048d201a5SJoerg Sonnenberger fatal("filename %s too long for buffer\n", origprae);
12148d201a5SJoerg Sonnenberger } else {
12248d201a5SJoerg Sonnenberger if ((s = find_backup_file_name(orig)) == NULL)
12348d201a5SJoerg Sonnenberger fatal("out of memory\n");
12448d201a5SJoerg Sonnenberger if (strlcpy(bakname, s, sizeof(bakname)) >= sizeof(bakname))
12548d201a5SJoerg Sonnenberger fatal("filename %s too long for buffer\n", s);
12648d201a5SJoerg Sonnenberger free(s);
12748d201a5SJoerg Sonnenberger }
12848d201a5SJoerg Sonnenberger
12948d201a5SJoerg Sonnenberger if ((simplename = strrchr(bakname, '/')) != NULL)
13048d201a5SJoerg Sonnenberger simplename = simplename + 1;
13148d201a5SJoerg Sonnenberger else
13248d201a5SJoerg Sonnenberger simplename = bakname;
13348d201a5SJoerg Sonnenberger
13448d201a5SJoerg Sonnenberger /*
13548d201a5SJoerg Sonnenberger * Find a backup name that is not the same file. Change the
13648d201a5SJoerg Sonnenberger * first lowercase char into uppercase; if that isn't
13748d201a5SJoerg Sonnenberger * sufficient, chop off the first char and try again.
13848d201a5SJoerg Sonnenberger */
13948d201a5SJoerg Sonnenberger while (stat(bakname, &filestat) == 0 &&
14048d201a5SJoerg Sonnenberger orig_device == filestat.st_dev && orig_inode == filestat.st_ino) {
14148d201a5SJoerg Sonnenberger /* Skip initial non-lowercase chars. */
14241871674SJoerg Sonnenberger for (s = simplename; *s && !islower((unsigned char)*s); s++)
14348d201a5SJoerg Sonnenberger ;
14448d201a5SJoerg Sonnenberger if (*s)
14541871674SJoerg Sonnenberger *s = toupper((unsigned char)*s);
14648d201a5SJoerg Sonnenberger else
14748d201a5SJoerg Sonnenberger memmove(simplename, simplename + 1,
14848d201a5SJoerg Sonnenberger strlen(simplename + 1) + 1);
14948d201a5SJoerg Sonnenberger }
15048d201a5SJoerg Sonnenberger #ifdef DEBUGGING
15148d201a5SJoerg Sonnenberger if (debug & 4)
15248d201a5SJoerg Sonnenberger say("Moving %s to %s.\n", orig, bakname);
15348d201a5SJoerg Sonnenberger #endif
15448d201a5SJoerg Sonnenberger if (rename(orig, bakname) < 0) {
15548d201a5SJoerg Sonnenberger if (errno != EXDEV || copy_file(orig, bakname) < 0)
15648d201a5SJoerg Sonnenberger return -1;
15748d201a5SJoerg Sonnenberger }
15848d201a5SJoerg Sonnenberger return 0;
15948d201a5SJoerg Sonnenberger }
16048d201a5SJoerg Sonnenberger
16148d201a5SJoerg Sonnenberger /*
16248d201a5SJoerg Sonnenberger * Copy a file.
16348d201a5SJoerg Sonnenberger */
16448d201a5SJoerg Sonnenberger int
copy_file(const char * from,const char * to)16548d201a5SJoerg Sonnenberger copy_file(const char *from, const char *to)
16648d201a5SJoerg Sonnenberger {
16748d201a5SJoerg Sonnenberger int tofd, fromfd;
16848d201a5SJoerg Sonnenberger ssize_t i;
16948d201a5SJoerg Sonnenberger
17048d201a5SJoerg Sonnenberger tofd = open(to, O_CREAT|O_TRUNC|O_WRONLY, 0666);
17148d201a5SJoerg Sonnenberger if (tofd < 0)
17248d201a5SJoerg Sonnenberger return -1;
17348d201a5SJoerg Sonnenberger fromfd = open(from, O_RDONLY, 0);
17448d201a5SJoerg Sonnenberger if (fromfd < 0)
17548d201a5SJoerg Sonnenberger pfatal("internal error, can't reopen %s", from);
1765027f2b8SJohn Marino while ((i = read(fromfd, buf, buf_size)) > 0)
17748d201a5SJoerg Sonnenberger if (write(tofd, buf, i) != i)
17848d201a5SJoerg Sonnenberger pfatal("write to %s failed", to);
17948d201a5SJoerg Sonnenberger close(fromfd);
18048d201a5SJoerg Sonnenberger close(tofd);
18148d201a5SJoerg Sonnenberger return 0;
18248d201a5SJoerg Sonnenberger }
18348d201a5SJoerg Sonnenberger
18448d201a5SJoerg Sonnenberger /*
18548d201a5SJoerg Sonnenberger * Allocate a unique area for a string.
18648d201a5SJoerg Sonnenberger */
18748d201a5SJoerg Sonnenberger char *
savestr(const char * s)18848d201a5SJoerg Sonnenberger savestr(const char *s)
18948d201a5SJoerg Sonnenberger {
19048d201a5SJoerg Sonnenberger char *rv;
19148d201a5SJoerg Sonnenberger
19248d201a5SJoerg Sonnenberger if (!s)
19348d201a5SJoerg Sonnenberger s = "Oops";
19448d201a5SJoerg Sonnenberger rv = strdup(s);
19548d201a5SJoerg Sonnenberger if (rv == NULL) {
19648d201a5SJoerg Sonnenberger if (using_plan_a)
19748d201a5SJoerg Sonnenberger out_of_mem = true;
19848d201a5SJoerg Sonnenberger else
19948d201a5SJoerg Sonnenberger fatal("out of memory\n");
20048d201a5SJoerg Sonnenberger }
20148d201a5SJoerg Sonnenberger return rv;
20248d201a5SJoerg Sonnenberger }
20348d201a5SJoerg Sonnenberger
20448d201a5SJoerg Sonnenberger /*
205*b94b84caSDaniel Fojt * Allocate a unique area for a string. Call fatal if out of memory.
206*b94b84caSDaniel Fojt */
207*b94b84caSDaniel Fojt char *
xstrdup(const char * s)208*b94b84caSDaniel Fojt xstrdup(const char *s)
209*b94b84caSDaniel Fojt {
210*b94b84caSDaniel Fojt char *rv;
211*b94b84caSDaniel Fojt
212*b94b84caSDaniel Fojt if (!s)
213*b94b84caSDaniel Fojt s = "Oops";
214*b94b84caSDaniel Fojt rv = strdup(s);
215*b94b84caSDaniel Fojt if (rv == NULL)
216*b94b84caSDaniel Fojt fatal("out of memory\n");
217*b94b84caSDaniel Fojt return rv;
218*b94b84caSDaniel Fojt }
219*b94b84caSDaniel Fojt
220*b94b84caSDaniel Fojt /*
22148d201a5SJoerg Sonnenberger * Vanilla terminal output (buffered).
22248d201a5SJoerg Sonnenberger */
22348d201a5SJoerg Sonnenberger void
say(const char * fmt,...)22448d201a5SJoerg Sonnenberger say(const char *fmt, ...)
22548d201a5SJoerg Sonnenberger {
22648d201a5SJoerg Sonnenberger va_list ap;
22748d201a5SJoerg Sonnenberger
22848d201a5SJoerg Sonnenberger va_start(ap, fmt);
2295027f2b8SJohn Marino vfprintf(stdout, fmt, ap);
23048d201a5SJoerg Sonnenberger va_end(ap);
2315027f2b8SJohn Marino fflush(stdout);
23248d201a5SJoerg Sonnenberger }
23348d201a5SJoerg Sonnenberger
23448d201a5SJoerg Sonnenberger /*
23548d201a5SJoerg Sonnenberger * Terminal output, pun intended.
23648d201a5SJoerg Sonnenberger */
23748d201a5SJoerg Sonnenberger void
fatal(const char * fmt,...)23848d201a5SJoerg Sonnenberger fatal(const char *fmt, ...)
23948d201a5SJoerg Sonnenberger {
24048d201a5SJoerg Sonnenberger va_list ap;
24148d201a5SJoerg Sonnenberger
24248d201a5SJoerg Sonnenberger va_start(ap, fmt);
24348d201a5SJoerg Sonnenberger fprintf(stderr, "patch: **** ");
24448d201a5SJoerg Sonnenberger vfprintf(stderr, fmt, ap);
24548d201a5SJoerg Sonnenberger va_end(ap);
24648d201a5SJoerg Sonnenberger my_exit(2);
24748d201a5SJoerg Sonnenberger }
24848d201a5SJoerg Sonnenberger
24948d201a5SJoerg Sonnenberger /*
25048d201a5SJoerg Sonnenberger * Say something from patch, something from the system, then silence . . .
25148d201a5SJoerg Sonnenberger */
25248d201a5SJoerg Sonnenberger void
pfatal(const char * fmt,...)25348d201a5SJoerg Sonnenberger pfatal(const char *fmt, ...)
25448d201a5SJoerg Sonnenberger {
25548d201a5SJoerg Sonnenberger va_list ap;
25648d201a5SJoerg Sonnenberger int errnum = errno;
25748d201a5SJoerg Sonnenberger
25848d201a5SJoerg Sonnenberger fprintf(stderr, "patch: **** ");
25948d201a5SJoerg Sonnenberger va_start(ap, fmt);
26048d201a5SJoerg Sonnenberger vfprintf(stderr, fmt, ap);
26148d201a5SJoerg Sonnenberger va_end(ap);
26248d201a5SJoerg Sonnenberger fprintf(stderr, ": %s\n", strerror(errnum));
26348d201a5SJoerg Sonnenberger my_exit(2);
26448d201a5SJoerg Sonnenberger }
26548d201a5SJoerg Sonnenberger
26648d201a5SJoerg Sonnenberger /*
26748d201a5SJoerg Sonnenberger * Get a response from the user via /dev/tty
26848d201a5SJoerg Sonnenberger */
26948d201a5SJoerg Sonnenberger void
ask(const char * fmt,...)27048d201a5SJoerg Sonnenberger ask(const char *fmt, ...)
27148d201a5SJoerg Sonnenberger {
27248d201a5SJoerg Sonnenberger va_list ap;
27348d201a5SJoerg Sonnenberger ssize_t nr = 0;
27448d201a5SJoerg Sonnenberger static int ttyfd = -1;
27548d201a5SJoerg Sonnenberger
27648d201a5SJoerg Sonnenberger va_start(ap, fmt);
27748d201a5SJoerg Sonnenberger vfprintf(stdout, fmt, ap);
27848d201a5SJoerg Sonnenberger va_end(ap);
27948d201a5SJoerg Sonnenberger fflush(stdout);
28048d201a5SJoerg Sonnenberger if (ttyfd < 0)
28148d201a5SJoerg Sonnenberger ttyfd = open(_PATH_TTY, O_RDONLY);
28248d201a5SJoerg Sonnenberger if (ttyfd >= 0) {
2835027f2b8SJohn Marino if ((nr = read(ttyfd, buf, buf_size)) > 0 &&
28448d201a5SJoerg Sonnenberger buf[nr - 1] == '\n')
28548d201a5SJoerg Sonnenberger buf[nr - 1] = '\0';
28648d201a5SJoerg Sonnenberger }
28748d201a5SJoerg Sonnenberger if (ttyfd < 0 || nr <= 0) {
28848d201a5SJoerg Sonnenberger /* no tty or error reading, pretend user entered 'return' */
28948d201a5SJoerg Sonnenberger putchar('\n');
29048d201a5SJoerg Sonnenberger buf[0] = '\0';
29148d201a5SJoerg Sonnenberger }
29248d201a5SJoerg Sonnenberger }
29348d201a5SJoerg Sonnenberger
29448d201a5SJoerg Sonnenberger /*
29548d201a5SJoerg Sonnenberger * How to handle certain events when not in a critical region.
29648d201a5SJoerg Sonnenberger */
29748d201a5SJoerg Sonnenberger void
set_signals(int reset)29848d201a5SJoerg Sonnenberger set_signals(int reset)
29948d201a5SJoerg Sonnenberger {
30048d201a5SJoerg Sonnenberger static sig_t hupval, intval;
30148d201a5SJoerg Sonnenberger
30248d201a5SJoerg Sonnenberger if (!reset) {
30348d201a5SJoerg Sonnenberger hupval = signal(SIGHUP, SIG_IGN);
30448d201a5SJoerg Sonnenberger if (hupval != SIG_IGN)
305f9ea5d32SJoerg Sonnenberger hupval = my_exit;
30648d201a5SJoerg Sonnenberger intval = signal(SIGINT, SIG_IGN);
30748d201a5SJoerg Sonnenberger if (intval != SIG_IGN)
308f9ea5d32SJoerg Sonnenberger intval = my_exit;
30948d201a5SJoerg Sonnenberger }
31048d201a5SJoerg Sonnenberger signal(SIGHUP, hupval);
31148d201a5SJoerg Sonnenberger signal(SIGINT, intval);
31248d201a5SJoerg Sonnenberger }
31348d201a5SJoerg Sonnenberger
31448d201a5SJoerg Sonnenberger /*
31548d201a5SJoerg Sonnenberger * How to handle certain events when in a critical region.
31648d201a5SJoerg Sonnenberger */
31748d201a5SJoerg Sonnenberger void
ignore_signals(void)31848d201a5SJoerg Sonnenberger ignore_signals(void)
31948d201a5SJoerg Sonnenberger {
32048d201a5SJoerg Sonnenberger signal(SIGHUP, SIG_IGN);
32148d201a5SJoerg Sonnenberger signal(SIGINT, SIG_IGN);
32248d201a5SJoerg Sonnenberger }
32348d201a5SJoerg Sonnenberger
32448d201a5SJoerg Sonnenberger /*
32548d201a5SJoerg Sonnenberger * Make sure we'll have the directories to create a file. If `striplast' is
32648d201a5SJoerg Sonnenberger * true, ignore the last element of `filename'.
32748d201a5SJoerg Sonnenberger */
32848d201a5SJoerg Sonnenberger
32948d201a5SJoerg Sonnenberger void
makedirs(const char * filename,bool striplast)33048d201a5SJoerg Sonnenberger makedirs(const char *filename, bool striplast)
33148d201a5SJoerg Sonnenberger {
33248d201a5SJoerg Sonnenberger char *tmpbuf;
33348d201a5SJoerg Sonnenberger
33448d201a5SJoerg Sonnenberger if ((tmpbuf = strdup(filename)) == NULL)
33548d201a5SJoerg Sonnenberger fatal("out of memory\n");
33648d201a5SJoerg Sonnenberger
33748d201a5SJoerg Sonnenberger if (striplast) {
33848d201a5SJoerg Sonnenberger char *s = strrchr(tmpbuf, '/');
339c9e3d8f9SVenkatesh Srinivas if (s == NULL) {
340c9e3d8f9SVenkatesh Srinivas free(tmpbuf);
34148d201a5SJoerg Sonnenberger return; /* nothing to be done */
342c9e3d8f9SVenkatesh Srinivas }
34348d201a5SJoerg Sonnenberger *s = '\0';
34448d201a5SJoerg Sonnenberger }
3459d62a0f9SSascha Wildner if (mkpath(tmpbuf) != 0)
3469d62a0f9SSascha Wildner pfatal("creation of %s failed", tmpbuf);
3479d62a0f9SSascha Wildner free(tmpbuf);
34848d201a5SJoerg Sonnenberger }
34948d201a5SJoerg Sonnenberger
35048d201a5SJoerg Sonnenberger /*
35148d201a5SJoerg Sonnenberger * Make filenames more reasonable.
35248d201a5SJoerg Sonnenberger */
35348d201a5SJoerg Sonnenberger char *
fetchname(const char * at,bool * exists,int strip_leading)35448d201a5SJoerg Sonnenberger fetchname(const char *at, bool *exists, int strip_leading)
35548d201a5SJoerg Sonnenberger {
35648d201a5SJoerg Sonnenberger char *fullname, *name, *t;
357f7e25d55SSascha Wildner int sleading, tab;
35848d201a5SJoerg Sonnenberger struct stat filestat;
35948d201a5SJoerg Sonnenberger
36048d201a5SJoerg Sonnenberger if (at == NULL || *at == '\0')
36148d201a5SJoerg Sonnenberger return NULL;
36241871674SJoerg Sonnenberger while (isspace((unsigned char)*at))
36348d201a5SJoerg Sonnenberger at++;
36448d201a5SJoerg Sonnenberger #ifdef DEBUGGING
36548d201a5SJoerg Sonnenberger if (debug & 128)
36648d201a5SJoerg Sonnenberger say("fetchname %s %d\n", at, strip_leading);
36748d201a5SJoerg Sonnenberger #endif
36848d201a5SJoerg Sonnenberger /* So files can be created by diffing against /dev/null. */
369*b94b84caSDaniel Fojt if (strnEQ(at, _PATH_DEVNULL, sizeof(_PATH_DEVNULL) - 1)) {
370*b94b84caSDaniel Fojt *exists = true;
37148d201a5SJoerg Sonnenberger return NULL;
372*b94b84caSDaniel Fojt }
37348d201a5SJoerg Sonnenberger name = fullname = t = savestr(at);
37448d201a5SJoerg Sonnenberger
375f7e25d55SSascha Wildner tab = strchr(t, '\t') != NULL;
37648d201a5SJoerg Sonnenberger /* Strip off up to `strip_leading' path components and NUL terminate. */
377f7e25d55SSascha Wildner for (sleading = strip_leading; *t != '\0' && ((tab && *t != '\t') ||
37841871674SJoerg Sonnenberger !isspace((unsigned char)*t)); t++) {
37948d201a5SJoerg Sonnenberger if (t[0] == '/' && t[1] != '/' && t[1] != '\0')
38048d201a5SJoerg Sonnenberger if (--sleading >= 0)
38148d201a5SJoerg Sonnenberger name = t + 1;
38248d201a5SJoerg Sonnenberger }
38348d201a5SJoerg Sonnenberger *t = '\0';
38448d201a5SJoerg Sonnenberger
38548d201a5SJoerg Sonnenberger /*
38648d201a5SJoerg Sonnenberger * If no -p option was given (957 is the default value!), we were
38748d201a5SJoerg Sonnenberger * given a relative pathname, and the leading directories that we
38848d201a5SJoerg Sonnenberger * just stripped off all exist, put them back on.
38948d201a5SJoerg Sonnenberger */
39048d201a5SJoerg Sonnenberger if (strip_leading == 957 && name != fullname && *fullname != '/') {
39148d201a5SJoerg Sonnenberger name[-1] = '\0';
39248d201a5SJoerg Sonnenberger if (stat(fullname, &filestat) == 0 && S_ISDIR(filestat.st_mode)) {
39348d201a5SJoerg Sonnenberger name[-1] = '/';
39448d201a5SJoerg Sonnenberger name = fullname;
39548d201a5SJoerg Sonnenberger }
39648d201a5SJoerg Sonnenberger }
39748d201a5SJoerg Sonnenberger name = savestr(name);
39848d201a5SJoerg Sonnenberger free(fullname);
39948d201a5SJoerg Sonnenberger
40048d201a5SJoerg Sonnenberger *exists = stat(name, &filestat) == 0;
40148d201a5SJoerg Sonnenberger return name;
40248d201a5SJoerg Sonnenberger }
40348d201a5SJoerg Sonnenberger
40448d201a5SJoerg Sonnenberger void
version(void)40548d201a5SJoerg Sonnenberger version(void)
40648d201a5SJoerg Sonnenberger {
407*b94b84caSDaniel Fojt printf("patch 2.0-12u11\n");
40848d201a5SJoerg Sonnenberger my_exit(EXIT_SUCCESS);
40948d201a5SJoerg Sonnenberger }
41048d201a5SJoerg Sonnenberger
41148d201a5SJoerg Sonnenberger /*
41248d201a5SJoerg Sonnenberger * Exit with cleanup.
41348d201a5SJoerg Sonnenberger */
41448d201a5SJoerg Sonnenberger void
my_exit(int status)41548d201a5SJoerg Sonnenberger my_exit(int status)
41648d201a5SJoerg Sonnenberger {
41748d201a5SJoerg Sonnenberger unlink(TMPINNAME);
41848d201a5SJoerg Sonnenberger if (!toutkeep)
41948d201a5SJoerg Sonnenberger unlink(TMPOUTNAME);
42048d201a5SJoerg Sonnenberger if (!trejkeep)
42148d201a5SJoerg Sonnenberger unlink(TMPREJNAME);
42248d201a5SJoerg Sonnenberger unlink(TMPPATNAME);
42348d201a5SJoerg Sonnenberger exit(status);
42448d201a5SJoerg Sonnenberger }
425