clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name util.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/patch/obj -resource-dir /usr/local/llvm16/lib/clang/16 -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/patch/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.bin/patch/util.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | #include <sys/stat.h> |
30 | |
31 | #include <ctype.h> |
32 | #include <errno.h> |
33 | #include <fcntl.h> |
34 | #include <paths.h> |
35 | #include <signal.h> |
36 | #include <stdarg.h> |
37 | #include <stdlib.h> |
38 | #include <stdio.h> |
39 | #include <string.h> |
40 | #include <unistd.h> |
41 | |
42 | #include "common.h" |
43 | #include "util.h" |
44 | #include "backupfile.h" |
45 | |
46 | |
47 | |
48 | int |
49 | move_file(const char *from, const char *to) |
50 | { |
51 | int fromfd; |
52 | ssize_t i; |
53 | |
54 | |
55 | |
56 | if (strEQ(to, "-")) { |
57 | #ifdef DEBUGGING |
58 | if (debug & 4) |
59 | say("Moving %s to stdout.\n", from); |
60 | #endif |
61 | fromfd = open(from, O_RDONLY); |
62 | if (fromfd == -1) |
63 | pfatal("internal error, can't reopen %s", from); |
64 | while ((i = read(fromfd, buf, bufsz)) > 0) |
65 | if (write(STDOUT_FILENO, buf, i) != i) |
66 | pfatal("write failed"); |
67 | close(fromfd); |
68 | return 0; |
69 | } |
70 | if (backup_file(to) < 0) { |
71 | say("Can't backup %s, output is in %s: %s\n", to, from, |
72 | strerror(errno)); |
73 | return -1; |
74 | } |
75 | #ifdef DEBUGGING |
76 | if (debug & 4) |
77 | say("Moving %s to %s.\n", from, to); |
78 | #endif |
79 | if (rename(from, to) == -1) { |
80 | if (errno != EXDEV || copy_file(from, to) < 0) { |
81 | say("Can't create %s, output is in %s: %s\n", |
82 | to, from, strerror(errno)); |
83 | return -1; |
84 | } |
85 | } |
86 | return 0; |
87 | } |
88 | |
89 | |
90 | |
91 | int |
92 | backup_file(const char *orig) |
93 | { |
94 | struct stat filestat; |
95 | char bakname[PATH_MAX], *s, *simplename; |
96 | dev_t orig_device; |
97 | ino_t orig_inode; |
98 | |
99 | if (backup_type == none || stat(orig, &filestat) != 0) |
100 | return 0; |
101 | orig_device = filestat.st_dev; |
102 | orig_inode = filestat.st_ino; |
103 | |
104 | if (origprae) { |
105 | if (strlcpy(bakname, origprae, sizeof(bakname)) >= sizeof(bakname) || |
106 | strlcat(bakname, orig, sizeof(bakname)) >= sizeof(bakname)) |
107 | fatal("filename %s too long for buffer\n", origprae); |
108 | } else { |
109 | if ((s = find_backup_file_name(orig)) == NULL) |
110 | fatal("out of memory\n"); |
111 | if (strlcpy(bakname, s, sizeof(bakname)) >= sizeof(bakname)) |
112 | fatal("filename %s too long for buffer\n", s); |
113 | free(s); |
114 | } |
115 | |
116 | if ((simplename = strrchr(bakname, '/')) != NULL) |
117 | simplename = simplename + 1; |
118 | else |
119 | simplename = bakname; |
120 | |
121 | |
122 | |
123 | |
124 | |
125 | |
126 | while (stat(bakname, &filestat) == 0 && |
127 | orig_device == filestat.st_dev && orig_inode == filestat.st_ino) { |
128 | |
129 | for (s = simplename; *s && !islower((unsigned char)*s); s++) |
130 | ; |
131 | if (*s) |
132 | *s = toupper((unsigned char)*s); |
133 | else |
134 | memmove(simplename, simplename + 1, |
135 | strlen(simplename + 1) + 1); |
136 | } |
137 | #ifdef DEBUGGING |
138 | if (debug & 4) |
139 | say("Moving %s to %s.\n", orig, bakname); |
140 | #endif |
141 | if (rename(orig, bakname) == -1) { |
142 | if (errno != EXDEV || copy_file(orig, bakname) < 0) |
143 | return -1; |
144 | } |
145 | return 0; |
146 | } |
147 | |
148 | |
149 | |
150 | |
151 | int |
152 | copy_file(const char *from, const char *to) |
153 | { |
154 | int tofd, fromfd; |
155 | ssize_t i; |
156 | |
157 | tofd = open(to, O_CREAT|O_TRUNC|O_WRONLY, 0666); |
158 | if (tofd == -1) |
159 | return -1; |
160 | fromfd = open(from, O_RDONLY); |
161 | if (fromfd == -1) |
162 | pfatal("internal error, can't reopen %s", from); |
163 | while ((i = read(fromfd, buf, bufsz)) > 0) |
164 | if (write(tofd, buf, i) != i) |
165 | pfatal("write to %s failed", to); |
166 | close(fromfd); |
167 | close(tofd); |
168 | return 0; |
169 | } |
170 | |
171 | |
172 | |
173 | |
174 | char * |
175 | savestr(const char *s) |
176 | { |
177 | char *rv; |
178 | |
179 | if (!s) |
180 | s = "Oops"; |
181 | rv = strdup(s); |
182 | if (rv == NULL) { |
183 | if (using_plan_a) |
184 | out_of_mem = true; |
185 | else |
186 | fatal("out of memory\n"); |
187 | } |
188 | return rv; |
189 | } |
190 | |
191 | |
192 | |
193 | |
194 | char * |
195 | xstrdup(const char *s) |
196 | { |
197 | char *rv; |
198 | |
199 | if (!s) |
200 | s = "Oops"; |
201 | rv = strdup(s); |
202 | if (rv == NULL) |
203 | fatal("out of memory\n"); |
204 | return rv; |
205 | } |
206 | |
207 | |
208 | |
209 | |
210 | void |
211 | say(const char *fmt, ...) |
212 | { |
213 | va_list ap; |
214 | |
215 | va_start(ap, fmt); |
216 | vfprintf(stdout, fmt, ap); |
217 | va_end(ap); |
218 | fflush(stdout); |
219 | } |
220 | |
221 | |
222 | |
223 | |
224 | void |
225 | fatal(const char *fmt, ...) |
226 | { |
227 | va_list ap; |
228 | |
229 | va_start(ap, fmt); |
230 | fprintf(stderr, "patch: **** "); |
231 | vfprintf(stderr, fmt, ap); |
232 | va_end(ap); |
233 | my_exit(2); |
234 | } |
235 | |
236 | |
237 | |
238 | |
239 | void |
240 | pfatal(const char *fmt, ...) |
241 | { |
242 | va_list ap; |
243 | int errnum = errno; |
244 | |
245 | fprintf(stderr, "patch: **** "); |
246 | va_start(ap, fmt); |
247 | vfprintf(stderr, fmt, ap); |
248 | va_end(ap); |
249 | fprintf(stderr, ": %s\n", strerror(errnum)); |
250 | my_exit(2); |
251 | } |
252 | |
253 | |
254 | |
255 | |
256 | void |
257 | ask(const char *fmt, ...) |
258 | { |
259 | va_list ap; |
260 | ssize_t nr; |
| 1 | 'nr' declared without an initial value | |
|
261 | static int ttyfd = -1; |
262 | |
263 | va_start(ap, fmt); |
264 | vfprintf(stdout, fmt, ap); |
265 | va_end(ap); |
266 | fflush(stdout); |
267 | if (ttyfd < 0) |
| |
268 | ttyfd = open(_PATH_TTY, O_RDONLY); |
269 | if (ttyfd >= 0) { |
| |
270 | if ((nr = read(ttyfd, buf, bufsz)) > 0 && |
271 | buf[nr - 1] == '\n') |
272 | buf[nr - 1] = '\0'; |
273 | } |
274 | if (ttyfd == -1 || nr <= 0) { |
| 4 | | Assuming the condition is false | |
|
| 5 | | The left operand of '<=' is a garbage value |
|
275 | |
276 | putchar('\n'); |
277 | buf[0] = '\0'; |
278 | } |
279 | } |
280 | |
281 | |
282 | |
283 | |
284 | void |
285 | set_signals(int reset) |
286 | { |
287 | static sig_t hupval, intval; |
288 | |
289 | if (!reset) { |
290 | hupval = signal(SIGHUP, SIG_IGN); |
291 | if (hupval != SIG_IGN) |
292 | hupval = my_sigexit; |
293 | intval = signal(SIGINT, SIG_IGN); |
294 | if (intval != SIG_IGN) |
295 | intval = my_sigexit; |
296 | } |
297 | signal(SIGHUP, hupval); |
298 | signal(SIGINT, intval); |
299 | } |
300 | |
301 | |
302 | |
303 | |
304 | void |
305 | ignore_signals(void) |
306 | { |
307 | signal(SIGHUP, SIG_IGN); |
308 | signal(SIGINT, SIG_IGN); |
309 | } |
310 | |
311 | |
312 | |
313 | |
314 | |
315 | |
316 | void |
317 | makedirs(const char *filename, bool striplast) |
318 | { |
319 | char *tmpbuf; |
320 | |
321 | if ((tmpbuf = strdup(filename)) == NULL) |
322 | fatal("out of memory\n"); |
323 | |
324 | if (striplast) { |
325 | char *s = strrchr(tmpbuf, '/'); |
326 | if (s == NULL) { |
327 | free(tmpbuf); |
328 | return; |
329 | } |
330 | *s = '\0'; |
331 | } |
332 | if (mkpath(tmpbuf) != 0) |
333 | pfatal("creation of %s failed", tmpbuf); |
334 | free(tmpbuf); |
335 | } |
336 | |
337 | |
338 | |
339 | |
340 | char * |
341 | fetchname(const char *at, bool *exists, int strip_leading) |
342 | { |
343 | char *fullname, *name, *t; |
344 | int sleading, tab; |
345 | struct stat filestat; |
346 | |
347 | if (at == NULL || *at == '\0') |
348 | return NULL; |
349 | while (isspace((unsigned char)*at)) |
350 | at++; |
351 | #ifdef DEBUGGING |
352 | if (debug & 128) |
353 | say("fetchname %s %d\n", at, strip_leading); |
354 | #endif |
355 | |
356 | if (strnEQ(at, _PATH_DEVNULL, sizeof(_PATH_DEVNULL) - 1)) |
357 | return NULL; |
358 | name = fullname = t = savestr(at); |
359 | |
360 | tab = strchr(t, '\t') != NULL; |
361 | |
362 | for (sleading = strip_leading; *t != '\0' && ((tab && *t != '\t') || |
363 | !isspace((unsigned char)*t)); t++) { |
364 | if (t[0] == '/' && t[1] != '/' && t[1] != '\0') |
365 | if (--sleading >= 0) |
366 | name = t + 1; |
367 | } |
368 | *t = '\0'; |
369 | |
370 | |
371 | |
372 | |
373 | |
374 | |
375 | if (strip_leading == 957 && name != fullname && *fullname != '/') { |
376 | name[-1] = '\0'; |
377 | if (stat(fullname, &filestat) == 0 && S_ISDIR(filestat.st_mode)) { |
378 | name[-1] = '/'; |
379 | name = fullname; |
380 | } |
381 | } |
382 | name = savestr(name); |
383 | free(fullname); |
384 | |
385 | *exists = stat(name, &filestat) == 0; |
386 | return name; |
387 | } |
388 | |
389 | void |
390 | version(void) |
391 | { |
392 | fprintf(stderr, "Patch version 2.0-12u8-OpenBSD\n"); |
393 | my_exit(EXIT_SUCCESS); |
394 | } |
395 | |
396 | void |
397 | my_cleanup(void) |
398 | { |
399 | unlink(TMPINNAME); |
400 | if (!toutkeep) |
401 | unlink(TMPOUTNAME); |
402 | if (!trejkeep) |
403 | unlink(TMPREJNAME); |
404 | unlink(TMPPATNAME); |
405 | } |
406 | |
407 | |
408 | |
409 | |
410 | void |
411 | my_exit(int status) |
412 | { |
413 | my_cleanup(); |
414 | exit(status); |
415 | } |
416 | |
417 | |
418 | |
419 | |
420 | void |
421 | my_sigexit(int signo) |
422 | { |
423 | my_cleanup(); |
424 | _exit(2); |
425 | } |