1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1988, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * David Hitz of Auspex Systems Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 /*
36 * Cp copies source files to target files.
37 *
38 * The global PATH_T structure "to" always contains the path to the
39 * current target file. Since fts(3) does not change directories,
40 * this path can be either absolute or dot-relative.
41 *
42 * The basic algorithm is to initialize "to" and use fts(3) to traverse
43 * the file hierarchy rooted in the argument list. A trivial case is the
44 * case of 'cp file1 file2'. The more interesting case is the case of
45 * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the
46 * path (relative to the root of the traversal) is appended to dir (stored
47 * in "to") to form the final target path.
48 */
49
50 #include <sys/types.h>
51 #include <sys/stat.h>
52
53 #include <assert.h>
54 #include <err.h>
55 #include <errno.h>
56 #include <fcntl.h>
57 #include <fts.h>
58 #include <limits.h>
59 #include <signal.h>
60 #include <stdbool.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <unistd.h>
65
66 #include "extern.h"
67
68 static char dot[] = ".";
69
70 #define END(buf) (buf + sizeof(buf))
71 PATH_T to = { .dir = -1, .end = to.path };
72 int Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag;
73 static int Hflag, Lflag, Pflag, Rflag, rflag;
74 volatile sig_atomic_t info;
75
76 enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
77
78 static int copy(char *[], enum op, int, struct stat *);
79 static void siginfo(int __unused);
80
81 int
main(int argc,char * argv[])82 main(int argc, char *argv[])
83 {
84 struct stat to_stat, tmp_stat;
85 enum op type;
86 int ch, fts_options, r;
87 char *sep, *target;
88 bool have_trailing_slash = false;
89
90 fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
91 while ((ch = getopt(argc, argv, "HLPRafilNnprsvx")) != -1)
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 pflag = 1;
110 Rflag = 1;
111 Pflag = 1;
112 Hflag = Lflag = 0;
113 break;
114 case 'f':
115 fflag = 1;
116 iflag = nflag = 0;
117 break;
118 case 'i':
119 iflag = 1;
120 fflag = nflag = 0;
121 break;
122 case 'l':
123 lflag = 1;
124 break;
125 case 'N':
126 Nflag = 1;
127 break;
128 case 'n':
129 nflag = 1;
130 fflag = iflag = 0;
131 break;
132 case 'p':
133 pflag = 1;
134 break;
135 case 'r':
136 rflag = Lflag = 1;
137 Hflag = Pflag = 0;
138 break;
139 case 's':
140 sflag = 1;
141 break;
142 case 'v':
143 vflag = 1;
144 break;
145 case 'x':
146 fts_options |= FTS_XDEV;
147 break;
148 default:
149 usage();
150 }
151 argc -= optind;
152 argv += optind;
153
154 if (argc < 2)
155 usage();
156
157 if (Rflag && rflag)
158 errx(1, "the -R and -r options may not be specified together");
159 if (lflag && sflag)
160 errx(1, "the -l and -s options may not be specified together");
161 if (rflag)
162 Rflag = 1;
163 if (Rflag) {
164 if (Hflag)
165 fts_options |= FTS_COMFOLLOW;
166 if (Lflag) {
167 fts_options &= ~FTS_PHYSICAL;
168 fts_options |= FTS_LOGICAL;
169 }
170 } else if (!Pflag) {
171 fts_options &= ~FTS_PHYSICAL;
172 fts_options |= FTS_LOGICAL | FTS_COMFOLLOW;
173 }
174 (void)signal(SIGINFO, siginfo);
175
176 /* Save the target base in "to". */
177 target = argv[--argc];
178 if (*target == '\0') {
179 target = dot;
180 } else if ((sep = strrchr(target, '/')) != NULL && sep[1] == '\0') {
181 have_trailing_slash = true;
182 while (sep > target && *sep == '/')
183 sep--;
184 sep[1] = '\0';
185 }
186 /*
187 * Copy target into to.base, leaving room for a possible separator
188 * which will be appended later in the non-FILE_TO_FILE cases.
189 */
190 if (strlcpy(to.base, target, sizeof(to.base) - 1) >=
191 sizeof(to.base) - 1)
192 errc(1, ENAMETOOLONG, "%s", target);
193
194 /* Set end of argument list for fts(3). */
195 argv[argc] = NULL;
196
197 /*
198 * Cp has two distinct cases:
199 *
200 * cp [-R] source target
201 * cp [-R] source1 ... sourceN directory
202 *
203 * In both cases, source can be either a file or a directory.
204 *
205 * In (1), the target becomes a copy of the source. That is, if the
206 * source is a file, the target will be a file, and likewise for
207 * directories.
208 *
209 * In (2), the real target is not directory, but "directory/source".
210 */
211 r = stat(to.base, &to_stat);
212 if (r == -1 && errno != ENOENT)
213 err(1, "%s", target);
214 if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
215 /*
216 * Case (1). Target is not a directory.
217 */
218 if (argc > 1)
219 errc(1, ENOTDIR, "%s", target);
220
221 /*
222 * Need to detect the case:
223 * cp -R dir foo
224 * Where dir is a directory and foo does not exist, where
225 * we want pathname concatenations turned on but not for
226 * the initial mkdir().
227 */
228 if (r == -1) {
229 if (Rflag && (Lflag || Hflag))
230 stat(*argv, &tmp_stat);
231 else
232 lstat(*argv, &tmp_stat);
233
234 if (S_ISDIR(tmp_stat.st_mode) && Rflag)
235 type = DIR_TO_DNE;
236 else
237 type = FILE_TO_FILE;
238 } else
239 type = FILE_TO_FILE;
240
241 if (have_trailing_slash && type == FILE_TO_FILE) {
242 if (r == -1)
243 errc(1, ENOENT, "%s", target);
244 else
245 errc(1, ENOTDIR, "%s", target);
246 }
247 } else {
248 /*
249 * Case (2). Target is a directory.
250 */
251 type = FILE_TO_DIR;
252 }
253
254 /*
255 * For DIR_TO_DNE, we could provide copy() with the to_stat we've
256 * already allocated on the stack here that isn't being used for
257 * anything. Not doing so, though, simplifies later logic a little bit
258 * as we need to skip checking root_stat on the first iteration and
259 * ensure that we set it with the first mkdir().
260 */
261 exit (copy(argv, type, fts_options, (type == DIR_TO_DNE ? NULL :
262 &to_stat)));
263 }
264
265 static int
copy(char * argv[],enum op type,int fts_options,struct stat * root_stat)266 copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
267 {
268 char rootname[NAME_MAX];
269 struct stat created_root_stat, to_stat, *curr_stat;
270 FTS *ftsp;
271 FTSENT *curr;
272 char *recpath = NULL, *sep;
273 int atflags, dne, badcp, len, level, rval;
274 mode_t mask, mode;
275 bool beneath = Rflag && type != FILE_TO_FILE;
276
277 /*
278 * Keep an inverted copy of the umask, for use in correcting
279 * permissions on created directories when not using -p.
280 */
281 mask = ~umask(0777);
282 umask(~mask);
283
284 if (type == FILE_TO_FILE) {
285 to.dir = AT_FDCWD;
286 to.end = to.path + strlcpy(to.path, to.base, sizeof(to.path));
287 to.base[0] = '\0';
288 } else if (type == FILE_TO_DIR) {
289 to.dir = open(to.base, O_DIRECTORY | O_SEARCH);
290 if (to.dir < 0)
291 err(1, "%s", to.base);
292 /*
293 * We have previously made sure there is room for this.
294 */
295 if (strcmp(to.base, "/") != 0) {
296 sep = strchr(to.base, '\0');
297 sep[0] = '/';
298 sep[1] = '\0';
299 }
300 } else {
301 /*
302 * We will create the destination directory imminently.
303 */
304 to.dir = -1;
305 }
306
307 level = FTS_ROOTLEVEL;
308 if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL)
309 err(1, "fts_open");
310 for (badcp = rval = 0;
311 (curr = fts_read(ftsp)) != NULL;
312 badcp = 0, *to.end = '\0') {
313 curr_stat = curr->fts_statp;
314 switch (curr->fts_info) {
315 case FTS_NS:
316 case FTS_DNR:
317 case FTS_ERR:
318 if (level > curr->fts_level) {
319 /* leaving a directory; remove its name from to.path */
320 if (type == DIR_TO_DNE &&
321 curr->fts_level == FTS_ROOTLEVEL) {
322 /* this is actually our created root */
323 } else {
324 while (to.end > to.path && *to.end != '/')
325 to.end--;
326 assert(strcmp(to.end + (*to.end == '/'),
327 curr->fts_name) == 0);
328 *to.end = '\0';
329 }
330 level--;
331 }
332 warnc(curr->fts_errno, "%s", curr->fts_path);
333 badcp = rval = 1;
334 continue;
335 case FTS_DC: /* Warn, continue. */
336 warnx("%s: directory causes a cycle", curr->fts_path);
337 badcp = rval = 1;
338 continue;
339 case FTS_D:
340 /*
341 * Stash the root basename off for detecting
342 * recursion later.
343 *
344 * This will be essential if the root is a symlink
345 * and we're rolling with -L or -H. The later
346 * bits will need this bit in particular.
347 */
348 if (curr->fts_level == FTS_ROOTLEVEL) {
349 strlcpy(rootname, curr->fts_name,
350 sizeof(rootname));
351 }
352 /* we must have a destination! */
353 if (type == DIR_TO_DNE &&
354 curr->fts_level == FTS_ROOTLEVEL) {
355 assert(to.dir < 0);
356 assert(root_stat == NULL);
357 mode = curr_stat->st_mode | S_IRWXU;
358 /*
359 * Will our umask prevent us from entering
360 * the directory after we create it?
361 */
362 if (~mask & S_IRWXU)
363 umask(~mask & ~S_IRWXU);
364 if (mkdir(to.base, mode) != 0) {
365 warn("%s", to.base);
366 fts_set(ftsp, curr, FTS_SKIP);
367 badcp = rval = 1;
368 if (~mask & S_IRWXU)
369 umask(~mask);
370 continue;
371 }
372 to.dir = open(to.base, O_DIRECTORY | O_SEARCH);
373 if (to.dir < 0) {
374 warn("%s", to.base);
375 (void)rmdir(to.base);
376 fts_set(ftsp, curr, FTS_SKIP);
377 badcp = rval = 1;
378 if (~mask & S_IRWXU)
379 umask(~mask);
380 continue;
381 }
382 if (fstat(to.dir, &created_root_stat) != 0) {
383 warn("%s", to.base);
384 (void)close(to.dir);
385 (void)rmdir(to.base);
386 fts_set(ftsp, curr, FTS_SKIP);
387 to.dir = -1;
388 badcp = rval = 1;
389 if (~mask & S_IRWXU)
390 umask(~mask);
391 continue;
392 }
393 if (~mask & S_IRWXU)
394 umask(~mask);
395 root_stat = &created_root_stat;
396 curr->fts_number = 1;
397 /*
398 * We have previously made sure there is
399 * room for this.
400 */
401 sep = strchr(to.base, '\0');
402 sep[0] = '/';
403 sep[1] = '\0';
404 } else {
405 /* entering a directory; append its name to to.path */
406 len = snprintf(to.end, END(to.path) - to.end, "%s%s",
407 to.end > to.path ? "/" : "", curr->fts_name);
408 if (to.end + len >= END(to.path)) {
409 *to.end = '\0';
410 warnc(ENAMETOOLONG, "%s%s%s%s", to.base,
411 to.path, to.end > to.path ? "/" : "",
412 curr->fts_name);
413 fts_set(ftsp, curr, FTS_SKIP);
414 badcp = rval = 1;
415 continue;
416 }
417 to.end += len;
418 }
419 level++;
420 /*
421 * We're on the verge of recursing on ourselves.
422 * Either we need to stop right here (we knowingly
423 * just created it), or we will in an immediate
424 * descendant. Record the path of the immediate
425 * descendant to make our lives a little less
426 * complicated looking.
427 */
428 if (type != FILE_TO_FILE &&
429 root_stat->st_dev == curr_stat->st_dev &&
430 root_stat->st_ino == curr_stat->st_ino) {
431 assert(recpath == NULL);
432 if (root_stat == &created_root_stat) {
433 /*
434 * This directory didn't exist
435 * when we started, we created it
436 * as part of traversal. Stop
437 * right here before we do
438 * something silly.
439 */
440 fts_set(ftsp, curr, FTS_SKIP);
441 continue;
442 }
443 if (asprintf(&recpath, "%s/%s", to.path,
444 rootname) < 0) {
445 warnc(ENOMEM, NULL);
446 fts_set(ftsp, curr, FTS_SKIP);
447 badcp = rval = 1;
448 continue;
449 }
450 }
451 if (recpath != NULL &&
452 strcmp(recpath, to.path) == 0) {
453 fts_set(ftsp, curr, FTS_SKIP);
454 continue;
455 }
456 break;
457 case FTS_DP:
458 /*
459 * We are nearly finished with this directory. If we
460 * didn't actually copy it, or otherwise don't need to
461 * change its attributes, then we are done.
462 *
463 * If -p is in effect, set all the attributes.
464 * Otherwise, set the correct permissions, limited
465 * by the umask. Optimise by avoiding a chmod()
466 * if possible (which is usually the case if we
467 * made the directory). Note that mkdir() does not
468 * honour setuid, setgid and sticky bits, but we
469 * normally want to preserve them on directories.
470 */
471 if (curr->fts_number && pflag) {
472 int fd = *to.path ? -1 : to.dir;
473 if (setfile(curr_stat, fd, true))
474 rval = 1;
475 if (preserve_dir_acls(curr->fts_accpath,
476 to.path) != 0)
477 rval = 1;
478 } else if (curr->fts_number) {
479 const char *path = *to.path ? to.path : dot;
480 mode = curr_stat->st_mode;
481 if (fchmodat(to.dir, path, mode & mask, 0) != 0) {
482 warn("chmod: %s%s", to.base, to.path);
483 rval = 1;
484 }
485 }
486 if (level > curr->fts_level) {
487 /* leaving a directory; remove its name from to.path */
488 if (type == DIR_TO_DNE &&
489 curr->fts_level == FTS_ROOTLEVEL) {
490 /* this is actually our created root */
491 } else {
492 while (to.end > to.path && *to.end != '/')
493 to.end--;
494 assert(strcmp(to.end + (*to.end == '/'),
495 curr->fts_name) == 0);
496 *to.end = '\0';
497 }
498 level--;
499 }
500 continue;
501 default:
502 /* something else: append its name to to.path */
503 if (type == FILE_TO_FILE)
504 break;
505 len = snprintf(to.end, END(to.path) - to.end, "%s%s",
506 to.end > to.path ? "/" : "", curr->fts_name);
507 if (to.end + len >= END(to.path)) {
508 *to.end = '\0';
509 warnc(ENAMETOOLONG, "%s%s%s%s", to.base,
510 to.path, to.end > to.path ? "/" : "",
511 curr->fts_name);
512 badcp = rval = 1;
513 continue;
514 }
515 /* intentionally do not update to.end */
516 break;
517 }
518
519 /* Not an error but need to remember it happened. */
520 if (to.path[0] == '\0') {
521 /*
522 * This can happen in two cases:
523 * - DIR_TO_DNE; we created the directory and
524 * populated root_stat earlier.
525 * - FILE_TO_DIR if a source has a trailing slash;
526 * the caller populated root_stat.
527 */
528 dne = false;
529 to_stat = *root_stat;
530 } else {
531 atflags = beneath ? AT_RESOLVE_BENEATH : 0;
532 if (curr->fts_info == FTS_D || curr->fts_info == FTS_SL)
533 atflags |= AT_SYMLINK_NOFOLLOW;
534 dne = fstatat(to.dir, to.path, &to_stat, atflags) != 0;
535 }
536
537 /* Check if source and destination are identical. */
538 if (!dne &&
539 to_stat.st_dev == curr_stat->st_dev &&
540 to_stat.st_ino == curr_stat->st_ino) {
541 warnx("%s%s and %s are identical (not copied).",
542 to.base, to.path, curr->fts_path);
543 badcp = rval = 1;
544 if (S_ISDIR(curr_stat->st_mode))
545 fts_set(ftsp, curr, FTS_SKIP);
546 continue;
547 }
548
549 switch (curr_stat->st_mode & S_IFMT) {
550 case S_IFLNK:
551 if ((fts_options & FTS_LOGICAL) ||
552 ((fts_options & FTS_COMFOLLOW) &&
553 curr->fts_level == 0)) {
554 /*
555 * We asked FTS to follow links but got
556 * here anyway, which means the target is
557 * nonexistent or inaccessible. Let
558 * copy_file() deal with the error.
559 */
560 if (copy_file(curr, dne, beneath))
561 badcp = rval = 1;
562 } else {
563 /* Copy the link. */
564 if (copy_link(curr, dne, beneath))
565 badcp = rval = 1;
566 }
567 break;
568 case S_IFDIR:
569 if (!Rflag) {
570 warnx("%s is a directory (not copied).",
571 curr->fts_path);
572 fts_set(ftsp, curr, FTS_SKIP);
573 badcp = rval = 1;
574 break;
575 }
576 /*
577 * If the directory doesn't exist, create the new
578 * one with the from file mode plus owner RWX bits,
579 * modified by the umask. Trade-off between being
580 * able to write the directory (if from directory is
581 * 555) and not causing a permissions race. If the
582 * umask blocks owner writes, we fail.
583 */
584 if (dne) {
585 mode = curr_stat->st_mode | S_IRWXU;
586 /*
587 * Will our umask prevent us from entering
588 * the directory after we create it?
589 */
590 if (~mask & S_IRWXU)
591 umask(~mask & ~S_IRWXU);
592 if (mkdirat(to.dir, to.path, mode) != 0) {
593 warn("%s%s", to.base, to.path);
594 fts_set(ftsp, curr, FTS_SKIP);
595 badcp = rval = 1;
596 if (~mask & S_IRWXU)
597 umask(~mask);
598 break;
599 }
600 if (~mask & S_IRWXU)
601 umask(~mask);
602 } else if (!S_ISDIR(to_stat.st_mode)) {
603 warnc(ENOTDIR, "%s%s", to.base, to.path);
604 fts_set(ftsp, curr, FTS_SKIP);
605 badcp = rval = 1;
606 break;
607 }
608 /*
609 * Arrange to correct directory attributes later
610 * (in the post-order phase) if this is a new
611 * directory, or if the -p flag is in effect.
612 * Note that fts_number may already be set if this
613 * is the newly created destination directory.
614 */
615 curr->fts_number |= pflag || dne;
616 break;
617 case S_IFBLK:
618 case S_IFCHR:
619 if (Rflag && !sflag) {
620 if (copy_special(curr_stat, dne, beneath))
621 badcp = rval = 1;
622 } else {
623 if (copy_file(curr, dne, beneath))
624 badcp = rval = 1;
625 }
626 break;
627 case S_IFSOCK:
628 warnx("%s is a socket (not copied).",
629 curr->fts_path);
630 break;
631 case S_IFIFO:
632 if (Rflag && !sflag) {
633 if (copy_fifo(curr_stat, dne, beneath))
634 badcp = rval = 1;
635 } else {
636 if (copy_file(curr, dne, beneath))
637 badcp = rval = 1;
638 }
639 break;
640 default:
641 if (copy_file(curr, dne, beneath))
642 badcp = rval = 1;
643 break;
644 }
645 if (vflag && !badcp)
646 (void)printf("%s -> %s%s\n", curr->fts_path, to.base, to.path);
647 }
648 assert(level == FTS_ROOTLEVEL);
649 if (errno)
650 err(1, "fts_read");
651 (void)fts_close(ftsp);
652 if (to.dir != AT_FDCWD && to.dir >= 0)
653 (void)close(to.dir);
654 free(recpath);
655 return (rval);
656 }
657
658 static void
siginfo(int sig __unused)659 siginfo(int sig __unused)
660 {
661
662 info = 1;
663 }
664