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 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 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, rval; 274 mode_t mask, mode; 275 bool beneath = Rflag && type != FILE_TO_FILE; 276 bool skipdp = false; 277 278 /* 279 * Keep an inverted copy of the umask, for use in correcting 280 * permissions on created directories when not using -p. 281 */ 282 mask = ~umask(0777); 283 umask(~mask); 284 285 if (type == FILE_TO_FILE) { 286 to.dir = AT_FDCWD; 287 to.end = to.path + strlcpy(to.path, to.base, sizeof(to.path)); 288 to.base[0] = '\0'; 289 } else if (type == FILE_TO_DIR) { 290 to.dir = open(to.base, O_DIRECTORY | O_SEARCH); 291 if (to.dir < 0) 292 err(1, "%s", to.base); 293 /* 294 * We have previously made sure there is room for this. 295 */ 296 if (strcmp(to.base, "/") != 0) { 297 sep = strchr(to.base, '\0'); 298 sep[0] = '/'; 299 sep[1] = '\0'; 300 } 301 } else { 302 /* 303 * We will create the destination directory imminently. 304 */ 305 to.dir = -1; 306 } 307 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 warnc(curr->fts_errno, "%s", curr->fts_path); 319 badcp = rval = 1; 320 continue; 321 case FTS_DC: /* Warn, continue. */ 322 warnx("%s: directory causes a cycle", curr->fts_path); 323 badcp = rval = 1; 324 continue; 325 case FTS_D: 326 /* 327 * Stash the root basename off for detecting 328 * recursion later. 329 * 330 * This will be essential if the root is a symlink 331 * and we're rolling with -L or -H. The later 332 * bits will need this bit in particular. 333 */ 334 if (curr->fts_level == FTS_ROOTLEVEL) { 335 strlcpy(rootname, curr->fts_name, 336 sizeof(rootname)); 337 } 338 /* 339 * If we FTS_SKIP while handling FTS_D, we will 340 * immediately get FTS_DP for the same directory. 341 * If this happens before we've appended the name 342 * to to.path, we need to remember not to perform 343 * the reverse operation. 344 */ 345 skipdp = true; 346 /* we must have a destination! */ 347 if (type == DIR_TO_DNE && 348 curr->fts_level == FTS_ROOTLEVEL) { 349 assert(to.dir < 0); 350 assert(root_stat == NULL); 351 mode = curr_stat->st_mode | S_IRWXU; 352 /* 353 * Will our umask prevent us from entering 354 * the directory after we create it? 355 */ 356 if (~mask & S_IRWXU) 357 umask(~mask & ~S_IRWXU); 358 if (mkdir(to.base, mode) != 0) { 359 warn("%s", to.base); 360 fts_set(ftsp, curr, FTS_SKIP); 361 badcp = rval = 1; 362 if (~mask & S_IRWXU) 363 umask(~mask); 364 continue; 365 } 366 to.dir = open(to.base, O_DIRECTORY | O_SEARCH); 367 if (to.dir < 0) { 368 warn("%s", to.base); 369 (void)rmdir(to.base); 370 fts_set(ftsp, curr, FTS_SKIP); 371 badcp = rval = 1; 372 if (~mask & S_IRWXU) 373 umask(~mask); 374 continue; 375 } 376 if (fstat(to.dir, &created_root_stat) != 0) { 377 warn("%s", to.base); 378 (void)close(to.dir); 379 (void)rmdir(to.base); 380 fts_set(ftsp, curr, FTS_SKIP); 381 to.dir = -1; 382 badcp = rval = 1; 383 if (~mask & S_IRWXU) 384 umask(~mask); 385 continue; 386 } 387 if (~mask & S_IRWXU) 388 umask(~mask); 389 root_stat = &created_root_stat; 390 curr->fts_number = 1; 391 /* 392 * We have previously made sure there is 393 * room for this. 394 */ 395 sep = strchr(to.base, '\0'); 396 sep[0] = '/'; 397 sep[1] = '\0'; 398 } else { 399 /* entering a directory; append its name to to.path */ 400 len = snprintf(to.end, END(to.path) - to.end, "%s%s", 401 to.end > to.path ? "/" : "", curr->fts_name); 402 if (to.end + len >= END(to.path)) { 403 *to.end = '\0'; 404 warnc(ENAMETOOLONG, "%s%s%s%s", to.base, 405 to.path, to.end > to.path ? "/" : "", 406 curr->fts_name); 407 fts_set(ftsp, curr, FTS_SKIP); 408 badcp = rval = 1; 409 continue; 410 } 411 to.end += len; 412 } 413 skipdp = false; 414 /* 415 * We're on the verge of recursing on ourselves. 416 * Either we need to stop right here (we knowingly 417 * just created it), or we will in an immediate 418 * descendant. Record the path of the immediate 419 * descendant to make our lives a little less 420 * complicated looking. 421 */ 422 if (type != FILE_TO_FILE && 423 root_stat->st_dev == curr_stat->st_dev && 424 root_stat->st_ino == curr_stat->st_ino) { 425 assert(recpath == NULL); 426 if (root_stat == &created_root_stat) { 427 /* 428 * This directory didn't exist 429 * when we started, we created it 430 * as part of traversal. Stop 431 * right here before we do 432 * something silly. 433 */ 434 fts_set(ftsp, curr, FTS_SKIP); 435 continue; 436 } 437 if (asprintf(&recpath, "%s/%s", to.path, 438 rootname) < 0) { 439 warnc(ENOMEM, NULL); 440 fts_set(ftsp, curr, FTS_SKIP); 441 badcp = rval = 1; 442 continue; 443 } 444 } 445 if (recpath != NULL && 446 strcmp(recpath, to.path) == 0) { 447 fts_set(ftsp, curr, FTS_SKIP); 448 continue; 449 } 450 break; 451 case FTS_DP: 452 /* 453 * We are nearly finished with this directory. If we 454 * didn't actually copy it, or otherwise don't need to 455 * change its attributes, then we are done. 456 * 457 * If -p is in effect, set all the attributes. 458 * Otherwise, set the correct permissions, limited 459 * by the umask. Optimise by avoiding a chmod() 460 * if possible (which is usually the case if we 461 * made the directory). Note that mkdir() does not 462 * honour setuid, setgid and sticky bits, but we 463 * normally want to preserve them on directories. 464 */ 465 if (curr->fts_number && pflag) { 466 int fd = *to.path ? -1 : to.dir; 467 if (setfile(curr_stat, fd, true)) 468 rval = 1; 469 if (preserve_dir_acls(curr->fts_accpath, 470 to.path) != 0) 471 rval = 1; 472 } else if (curr->fts_number) { 473 const char *path = *to.path ? to.path : dot; 474 mode = curr_stat->st_mode; 475 if (fchmodat(to.dir, path, mode & mask, 0) != 0) { 476 warn("chmod: %s%s", to.base, to.path); 477 rval = 1; 478 } 479 } 480 /* are we leaving a directory we failed to enter? */ 481 if (skipdp) 482 continue; 483 /* leaving a directory; remove its name from to.path */ 484 if (type == DIR_TO_DNE && 485 curr->fts_level == FTS_ROOTLEVEL) { 486 /* this is actually our created root */ 487 } else { 488 while (to.end > to.path && *to.end != '/') 489 to.end--; 490 assert(strcmp(to.end + (*to.end == '/'), curr->fts_name) == 0); 491 *to.end = '\0'; 492 } 493 continue; 494 default: 495 /* something else: append its name to to.path */ 496 if (type == FILE_TO_FILE) 497 break; 498 len = snprintf(to.end, END(to.path) - to.end, "%s%s", 499 to.end > to.path ? "/" : "", curr->fts_name); 500 if (to.end + len >= END(to.path)) { 501 *to.end = '\0'; 502 warnc(ENAMETOOLONG, "%s%s%s%s", to.base, 503 to.path, to.end > to.path ? "/" : "", 504 curr->fts_name); 505 badcp = rval = 1; 506 continue; 507 } 508 /* intentionally do not update to.end */ 509 break; 510 } 511 512 /* Not an error but need to remember it happened. */ 513 if (to.path[0] == '\0') { 514 /* 515 * This can happen in two cases: 516 * - DIR_TO_DNE; we created the directory and 517 * populated root_stat earlier. 518 * - FILE_TO_DIR if a source has a trailing slash; 519 * the caller populated root_stat. 520 */ 521 dne = false; 522 to_stat = *root_stat; 523 } else { 524 atflags = beneath ? AT_RESOLVE_BENEATH : 0; 525 if (curr->fts_info == FTS_D || curr->fts_info == FTS_SL) 526 atflags |= AT_SYMLINK_NOFOLLOW; 527 dne = fstatat(to.dir, to.path, &to_stat, atflags) != 0; 528 } 529 530 /* Check if source and destination are identical. */ 531 if (!dne && 532 to_stat.st_dev == curr_stat->st_dev && 533 to_stat.st_ino == curr_stat->st_ino) { 534 warnx("%s%s and %s are identical (not copied).", 535 to.base, to.path, curr->fts_path); 536 badcp = rval = 1; 537 if (S_ISDIR(curr_stat->st_mode)) 538 fts_set(ftsp, curr, FTS_SKIP); 539 continue; 540 } 541 542 switch (curr_stat->st_mode & S_IFMT) { 543 case S_IFLNK: 544 if ((fts_options & FTS_LOGICAL) || 545 ((fts_options & FTS_COMFOLLOW) && 546 curr->fts_level == 0)) { 547 /* 548 * We asked FTS to follow links but got 549 * here anyway, which means the target is 550 * nonexistent or inaccessible. Let 551 * copy_file() deal with the error. 552 */ 553 if (copy_file(curr, dne, beneath)) 554 badcp = rval = 1; 555 } else { 556 /* Copy the link. */ 557 if (copy_link(curr, dne, beneath)) 558 badcp = rval = 1; 559 } 560 break; 561 case S_IFDIR: 562 if (!Rflag) { 563 warnx("%s is a directory (not copied).", 564 curr->fts_path); 565 fts_set(ftsp, curr, FTS_SKIP); 566 badcp = rval = 1; 567 break; 568 } 569 /* 570 * If the directory doesn't exist, create the new 571 * one with the from file mode plus owner RWX bits, 572 * modified by the umask. Trade-off between being 573 * able to write the directory (if from directory is 574 * 555) and not causing a permissions race. If the 575 * umask blocks owner writes, we fail. 576 */ 577 if (dne) { 578 mode = curr_stat->st_mode | S_IRWXU; 579 /* 580 * Will our umask prevent us from entering 581 * the directory after we create it? 582 */ 583 if (~mask & S_IRWXU) 584 umask(~mask & ~S_IRWXU); 585 if (mkdirat(to.dir, to.path, mode) != 0) { 586 warn("%s%s", to.base, to.path); 587 fts_set(ftsp, curr, FTS_SKIP); 588 badcp = rval = 1; 589 if (~mask & S_IRWXU) 590 umask(~mask); 591 break; 592 } 593 if (~mask & S_IRWXU) 594 umask(~mask); 595 } else if (!S_ISDIR(to_stat.st_mode)) { 596 warnc(ENOTDIR, "%s%s", to.base, to.path); 597 fts_set(ftsp, curr, FTS_SKIP); 598 badcp = rval = 1; 599 break; 600 } 601 /* 602 * Arrange to correct directory attributes later 603 * (in the post-order phase) if this is a new 604 * directory, or if the -p flag is in effect. 605 * Note that fts_number may already be set if this 606 * is the newly created destination directory. 607 */ 608 curr->fts_number |= pflag || dne; 609 break; 610 case S_IFBLK: 611 case S_IFCHR: 612 if (Rflag && !sflag) { 613 if (copy_special(curr_stat, dne, beneath)) 614 badcp = rval = 1; 615 } else { 616 if (copy_file(curr, dne, beneath)) 617 badcp = rval = 1; 618 } 619 break; 620 case S_IFSOCK: 621 warnx("%s is a socket (not copied).", 622 curr->fts_path); 623 break; 624 case S_IFIFO: 625 if (Rflag && !sflag) { 626 if (copy_fifo(curr_stat, dne, beneath)) 627 badcp = rval = 1; 628 } else { 629 if (copy_file(curr, dne, beneath)) 630 badcp = rval = 1; 631 } 632 break; 633 default: 634 if (copy_file(curr, dne, beneath)) 635 badcp = rval = 1; 636 break; 637 } 638 if (vflag && !badcp) 639 (void)printf("%s -> %s%s\n", curr->fts_path, to.base, to.path); 640 } 641 if (errno) 642 err(1, "fts_read"); 643 (void)fts_close(ftsp); 644 if (to.dir != AT_FDCWD && to.dir >= 0) 645 (void)close(to.dir); 646 free(recpath); 647 return (rval); 648 } 649 650 static void 651 siginfo(int sig __unused) 652 { 653 654 info = 1; 655 } 656