]>
git.cameronkatri.com Git - apple_cmds.git/blob - patch_cmds/patch/util.c
1 /* $OpenBSD: util.c,v 1.33 2009/10/27 23:59:41 deraadt Exp $ */
4 * patch - a program to apply diffs to original files
6 * Copyright 1986, Larry Wall
8 * Redistribution and use in source and binary forms, with or without
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.
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
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
25 * -C option added in 1998, original code by Marc Espie, based on FreeBSD
29 #include <sys/param.h>
46 #include "backupfile.h"
47 #include "pathnames.h"
49 /* Rename a file, copying it if necessary. */
52 move_file(const char *from
, const char *to
)
62 say("Moving %s to stdout.\n", from
);
64 fromfd
= open(from
, O_RDONLY
);
66 pfatal("internal error, can't reopen %s", from
);
67 while ((i
= read(fromfd
, buf
, sizeof buf
)) > 0)
68 if (write(STDOUT_FILENO
, buf
, i
) != i
)
69 pfatal("write failed");
73 if (backup_file(to
) < 0) {
74 say("Can't backup %s, output is in %s: %s\n", to
, from
,
80 say("Moving %s to %s.\n", from
, to
);
82 if (rename(from
, to
) < 0) {
83 if (errno
!= EXDEV
|| copy_file(from
, to
) < 0) {
84 say("Can't create %s, output is in %s: %s\n",
85 to
, from
, strerror(errno
));
92 /* Backup the original file. */
95 backup_file(const char *orig
)
98 char bakname
[MAXPATHLEN
], *s
, *simplename
;
102 if (backup_type
== none
|| stat(orig
, &filestat
) != 0)
103 return 0; /* nothing to do */
104 orig_device
= filestat
.st_dev
;
105 orig_inode
= filestat
.st_ino
;
108 if (strlcpy(bakname
, origprae
, sizeof(bakname
)) >= sizeof(bakname
) ||
109 strlcat(bakname
, orig
, sizeof(bakname
)) >= sizeof(bakname
))
110 fatal("filename %s too long for buffer\n", origprae
);
112 if ((s
= find_backup_file_name(orig
)) == NULL
)
113 fatal("out of memory\n");
114 if (strlcpy(bakname
, s
, sizeof(bakname
)) >= sizeof(bakname
))
115 fatal("filename %s too long for buffer\n", s
);
119 if ((simplename
= strrchr(bakname
, '/')) != NULL
)
120 simplename
= simplename
+ 1;
122 simplename
= bakname
;
125 * Find a backup name that is not the same file. Change the
126 * first lowercase char into uppercase; if that isn't
127 * sufficient, chop off the first char and try again.
129 while (stat(bakname
, &filestat
) == 0 &&
130 orig_device
== filestat
.st_dev
&& orig_inode
== filestat
.st_ino
) {
131 /* Skip initial non-lowercase chars. */
132 for (s
= simplename
; *s
&& !islower(*s
); s
++)
137 memmove(simplename
, simplename
+ 1,
138 strlen(simplename
+ 1) + 1);
142 say("Moving %s to %s.\n", orig
, bakname
);
144 if (rename(orig
, bakname
) < 0) {
145 if (errno
!= EXDEV
|| copy_file(orig
, bakname
) < 0)
155 copy_file(const char *from
, const char *to
)
160 tofd
= open(to
, O_CREAT
|O_TRUNC
|O_WRONLY
, 0666);
163 fromfd
= open(from
, O_RDONLY
, 0);
165 pfatal("internal error, can't reopen %s", from
);
166 while ((i
= read(fromfd
, buf
, sizeof buf
)) > 0)
167 if (write(tofd
, buf
, i
) != i
)
168 pfatal("write to %s failed", to
);
175 * Allocate a unique area for a string.
178 savestr(const char *s
)
189 fatal("out of memory\n");
195 * Vanilla terminal output (buffered).
198 say(const char *fmt
, ...)
203 vfprintf(stderr
, fmt
, ap
);
209 * Terminal output, pun intended.
212 fatal(const char *fmt
, ...)
217 fprintf(stderr
, "patch: **** ");
218 vfprintf(stderr
, fmt
, ap
);
224 * Say something from patch, something from the system, then silence . . .
227 pfatal(const char *fmt
, ...)
232 fprintf(stderr
, "patch: **** ");
234 vfprintf(stderr
, fmt
, ap
);
236 fprintf(stderr
, ": %s\n", strerror(errnum
));
241 * Get a response from the user via /dev/tty
244 ask(const char *fmt
, ...)
248 static int ttyfd
= -1;
251 vfprintf(stdout
, fmt
, ap
);
255 ttyfd
= open(_PATH_TTY
, O_RDONLY
);
257 if ((nr
= read(ttyfd
, buf
, sizeof(buf
))) > 0 &&
261 if (ttyfd
< 0 || nr
<= 0) {
262 /* no tty or error reading, pretend user entered 'return' */
269 * How to handle certain events when not in a critical region.
272 set_signals(int reset
)
274 static sig_t hupval
, intval
;
277 hupval
= signal(SIGHUP
, SIG_IGN
);
278 if (hupval
!= SIG_IGN
)
279 hupval
= (sig_t
) my_exit
;
280 intval
= signal(SIGINT
, SIG_IGN
);
281 if (intval
!= SIG_IGN
)
282 intval
= (sig_t
) my_exit
;
284 signal(SIGHUP
, hupval
);
285 signal(SIGINT
, intval
);
289 * How to handle certain events when in a critical region.
294 signal(SIGHUP
, SIG_IGN
);
295 signal(SIGINT
, SIG_IGN
);
299 * Make sure we'll have the directories to create a file. If `striplast' is
300 * true, ignore the last element of `filename'.
304 makedirs(const char *filename
, bool striplast
)
308 if ((tmpbuf
= strdup(filename
)) == NULL
)
309 fatal("out of memory\n");
312 char *s
= strrchr(tmpbuf
, '/');
314 return; /* nothing to be done */
317 if (mkpath(tmpbuf
) != 0)
318 pfatal("creation of %s failed", tmpbuf
);
323 * Make filenames more reasonable.
326 fetchname(const char *at
, bool *exists
, int strip_leading
)
328 char *fullname
, *name
, *t
;
330 struct stat filestat
;
332 if (at
== NULL
|| *at
== '\0')
338 say("fetchname %s %d\n", at
, strip_leading
);
340 /* So files can be created by diffing against /dev/null. */
341 if (strnEQ(at
, _PATH_DEVNULL
, sizeof(_PATH_DEVNULL
) - 1))
343 name
= fullname
= t
= savestr(at
);
345 tab
= strchr(t
, '\t') != NULL
;
346 /* Strip off up to `strip_leading' path components and NUL terminate. */
347 for (sleading
= strip_leading
; *t
!= '\0' && ((tab
&& *t
!= '\t') ||
348 !isspace(*t
)); t
++) {
349 if (t
[0] == '/' && t
[1] != '/' && t
[1] != '\0')
356 * If no -p option was given (957 is the default value!), we were
357 * given a relative pathname, and the leading directories that we
358 * just stripped off all exist, put them back on.
360 if (strip_leading
== 957 && name
!= fullname
&& *fullname
!= '/') {
362 if (stat(fullname
, &filestat
) == 0 && S_ISDIR(filestat
.st_mode
)) {
367 name
= savestr(name
);
370 *exists
= stat(name
, &filestat
) == 0;
375 * Takes the name returned by fetchname and looks in RCS/SCCS directories
376 * for a checked in version.
379 checked_in(char *file
)
381 char *filebase
, *filedir
, tmpbuf
[MAXPATHLEN
];
382 struct stat filestat
;
384 filebase
= basename(file
);
385 filedir
= dirname(file
);
387 #define try(f, a1, a2, a3) \
388 (snprintf(tmpbuf, sizeof tmpbuf, f, a1, a2, a3), stat(tmpbuf, &filestat) == 0)
390 if (try("%s/RCS/%s%s", filedir
, filebase
, RCSSUFFIX
) ||
391 try("%s/RCS/%s%s", filedir
, filebase
, "") ||
392 try("%s/%s%s", filedir
, filebase
, RCSSUFFIX
) ||
393 try("%s/SCCS/%s%s", filedir
, SCCSPREFIX
, filebase
) ||
394 try("%s/%s%s", filedir
, SCCSPREFIX
, filebase
))
403 fprintf(stderr
, "Patch version 2.0-12u8-Apple\n");
404 my_exit(EXIT_SUCCESS
);