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 <getopt.h> 59 #include <limits.h> 60 #include <signal.h> 61 #include <stdbool.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <unistd.h> 66 67 #include "extern.h" 68 69 static char dot[] = "."; 70 71 #define END(buf) (buf + sizeof(buf)) 72 PATH_T to = { .dir = -1, .end = to.path }; 73 bool Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag; 74 static bool Hflag, Lflag, Pflag, Rflag, rflag, Sflag; 75 volatile sig_atomic_t info; 76 77 enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; 78 79 static int copy(char *[], enum op, int, struct stat *); 80 static void siginfo(int __unused); 81 82 enum { 83 SORT_OPT = CHAR_MAX, 84 }; 85 86 static const struct option long_opts[] = 87 { 88 { "archive", no_argument, NULL, 'a' }, 89 { "force", no_argument, NULL, 'f' }, 90 { "interactive", no_argument, NULL, 'i' }, 91 { "dereference", no_argument, NULL, 'L' }, 92 { "link", no_argument, NULL, 'l' }, 93 { "no-clobber", no_argument, NULL, 'n' }, 94 { "no-dereference", no_argument, NULL, 'P' }, 95 { "recursive", no_argument, NULL, 'R' }, 96 { "symbolic-link", no_argument, NULL, 's' }, 97 { "verbose", no_argument, NULL, 'v' }, 98 { "one-file-system", no_argument, NULL, 'x' }, 99 { "sort", no_argument, NULL, SORT_OPT }, 100 { 0 } 101 }; 102 103 int 104 main(int argc, char *argv[]) 105 { 106 struct stat to_stat, tmp_stat; 107 enum op type; 108 int ch, fts_options, r; 109 char *sep, *target; 110 bool have_trailing_slash = false; 111 112 fts_options = FTS_NOCHDIR | FTS_PHYSICAL; 113 while ((ch = getopt_long(argc, argv, "+HLPRafilNnprsvx", long_opts, 114 NULL)) != -1) 115 switch (ch) { 116 case 'H': 117 Hflag = true; 118 Lflag = Pflag = false; 119 break; 120 case 'L': 121 Lflag = true; 122 Hflag = Pflag = false; 123 break; 124 case 'P': 125 Pflag = true; 126 Hflag = Lflag = false; 127 break; 128 case 'R': 129 Rflag = true; 130 break; 131 case 'a': 132 pflag = true; 133 Rflag = true; 134 Pflag = true; 135 Hflag = Lflag = false; 136 break; 137 case 'f': 138 fflag = true; 139 iflag = nflag = false; 140 break; 141 case 'i': 142 iflag = true; 143 fflag = nflag = false; 144 break; 145 case 'l': 146 lflag = true; 147 break; 148 case 'N': 149 Nflag = true; 150 break; 151 case 'n': 152 nflag = true; 153 fflag = iflag = false; 154 break; 155 case 'p': 156 pflag = true; 157 break; 158 case 'r': 159 rflag = Lflag = true; 160 Hflag = Pflag = false; 161 break; 162 case 's': 163 sflag = true; 164 break; 165 case 'v': 166 vflag = true; 167 break; 168 case 'x': 169 fts_options |= FTS_XDEV; 170 break; 171 case SORT_OPT: 172 Sflag = true; 173 break; 174 default: 175 usage(); 176 } 177 argc -= optind; 178 argv += optind; 179 180 if (argc < 2) 181 usage(); 182 183 if (Rflag && rflag) 184 errx(1, "the -R and -r options may not be specified together"); 185 if (lflag && sflag) 186 errx(1, "the -l and -s options may not be specified together"); 187 if (rflag) 188 Rflag = true; 189 if (Rflag) { 190 if (Hflag) 191 fts_options |= FTS_COMFOLLOW; 192 if (Lflag) { 193 fts_options &= ~FTS_PHYSICAL; 194 fts_options |= FTS_LOGICAL; 195 } 196 } else if (!Pflag) { 197 fts_options &= ~FTS_PHYSICAL; 198 fts_options |= FTS_LOGICAL | FTS_COMFOLLOW; 199 } 200 (void)signal(SIGINFO, siginfo); 201 202 /* Save the target base in "to". */ 203 target = argv[--argc]; 204 if (*target == '\0') { 205 target = dot; 206 } else if ((sep = strrchr(target, '/')) != NULL && sep[1] == '\0') { 207 have_trailing_slash = true; 208 while (sep > target && *sep == '/') 209 sep--; 210 sep[1] = '\0'; 211 } 212 /* 213 * Copy target into to.base, leaving room for a possible separator 214 * which will be appended later in the non-FILE_TO_FILE cases. 215 */ 216 if (strlcpy(to.base, target, sizeof(to.base) - 1) >= 217 sizeof(to.base) - 1) 218 errc(1, ENAMETOOLONG, "%s", target); 219 220 /* Set end of argument list for fts(3). */ 221 argv[argc] = NULL; 222 223 /* 224 * Cp has two distinct cases: 225 * 226 * cp [-R] source target 227 * cp [-R] source1 ... sourceN directory 228 * 229 * In both cases, source can be either a file or a directory. 230 * 231 * In (1), the target becomes a copy of the source. That is, if the 232 * source is a file, the target will be a file, and likewise for 233 * directories. 234 * 235 * In (2), the real target is not directory, but "directory/source". 236 */ 237 r = stat(to.base, &to_stat); 238 if (r == -1 && errno != ENOENT) 239 err(1, "%s", target); 240 if (r == -1 || !S_ISDIR(to_stat.st_mode)) { 241 /* 242 * Case (1). Target is not a directory. 243 */ 244 if (argc > 1) 245 errc(1, ENOTDIR, "%s", target); 246 247 /* 248 * Need to detect the case: 249 * cp -R dir foo 250 * Where dir is a directory and foo does not exist, where 251 * we want pathname concatenations turned on but not for 252 * the initial mkdir(). 253 */ 254 if (r == -1) { 255 if (Rflag && (Lflag || Hflag)) 256 stat(*argv, &tmp_stat); 257 else 258 lstat(*argv, &tmp_stat); 259 260 if (S_ISDIR(tmp_stat.st_mode) && Rflag) 261 type = DIR_TO_DNE; 262 else 263 type = FILE_TO_FILE; 264 } else 265 type = FILE_TO_FILE; 266 267 if (have_trailing_slash && type == FILE_TO_FILE) { 268 if (r == -1) 269 errc(1, ENOENT, "%s", target); 270 else 271 errc(1, ENOTDIR, "%s", target); 272 } 273 } else { 274 /* 275 * Case (2). Target is a directory. 276 */ 277 type = FILE_TO_DIR; 278 } 279 280 /* 281 * For DIR_TO_DNE, we could provide copy() with the to_stat we've 282 * already allocated on the stack here that isn't being used for 283 * anything. Not doing so, though, simplifies later logic a little bit 284 * as we need to skip checking root_stat on the first iteration and 285 * ensure that we set it with the first mkdir(). 286 */ 287 exit (copy(argv, type, fts_options, (type == DIR_TO_DNE ? NULL : 288 &to_stat))); 289 } 290 291 static int 292 ftscmp(const FTSENT * const *a, const FTSENT * const *b) 293 { 294 return (strcmp((*a)->fts_name, (*b)->fts_name)); 295 } 296 297 static int 298 copy(char *argv[], enum op type, int fts_options, struct stat *root_stat) 299 { 300 char rootname[NAME_MAX]; 301 struct stat created_root_stat, to_stat, *curr_stat; 302 FTS *ftsp; 303 FTSENT *curr; 304 char *recpath = NULL, *sep; 305 int atflags, dne, badcp, len, level, rval; 306 mode_t mask, mode; 307 bool beneath = Rflag && type != FILE_TO_FILE; 308 309 /* 310 * Keep an inverted copy of the umask, for use in correcting 311 * permissions on created directories when not using -p. 312 */ 313 mask = ~umask(0777); 314 umask(~mask); 315 316 if (type == FILE_TO_FILE) { 317 to.dir = AT_FDCWD; 318 to.end = to.path + strlcpy(to.path, to.base, sizeof(to.path)); 319 to.base[0] = '\0'; 320 } else if (type == FILE_TO_DIR) { 321 to.dir = open(to.base, O_DIRECTORY | O_SEARCH); 322 if (to.dir < 0) 323 err(1, "%s", to.base); 324 /* 325 * We have previously made sure there is room for this. 326 */ 327 if (strcmp(to.base, "/") != 0) { 328 sep = strchr(to.base, '\0'); 329 sep[0] = '/'; 330 sep[1] = '\0'; 331 } 332 } else { 333 /* 334 * We will create the destination directory imminently. 335 */ 336 to.dir = -1; 337 } 338 339 level = FTS_ROOTLEVEL; 340 if ((ftsp = fts_open(argv, fts_options, Sflag ? ftscmp : NULL)) == NULL) 341 err(1, "fts_open"); 342 for (badcp = rval = 0; 343 (curr = fts_read(ftsp)) != NULL; 344 badcp = 0, *to.end = '\0') { 345 curr_stat = curr->fts_statp; 346 switch (curr->fts_info) { 347 case FTS_NS: 348 case FTS_DNR: 349 case FTS_ERR: 350 if (level > curr->fts_level) { 351 /* leaving a directory; remove its name from to.path */ 352 if (type == DIR_TO_DNE && 353 curr->fts_level == FTS_ROOTLEVEL) { 354 /* this is actually our created root */ 355 } else { 356 while (to.end > to.path && *to.end != '/') 357 to.end--; 358 assert(strcmp(to.end + (*to.end == '/'), 359 curr->fts_name) == 0); 360 *to.end = '\0'; 361 } 362 level--; 363 } 364 warnc(curr->fts_errno, "%s", curr->fts_path); 365 badcp = rval = 1; 366 continue; 367 case FTS_DC: /* Warn, continue. */ 368 warnx("%s: directory causes a cycle", curr->fts_path); 369 badcp = rval = 1; 370 continue; 371 case FTS_D: 372 /* 373 * Stash the root basename off for detecting 374 * recursion later. 375 * 376 * This will be essential if the root is a symlink 377 * and we're rolling with -L or -H. The later 378 * bits will need this bit in particular. 379 */ 380 if (curr->fts_level == FTS_ROOTLEVEL) { 381 strlcpy(rootname, curr->fts_name, 382 sizeof(rootname)); 383 } 384 /* we must have a destination! */ 385 if (type == DIR_TO_DNE && 386 curr->fts_level == FTS_ROOTLEVEL) { 387 assert(to.dir < 0); 388 assert(root_stat == NULL); 389 mode = curr_stat->st_mode | S_IRWXU; 390 /* 391 * Will our umask prevent us from entering 392 * the directory after we create it? 393 */ 394 if (~mask & S_IRWXU) 395 umask(~mask & ~S_IRWXU); 396 if (mkdir(to.base, mode) != 0) { 397 warn("%s", to.base); 398 fts_set(ftsp, curr, FTS_SKIP); 399 badcp = rval = 1; 400 if (~mask & S_IRWXU) 401 umask(~mask); 402 continue; 403 } 404 to.dir = open(to.base, O_DIRECTORY | O_SEARCH); 405 if (to.dir < 0) { 406 warn("%s", to.base); 407 (void)rmdir(to.base); 408 fts_set(ftsp, curr, FTS_SKIP); 409 badcp = rval = 1; 410 if (~mask & S_IRWXU) 411 umask(~mask); 412 continue; 413 } 414 if (fstat(to.dir, &created_root_stat) != 0) { 415 warn("%s", to.base); 416 (void)close(to.dir); 417 (void)rmdir(to.base); 418 fts_set(ftsp, curr, FTS_SKIP); 419 to.dir = -1; 420 badcp = rval = 1; 421 if (~mask & S_IRWXU) 422 umask(~mask); 423 continue; 424 } 425 if (~mask & S_IRWXU) 426 umask(~mask); 427 root_stat = &created_root_stat; 428 curr->fts_number = 1; 429 /* 430 * We have previously made sure there is 431 * room for this. 432 */ 433 sep = strchr(to.base, '\0'); 434 sep[0] = '/'; 435 sep[1] = '\0'; 436 } else if (strcmp(curr->fts_name, "/") == 0) { 437 /* special case when source is the root directory */ 438 } else { 439 /* entering a directory; append its name to to.path */ 440 len = snprintf(to.end, END(to.path) - to.end, "%s%s", 441 to.end > to.path ? "/" : "", curr->fts_name); 442 if (to.end + len >= END(to.path)) { 443 *to.end = '\0'; 444 warnc(ENAMETOOLONG, "%s%s%s%s", to.base, 445 to.path, to.end > to.path ? "/" : "", 446 curr->fts_name); 447 fts_set(ftsp, curr, FTS_SKIP); 448 badcp = rval = 1; 449 continue; 450 } 451 to.end += len; 452 } 453 level++; 454 /* 455 * We're on the verge of recursing on ourselves. 456 * Either we need to stop right here (we knowingly 457 * just created it), or we will in an immediate 458 * descendant. Record the path of the immediate 459 * descendant to make our lives a little less 460 * complicated looking. 461 */ 462 if (type != FILE_TO_FILE && 463 root_stat->st_dev == curr_stat->st_dev && 464 root_stat->st_ino == curr_stat->st_ino) { 465 assert(recpath == NULL); 466 if (root_stat == &created_root_stat) { 467 /* 468 * This directory didn't exist 469 * when we started, we created it 470 * as part of traversal. Stop 471 * right here before we do 472 * something silly. 473 */ 474 fts_set(ftsp, curr, FTS_SKIP); 475 continue; 476 } 477 if (asprintf(&recpath, "%s/%s", to.path, 478 rootname) < 0) { 479 warnc(ENOMEM, NULL); 480 fts_set(ftsp, curr, FTS_SKIP); 481 badcp = rval = 1; 482 continue; 483 } 484 } 485 if (recpath != NULL && 486 strcmp(recpath, to.path) == 0) { 487 fts_set(ftsp, curr, FTS_SKIP); 488 continue; 489 } 490 break; 491 case FTS_DP: 492 /* 493 * We are nearly finished with this directory. If we 494 * didn't actually copy it, or otherwise don't need to 495 * change its attributes, then we are done. 496 * 497 * If -p is in effect, set all the attributes. 498 * Otherwise, set the correct permissions, limited 499 * by the umask. Optimise by avoiding a chmod() 500 * if possible (which is usually the case if we 501 * made the directory). Note that mkdir() does not 502 * honour setuid, setgid and sticky bits, but we 503 * normally want to preserve them on directories. 504 */ 505 if (curr->fts_number && pflag) { 506 int fd = *to.path ? -1 : to.dir; 507 if (setfile(curr_stat, fd, true)) 508 rval = 1; 509 if (preserve_dir_acls(curr->fts_accpath, 510 to.path) != 0) 511 rval = 1; 512 } else if (curr->fts_number) { 513 const char *path = *to.path ? to.path : dot; 514 mode = curr_stat->st_mode; 515 if (fchmodat(to.dir, path, mode & mask, 0) != 0) { 516 warn("chmod: %s%s", to.base, to.path); 517 rval = 1; 518 } 519 } 520 if (level > curr->fts_level) { 521 /* leaving a directory; remove its name from to.path */ 522 if (type == DIR_TO_DNE && 523 curr->fts_level == FTS_ROOTLEVEL) { 524 /* this is actually our created root */ 525 } else if (strcmp(curr->fts_name, "/") == 0) { 526 /* special case when source is the root directory */ 527 } else { 528 while (to.end > to.path && *to.end != '/') 529 to.end--; 530 assert(strcmp(to.end + (*to.end == '/'), 531 curr->fts_name) == 0); 532 *to.end = '\0'; 533 } 534 level--; 535 } 536 continue; 537 default: 538 /* something else: append its name to to.path */ 539 if (type == FILE_TO_FILE) 540 break; 541 len = snprintf(to.end, END(to.path) - to.end, "%s%s", 542 to.end > to.path ? "/" : "", curr->fts_name); 543 if (to.end + len >= END(to.path)) { 544 *to.end = '\0'; 545 warnc(ENAMETOOLONG, "%s%s%s%s", to.base, 546 to.path, to.end > to.path ? "/" : "", 547 curr->fts_name); 548 badcp = rval = 1; 549 continue; 550 } 551 /* intentionally do not update to.end */ 552 break; 553 } 554 555 /* Not an error but need to remember it happened. */ 556 if (to.path[0] == '\0') { 557 /* 558 * This can happen in three cases: 559 * - The source path is the root directory. 560 * - DIR_TO_DNE; we created the directory and 561 * populated root_stat earlier. 562 * - FILE_TO_DIR if a source has a trailing slash; 563 * the caller populated root_stat. 564 */ 565 dne = false; 566 to_stat = *root_stat; 567 } else { 568 atflags = beneath ? AT_RESOLVE_BENEATH : 0; 569 if (curr->fts_info == FTS_D || curr->fts_info == FTS_SL) 570 atflags |= AT_SYMLINK_NOFOLLOW; 571 dne = fstatat(to.dir, to.path, &to_stat, atflags) != 0; 572 } 573 574 /* Check if source and destination are identical. */ 575 if (!dne && 576 to_stat.st_dev == curr_stat->st_dev && 577 to_stat.st_ino == curr_stat->st_ino) { 578 warnx("%s%s and %s are identical (not copied).", 579 to.base, to.path, curr->fts_path); 580 badcp = rval = 1; 581 if (S_ISDIR(curr_stat->st_mode)) 582 fts_set(ftsp, curr, FTS_SKIP); 583 continue; 584 } 585 586 switch (curr_stat->st_mode & S_IFMT) { 587 case S_IFLNK: 588 if ((fts_options & FTS_LOGICAL) || 589 ((fts_options & FTS_COMFOLLOW) && 590 curr->fts_level == 0)) { 591 /* 592 * We asked FTS to follow links but got 593 * here anyway, which means the target is 594 * nonexistent or inaccessible. Let 595 * copy_file() deal with the error. 596 */ 597 if (copy_file(curr, dne, beneath)) 598 badcp = rval = 1; 599 } else { 600 /* Copy the link. */ 601 if (copy_link(curr, dne, beneath)) 602 badcp = rval = 1; 603 } 604 break; 605 case S_IFDIR: 606 if (!Rflag) { 607 warnx("%s is a directory (not copied).", 608 curr->fts_path); 609 fts_set(ftsp, curr, FTS_SKIP); 610 badcp = rval = 1; 611 break; 612 } 613 /* 614 * If the directory doesn't exist, create the new 615 * one with the from file mode plus owner RWX bits, 616 * modified by the umask. Trade-off between being 617 * able to write the directory (if from directory is 618 * 555) and not causing a permissions race. If the 619 * umask blocks owner writes, we fail. 620 */ 621 if (dne) { 622 mode = curr_stat->st_mode | S_IRWXU; 623 /* 624 * Will our umask prevent us from entering 625 * the directory after we create it? 626 */ 627 if (~mask & S_IRWXU) 628 umask(~mask & ~S_IRWXU); 629 if (mkdirat(to.dir, to.path, mode) != 0) { 630 warn("%s%s", to.base, to.path); 631 fts_set(ftsp, curr, FTS_SKIP); 632 badcp = rval = 1; 633 if (~mask & S_IRWXU) 634 umask(~mask); 635 break; 636 } 637 if (~mask & S_IRWXU) 638 umask(~mask); 639 } else if (!S_ISDIR(to_stat.st_mode)) { 640 warnc(ENOTDIR, "%s%s", to.base, to.path); 641 fts_set(ftsp, curr, FTS_SKIP); 642 badcp = rval = 1; 643 break; 644 } 645 /* 646 * Arrange to correct directory attributes later 647 * (in the post-order phase) if this is a new 648 * directory, or if the -p flag is in effect. 649 * Note that fts_number may already be set if this 650 * is the newly created destination directory. 651 */ 652 curr->fts_number |= pflag || dne; 653 break; 654 case S_IFBLK: 655 case S_IFCHR: 656 if (Rflag && !sflag) { 657 if (copy_special(curr_stat, dne, beneath)) 658 badcp = rval = 1; 659 } else { 660 if (copy_file(curr, dne, beneath)) 661 badcp = rval = 1; 662 } 663 break; 664 case S_IFSOCK: 665 warnx("%s is a socket (not copied).", 666 curr->fts_path); 667 break; 668 case S_IFIFO: 669 if (Rflag && !sflag) { 670 if (copy_fifo(curr_stat, dne, beneath)) 671 badcp = rval = 1; 672 } else { 673 if (copy_file(curr, dne, beneath)) 674 badcp = rval = 1; 675 } 676 break; 677 default: 678 if (copy_file(curr, dne, beneath)) 679 badcp = rval = 1; 680 break; 681 } 682 if (vflag && !badcp) 683 (void)printf("%s -> %s%s\n", curr->fts_path, to.base, to.path); 684 } 685 assert(level == FTS_ROOTLEVEL); 686 if (errno) 687 err(1, "fts_read"); 688 (void)fts_close(ftsp); 689 if (to.dir != AT_FDCWD && to.dir >= 0) 690 (void)close(to.dir); 691 free(recpath); 692 return (rval); 693 } 694 695 static void 696 siginfo(int sig __unused) 697 { 698 699 info = 1; 700 } 701