clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name cp.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -fno-rounding-math -mconstructor-aliases -munwind-tables -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/bin/cp/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/bin/cp/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -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/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/bin/cp/cp.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 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | #include <sys/types.h> |
52 | #include <sys/stat.h> |
53 | #include <sys/mman.h> |
54 | #include <sys/time.h> |
55 | |
56 | #include <dirent.h> |
57 | #include <err.h> |
58 | #include <errno.h> |
59 | #include <fcntl.h> |
60 | #include <fts.h> |
61 | #include <limits.h> |
62 | #include <stdio.h> |
63 | #include <stdlib.h> |
64 | #include <string.h> |
65 | #include <unistd.h> |
66 | |
67 | #include "extern.h" |
68 | |
69 | #define fts_dne(_x) (_x->fts_pointer != NULL) |
70 | |
71 | PATH_T to = { to.p_path, "" }; |
72 | |
73 | uid_t myuid; |
74 | int Rflag, fflag, iflag, pflag, rflag, vflag; |
75 | mode_t myumask; |
76 | |
77 | enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; |
78 | |
79 | int copy(char *[], enum op, int); |
80 | char *find_last_component(char *); |
81 | |
82 | int |
83 | main(int argc, char *argv[]) |
84 | { |
85 | struct stat to_stat, tmp_stat; |
86 | enum op type; |
87 | int Hflag, Lflag, Pflag, ch, fts_options, r; |
88 | char *target; |
89 | |
90 | Hflag = Lflag = Pflag = Rflag = 0; |
91 | while ((ch = getopt(argc, argv, "HLPRafiprv")) != -1) |
| 1 | Assuming the condition is false | |
|
| 2 | | Loop condition is false. Execution continues on line 135 | |
|
92 | switch (ch) { |
93 | case 'H': |
94 | Hflag = 1; |
95 | Lflag = Pflag = 0; |
96 | break; |
97 | case 'L': |
98 | Lflag = 1; |
99 | Hflag = Pflag = 0; |
100 | break; |
101 | case 'P': |
102 | Pflag = 1; |
103 | Hflag = Lflag = 0; |
104 | break; |
105 | case 'R': |
106 | Rflag = 1; |
107 | break; |
108 | case 'a': |
109 | Rflag = 1; |
110 | pflag = 1; |
111 | Pflag = 1; |
112 | Hflag = Lflag = 0; |
113 | break; |
114 | case 'f': |
115 | fflag = 1; |
116 | iflag = 0; |
117 | break; |
118 | case 'i': |
119 | iflag = 1; |
120 | fflag = 0; |
121 | break; |
122 | case 'p': |
123 | pflag = 1; |
124 | break; |
125 | case 'r': |
126 | rflag = 1; |
127 | break; |
128 | case 'v': |
129 | vflag = 1; |
130 | break; |
131 | default: |
132 | usage(); |
133 | break; |
134 | } |
135 | argc -= optind; |
136 | argv += optind; |
137 | |
138 | |
139 | |
140 | |
141 | |
142 | if (Rflag == 0 && pflag == 0) |
| 3 | | Assuming 'pflag' is not equal to 0 | |
|
| |
143 | if (pledge("stdio rpath wpath cpath fattr", NULL) == -1) |
144 | err(1, "pledge"); |
145 | |
146 | if (argc < 2) |
| |
| |
147 | usage(); |
148 | |
149 | fts_options = FTS_NOCHDIR | FTS_PHYSICAL; |
150 | if (rflag) { |
| |
| |
151 | if (Rflag) |
152 | errx(1, |
153 | "the -R and -r options may not be specified together."); |
154 | if (Hflag || Lflag || Pflag) |
155 | errx(1, |
156 | "the -H, -L, and -P options may not be specified with the -r option."); |
157 | fts_options &= ~FTS_PHYSICAL; |
158 | fts_options |= FTS_LOGICAL; |
159 | } |
160 | if (Rflag) { |
| |
161 | if (Hflag) |
162 | fts_options |= FTS_COMFOLLOW; |
163 | if (Lflag) { |
164 | fts_options &= ~FTS_PHYSICAL; |
165 | fts_options |= FTS_LOGICAL; |
166 | } |
167 | } else { |
168 | fts_options &= ~FTS_PHYSICAL; |
169 | fts_options |= FTS_LOGICAL; |
170 | } |
171 | |
172 | myuid = getuid(); |
173 | |
174 | |
175 | myumask = umask(0); |
176 | (void)umask(myumask); |
177 | |
178 | |
179 | target = argv[--argc]; |
180 | if (strlcpy(to.p_path, target, sizeof to.p_path) >= sizeof(to.p_path)) |
| 10 | | Assuming the condition is false | |
|
| |
181 | errx(1, "%s: name too long", target); |
182 | to.p_end = to.p_path + strlen(to.p_path); |
183 | if (to.p_path == to.p_end) { |
| 12 | | Assuming field 'p_path' is not equal to field 'p_end' | |
|
| |
184 | *to.p_end++ = '.'; |
185 | *to.p_end = '\0'; |
186 | } |
187 | to.target_end = to.p_end; |
188 | |
189 | |
190 | argv[argc] = NULL; |
191 | |
192 | |
193 | |
194 | |
195 | |
196 | |
197 | |
198 | |
199 | |
200 | |
201 | |
202 | |
203 | |
204 | |
205 | |
206 | r = stat(to.p_path, &to_stat); |
207 | if (r == -1 && errno != ENOENT) |
| 14 | | Assuming the condition is false | |
|
208 | err(1, "%s", to.p_path); |
209 | if (r == -1 || !S_ISDIR(to_stat.st_mode)) { |
| 15 | | Assuming the condition is true | |
|
| |
210 | |
211 | |
212 | |
213 | if (argc > 1) |
214 | usage(); |
215 | |
216 | |
217 | |
218 | |
219 | |
220 | |
221 | |
222 | if (r == -1) { |
223 | if (rflag || (Rflag && (Lflag || Hflag))) |
224 | stat(*argv, &tmp_stat); |
225 | else |
226 | lstat(*argv, &tmp_stat); |
227 | |
228 | if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag)) |
229 | type = DIR_TO_DNE; |
230 | else |
231 | type = FILE_TO_FILE; |
232 | } else |
233 | type = FILE_TO_FILE; |
234 | } else { |
235 | |
236 | |
237 | |
238 | type = FILE_TO_DIR; |
239 | } |
240 | |
241 | return (copy(argv, type, fts_options)); |
| |
242 | } |
243 | |
244 | char * |
245 | find_last_component(char *path) |
246 | { |
247 | char *p; |
248 | |
249 | if ((p = strrchr(path, '/')) == NULL) |
250 | p = path; |
251 | else { |
252 | |
253 | if (!*(p+1)) { |
254 | while ((p >= path) && *p == '/') |
255 | p--; |
256 | |
257 | while ((p >= path) && *p != '/') |
258 | p--; |
259 | } |
260 | |
261 | p++; |
262 | } |
263 | |
264 | return (p); |
265 | } |
266 | |
267 | int |
268 | copy(char *argv[], enum op type, int fts_options) |
269 | { |
270 | struct stat to_stat; |
271 | FTS *ftsp; |
272 | FTSENT *curr; |
273 | int base, cval, nlen, rval; |
274 | char *p, *target_mid; |
275 | base = 0; |
276 | |
277 | if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL) |
| 18 | | Assuming the condition is false | |
|
| |
278 | err(1, NULL); |
279 | for (rval = 0; (curr = fts_read(ftsp)) != NULL;) { |
| 20 | | Assuming the condition is true | |
|
| 21 | | Loop condition is true. Entering loop body | |
|
280 | switch (curr->fts_info) { |
| 22 | | 'Default' branch taken. Execution continues on line 298 | |
|
281 | case FTS_NS: |
282 | case FTS_DNR: |
283 | case FTS_ERR: |
284 | warnx("%s: %s", |
285 | curr->fts_path, strerror(curr->fts_errno)); |
286 | rval = 1; |
287 | continue; |
288 | case FTS_DC: |
289 | warnx("%s: directory causes a cycle", curr->fts_path); |
290 | rval = 1; |
291 | continue; |
292 | } |
293 | |
294 | |
295 | |
296 | |
297 | |
298 | if (type != FILE_TO_FILE) { |
| |
299 | |
300 | |
301 | |
302 | |
303 | |
304 | |
305 | |
306 | |
307 | |
308 | |
309 | |
310 | |
311 | |
312 | |
313 | |
314 | |
315 | |
316 | |
317 | |
318 | if (curr->fts_level == FTS_ROOTLEVEL) { |
| 24 | | Assuming field 'fts_level' is equal to FTS_ROOTLEVEL | |
|
| |
319 | if (type != DIR_TO_DNE) { |
| |
320 | p = find_last_component(curr->fts_path); |
321 | base = p - curr->fts_path; |
322 | |
323 | if (!strcmp(&curr->fts_path[base], |
| 27 | | Assuming the condition is false | |
|
| |
324 | "..")) |
325 | base += 1; |
326 | } else |
327 | base = curr->fts_pathlen; |
328 | } |
329 | |
330 | p = &curr->fts_path[base]; |
331 | nlen = curr->fts_pathlen - base; |
332 | target_mid = to.target_end; |
333 | if (*p != '/' && target_mid[-1] != '/') |
| 29 | | Assuming the condition is true | |
|
| 30 | | The left operand of '!=' is a garbage value due to array index out of bounds |
|
334 | *target_mid++ = '/'; |
335 | *target_mid = '\0'; |
336 | if (target_mid - to.p_path + nlen >= PATH_MAX) { |
337 | warnx("%s%s: name too long (not copied)", |
338 | to.p_path, p); |
339 | rval = 1; |
340 | continue; |
341 | } |
342 | (void)strncat(target_mid, p, nlen); |
343 | to.p_end = target_mid + nlen; |
344 | *to.p_end = '\0'; |
345 | } |
346 | |
347 | |
348 | if (stat(to.p_path, &to_stat) == -1) { |
349 | if (curr->fts_info == FTS_DP) |
350 | continue; |
351 | |
352 | |
353 | |
354 | |
355 | |
356 | |
357 | |
358 | curr->fts_pointer = (void *)1; |
359 | } else { |
360 | |
361 | |
362 | |
363 | |
364 | |
365 | |
366 | |
367 | |
368 | if (curr->fts_info == FTS_DP) { |
369 | if (!S_ISDIR(to_stat.st_mode)) |
370 | continue; |
371 | |
372 | |
373 | |
374 | |
375 | |
376 | |
377 | if (pflag && setfile(curr->fts_statp, -1)) |
378 | rval = 1; |
379 | else if (fts_dne(curr)) |
380 | (void)chmod(to.p_path, |
381 | curr->fts_statp->st_mode); |
382 | continue; |
383 | } |
384 | if (to_stat.st_dev == curr->fts_statp->st_dev && |
385 | to_stat.st_ino == curr->fts_statp->st_ino) { |
386 | warnx("%s and %s are identical (not copied).", |
387 | to.p_path, curr->fts_path); |
388 | rval = 1; |
389 | if (S_ISDIR(curr->fts_statp->st_mode)) |
390 | (void)fts_set(ftsp, curr, FTS_SKIP); |
391 | continue; |
392 | } |
393 | if (!S_ISDIR(curr->fts_statp->st_mode) && |
394 | S_ISDIR(to_stat.st_mode)) { |
395 | warnx("cannot overwrite directory %s with non-directory %s", |
396 | to.p_path, curr->fts_path); |
397 | rval = 1; |
398 | continue; |
399 | } |
400 | } |
401 | |
402 | switch (curr->fts_statp->st_mode & S_IFMT) { |
403 | case S_IFLNK: |
404 | if ((cval = copy_link(curr, !fts_dne(curr))) == 1) |
405 | rval = 1; |
406 | if (!cval && vflag) |
407 | (void)fprintf(stdout, "%s -> %s\n", |
408 | curr->fts_path, to.p_path); |
409 | break; |
410 | case S_IFDIR: |
411 | if (!Rflag && !rflag) { |
412 | warnx("%s is a directory (not copied).", |
413 | curr->fts_path); |
414 | (void)fts_set(ftsp, curr, FTS_SKIP); |
415 | rval = 1; |
416 | break; |
417 | } |
418 | |
419 | |
420 | |
421 | |
422 | |
423 | |
424 | |
425 | |
426 | if (fts_dne(curr)) { |
427 | if (mkdir(to.p_path, |
428 | curr->fts_statp->st_mode | S_IRWXU) == -1) |
429 | err(1, "%s", to.p_path); |
430 | else if (vflag) |
431 | (void)fprintf(stdout, "%s -> %s\n", |
432 | curr->fts_path, to.p_path); |
433 | } else if (!S_ISDIR(to_stat.st_mode)) |
434 | errc(1, ENOTDIR, "%s", to.p_path); |
435 | break; |
436 | case S_IFBLK: |
437 | case S_IFCHR: |
438 | if (Rflag) { |
439 | if ((cval = copy_special(curr->fts_statp, |
440 | !fts_dne(curr))) == 1) |
441 | rval = 1; |
442 | } else |
443 | if ((cval = copy_file(curr, !fts_dne(curr))) == 1) |
444 | rval = 1; |
445 | if (!cval && vflag) |
446 | (void)fprintf(stdout, "%s -> %s\n", |
447 | curr->fts_path, to.p_path); |
448 | cval = 0; |
449 | break; |
450 | case S_IFIFO: |
451 | if (Rflag) { |
452 | if ((cval = copy_fifo(curr->fts_statp, |
453 | !fts_dne(curr))) == 1) |
454 | rval = 1; |
455 | } else |
456 | if ((cval = copy_file(curr, !fts_dne(curr))) == 1) |
457 | rval = 1; |
458 | if (!cval && vflag) |
459 | (void)fprintf(stdout, "%s -> %s\n", |
460 | curr->fts_path, to.p_path); |
461 | cval = 0; |
462 | break; |
463 | case S_IFSOCK: |
464 | warnc(EOPNOTSUPP, "%s", curr->fts_path); |
465 | break; |
466 | default: |
467 | if ((cval = copy_file(curr, !fts_dne(curr))) == 1) |
468 | rval = 1; |
469 | if (!cval && vflag) |
470 | (void)fprintf(stdout, "%s -> %s\n", |
471 | curr->fts_path, to.p_path); |
472 | cval = 0; |
473 | break; |
474 | } |
475 | } |
476 | if (errno) |
477 | err(1, "fts_read"); |
478 | (void)fts_close(ftsp); |
479 | return (rval); |
480 | } |