xref: /dflybsd-src/usr.bin/patch/util.c (revision b94b84ca5c08efb447331811e050106ac4c7d3f1)
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