1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 /* 27 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 32 /* All Rights Reserved */ 33 34 /* 35 * Copyright (c) 2018, Joyent, Inc. 36 * Copyright 2026 Oxide Computer Company 37 */ 38 39 /* 40 * University Copyright- Copyright (c) 1982, 1986, 1988 41 * The Regents of the University of California 42 * All Rights Reserved 43 * 44 * University Acknowledgment- Portions of this document are derived from 45 * software developed by the University of California, Berkeley, and its 46 * contributors. 47 */ 48 49 /* 50 * This command implements all three of mv(1), cp(1), and ln(1) which all have 51 * similar operating modes. In particular, some invocations of mv must fall back 52 * to acting like cp when crossing file systems for example. 53 * 54 * These commands have the following high level synopsis: 55 * 56 * <command> [options] source target 57 * <command> [options] source source... directory 58 * <command> [options] source [target] 59 * 60 * By default, whenever one has a target that is a directory, these commands 61 * will place the resulting object inside of directory. So say you had a file 62 * 'a' and a directory 'b' and ran 'mv a b' that would result in moving 'a' to 63 * 'b/a', that is putting it inside b. The same would happen if there were 64 * multiple files. 65 * 66 * To avoid this behavior the -T flag exists which causes the various commands 67 * to not check whether or not the target is a directory for the effect of 68 * trying to see if it should move something inside. 69 * 70 * The final form of an optional target is present only for ln. 71 * 72 * Overwriting Behavior 73 * -------------------- 74 * 75 * These commands have different defaults that control what happens when they 76 * encounter things that already exist. See the discussion on the definition of 77 * the target_action_t enum and the logic in chkfiles() for an overview. 78 * 79 * Symlink Behavior 80 * ---------------- 81 * 82 * These three tools all have to deal with what happens when you encounter a 83 * symbolic link. Let's take each of these in turn: 84 * 85 * mv does not do anything special when it encounters a symbolic link. It never 86 * follows links and there is no option to control this behavior. This is the 87 * simplest case and means that when we are looking at files we always use 88 * lstat(2). 89 * 90 * ln's behavior varies on whether or not one is creating a symlink with the -s 91 * option. If -s is specified, then symlinks are not followed. There are two 92 * options which control the behavior when creating hardlinks: -L and -P. These 93 * control what the hardlink is created to. 94 * 95 * Consider the case where we have a directory with a file a and a symlink b. 96 * When one runs ln b c what is supposed to happen? 97 * 98 * When -L is specified, c is going to be a symlink and b/c are hardlinks to one 99 * another and share the same inode. Meaning the directory now contains two 100 * symlinks and the single file a. When -P is specified, b is followed and a/c 101 * are hardlinks to one another. This implies that the directory now contains 102 * two files and the single symlink b. The default behavior of ln is to act like 103 * -P is specified. To summarize the default behavior and -P is to use lstat(2) 104 * when looking for information. When using -L we need to use stat and 105 * AT_SYMLINK_FOLLOW. 106 * 107 * There is one wrinkle, because nothing can ever be quite so simple. The 108 * behavior of link(2) changed with the SVR4 merge, but was left specific to an 109 * xpg4 environment. See the implementation of link(2) in libc for more 110 * information. This means the default for normal ln and xpg4 ln are different 111 * and xpg4 ln acts like -L is the default actually. This is addressed by 112 * pre-seeding the options when performing xpg4 ln. 113 * 114 * Finally we have cp. cp is the most complicated of these. There are two 115 * different general modes for cp: 116 * 117 * 1. cp is copying non-recursively. Symlinks are always followed in this case. 118 * 2. cp is copying recursively. Symlink behavior is controlled by three 119 * options: -L, -P, and a new option -H. 120 * 121 * cp -L does not preserve symbolic links. It uses stat(2) and copies the 122 * resulting file into place. cp -P preserves symbolic links. It uses lstat(2) 123 * and will result in a new symbolic link, pointing to the same original target, 124 * being created. Finally, -H is the compromise position. It asks is this a 125 * symbolic link that was encountered on the command line directly as an 126 * operand. If so, it will be copied like -L is specified. Otherwise this 127 * implies it is a symlink encountered recursively and the equivalent of -P 128 * should be used. 129 * 130 * When cp is used recursively the default behavior is -L. 131 * 132 * The following table attempts to summarize the options available across all 133 * the different commands: 134 * 135 * COMMAND DEFAULT -L -P -H FLAG 136 * mv lstat (-P) - - - - 137 * ln lstat (-P) stat lstat - Lflg 138 * xpg4 ln stat (-L) stat lstat - Lflg 139 * ln -s lstat (-P) ign ign - - 140 * cp stat (-L) - - - - 141 * cp -r | -R stat (-L) stat lstat both Pflg 142 * 143 * The default column indicates what the action the command takes and what the 144 * equivalent stat command and flag is. The option columns indicate the behavior 145 * and a '-' indicates that the flag is unsupported while 'ign' indicates that 146 * the flag is ignored. POSIX indicates ln -s ignores -L/-P. The FLAG column 147 * indicates which of the variables the program uses to drive behavior after 148 * option processing. In all cases it is legal for these options to occur 149 * multiple times. 150 */ 151 152 #include <sys/time.h> 153 #include <signal.h> 154 #include <locale.h> 155 #include <stdarg.h> 156 #include <sys/acl.h> 157 #include <libcmdutils.h> 158 #include <aclutils.h> 159 #include <assert.h> 160 #include "getresponse.h" 161 162 #define FTYPE(A) (A.st_mode) 163 #define FMODE(A) (A.st_mode) 164 #define UID(A) (A.st_uid) 165 #define GID(A) (A.st_gid) 166 #define IDENTICAL(A, B) (A.st_dev == B.st_dev && A.st_ino == B.st_ino) 167 #define ISDIR(A) ((A.st_mode & S_IFMT) == S_IFDIR) 168 #define ISDOOR(A) ((A.st_mode & S_IFMT) == S_IFDOOR) 169 #define ISLNK(A) ((A.st_mode & S_IFMT) == S_IFLNK) 170 #define ISREG(A) (((A).st_mode & S_IFMT) == S_IFREG) 171 #define ISDEV(A) ((A.st_mode & S_IFMT) == S_IFCHR || \ 172 (A.st_mode & S_IFMT) == S_IFBLK || \ 173 (A.st_mode & S_IFMT) == S_IFIFO) 174 #define ISSOCK(A) ((A.st_mode & S_IFMT) == S_IFSOCK) 175 176 #define DELIM '/' 177 #define EQ(x, y) (strcmp(x, y) == 0) 178 #define FALSE 0 179 #define MODEBITS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) 180 #define TRUE 1 181 182 typedef enum { 183 /* 184 * Indicates that after checking the file we should proceed with the 185 * action. 186 */ 187 CHK_CONT, 188 /* 189 * Indicates that after checking the file we encountered an error that 190 * should be percolated up. 191 */ 192 CHK_ERROR, 193 /* 194 * Indicate that the user opted to skip this file. No action should be 195 * taken and this should be treated as successful. 196 */ 197 CHK_SKIP 198 } chkfiles_t; 199 200 static chkfiles_t chkfiles(const char *, char **); 201 static const char *dname(const char *); 202 static int lnkfil(const char *, char *); 203 static int cpymve(const char *, char *); 204 static int rcopy(const char *, char *); 205 static int chk_different(const char *, const char *); 206 static int chg_time(const char *, struct stat); 207 static int chg_mode(const char *, uid_t, gid_t, mode_t); 208 static int copydir(const char *, char *); 209 static int copyspecial(const char *); 210 static int getrealpath(const char *, char *); 211 static void usage(void); 212 static void Perror(const char *); 213 static void Perror2(const char *, const char *); 214 static int use_stdin(void); 215 static int copyattributes(const char *, const char *); 216 static int copy_sysattr(const char *, const char *); 217 static tree_node_t *create_tnode(dev_t, ino_t); 218 219 static struct stat s1, s2, s3, s4; 220 static int cpy = FALSE; 221 static int mve = FALSE; 222 static int lnk = FALSE; 223 static char *cmd; 224 static int fflg = 0; 225 static int pflg = 0; 226 static int Rflg = 0; /* recursive copy */ 227 static int rflg = 0; /* recursive copy */ 228 static int sflg = 0; 229 static int Hflg = 0; /* follow cmd line arg symlink to dir */ 230 static int Lflg = 0; /* follow symlinks */ 231 static int Pflg = 0; /* do not follow symlinks */ 232 static int atflg = 0; 233 static int Tflg = 0; /* Treat target as a normal file */ 234 static int attrsilent = 0; 235 static int targetexists = 0; 236 static int cmdarg; /* command line argument */ 237 static avl_tree_t *stree = NULL; /* source file inode search tree */ 238 static acl_t *s1acl; 239 static int saflg = 0; /* 'cp' extended system attr. */ 240 static int srcfd = -1; 241 static int targfd = -1; 242 static int sourcedirfd = -1; 243 static int targetdirfd = -1; 244 static DIR *srcdirp = NULL; 245 static int srcattrfd = -1; 246 static int targattrfd = -1; 247 static struct stat attrdir; 248 249 /* 250 * cp, mv, and ln all have behaviors around what happens when a file already 251 * exists at the target. These behaviors depend on a combination of the program, 252 * the options specified, and the permissions of the target file. 253 * 254 * 1) Explicitly remove any target file 255 * 2) Always ask the user 256 * 3) Take no action and treat as successful 257 * 4) Take no action and treat as a failure 258 * 5) Replace the target file if permissions align, otherwise fail 259 * 6) Replace the target file if permissions align, otherwise prompt if stdin 260 * is a tty 261 * 262 * The default action varies based on the program. cp defaults to (5), mv to 263 * (6), and ln to (4). There are three flags that depending on the program 264 * will change the behavior that is taken: -f, -i, and -n. Of these only -i has 265 * the same meaning across all three programs. In this context, we treat these 266 * flags as: 267 * 268 * -f: take action (1) 269 * -i: take action (2) 270 * -n: take action (3) 271 * 272 * The following table shows which programs honor which of these flags: 273 * 274 * CP LN MV 275 * -f N Y Y 276 * -i Y Y Y 277 * -n Y Y N 278 * 279 * Any case where you see a 'N' above means the program has a different meaning 280 * for the flag. These four actions are summarized in the following enumeration. 281 * 282 * The last wrinkle with these is how they are processed on the command line. In 283 * general, we treat these as the last one wins. That is, if you specified -i -n 284 * then we would use the -n behavior. The only wrinkle for this is with mv. The 285 * non-POSIX form of mv any -f trump all -i options, but the xpg4 behavior was 286 * the last one wins. In this case -n takes the last one wins behavior with mv 287 * to try to make it as similar to everything else as we can. 288 */ 289 typedef enum { 290 /* 291 * Take the program's default behavior. 292 */ 293 TA_DEFAULT, 294 /* 295 * The user has explicitly said we should remove the file. 296 */ 297 TA_OVERWRITE, 298 /* 299 * The user has said we should always prompt about the file. 300 */ 301 TA_PROMPT, 302 /* 303 * The user has said we should always leave it be. 304 */ 305 TA_SKIP 306 } target_action_t; 307 308 target_action_t targact = TA_DEFAULT; 309 310 /* Extended system attributes support */ 311 312 static int open_source(const char *); 313 static int open_target_srctarg_attrdirs(const char *, const char *); 314 static int open_attrdirp(const char *); 315 static int traverse_attrfile(struct dirent *, const char *, const char *, int); 316 static void rewind_attrdir(DIR *); 317 static void close_all(void); 318 319 320 int 321 main(int argc, char *argv[]) 322 { 323 int c, i, r, errflg = 0; 324 char target[PATH_MAX]; 325 int (*move)(const char *, char *); 326 327 /* 328 * Determine command invoked (mv, cp, or ln) 329 */ 330 331 if ((cmd = strrchr(argv[0], '/')) != NULL) 332 ++cmd; 333 else 334 cmd = argv[0]; 335 336 /* 337 * Set flags based on command. 338 */ 339 340 (void) setlocale(LC_ALL, ""); 341 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 342 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 343 #endif 344 (void) textdomain(TEXT_DOMAIN); 345 if (init_yes() < 0) { 346 (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES), 347 strerror(errno)); 348 exit(3); 349 } 350 351 if (EQ(cmd, "mv")) 352 mve = TRUE; 353 else if (EQ(cmd, "ln")) 354 lnk = TRUE; 355 else if (EQ(cmd, "cp")) 356 cpy = TRUE; 357 else { 358 (void) fprintf(stderr, 359 gettext("Invalid command name (%s); expecting " 360 "mv, cp, or ln.\n"), cmd); 361 exit(1); 362 } 363 364 /* 365 * Check for options: 366 * cp [-afinpT@/] source_file target_file 367 * cp [-afinp@/] source_file... target 368 * cp [-afinp@/] -T source_file target 369 * cp [-r|-R [-H|-L|-P]] [-afinp@/] source_dir... target 370 * ln [-fins] [-L|-P] source_file [target] 371 * ln [-fins] [-L|-P] source_file... target 372 * ln [-fins] [-L|-P] -T source_file target 373 * mv [-fin] source target_file 374 * mv [-fin] source... target_dir 375 * mv [-fin] -T source target 376 */ 377 378 if (cpy) { 379 while ((c = getopt(argc, argv, "afHinLpPrRT@/")) != EOF) 380 switch (c) { 381 case 'f': 382 fflg++; 383 break; 384 case 'i': 385 targact = TA_PROMPT; 386 break; 387 case 'n': 388 targact = TA_SKIP; 389 break; 390 case 'p': 391 pflg++; 392 #ifdef XPG4 393 attrsilent = 1; 394 atflg = 0; 395 saflg = 0; 396 #else 397 if (atflg == 0) 398 attrsilent = 1; 399 #endif 400 break; 401 case 'H': 402 /* 403 * If more than one of -H, -L, or -P are 404 * specified, only the last option specified 405 * determines the behavior. 406 */ 407 Lflg = Pflg = 0; 408 Hflg++; 409 break; 410 case 'L': 411 Hflg = Pflg = 0; 412 Lflg++; 413 break; 414 case 'P': 415 Lflg = Hflg = 0; 416 Pflg++; 417 break; 418 case 'R': 419 /* 420 * The default behavior of cp -R|-r 421 * when specified without -H|-L|-P 422 * is -L. 423 */ 424 Rflg++; 425 /*FALLTHROUGH*/ 426 case 'r': 427 rflg++; 428 break; 429 case 'a': 430 Lflg = Hflg = 0; 431 pflg++; 432 Pflg++; 433 Rflg++; 434 rflg++; 435 break; 436 case 'T': 437 Tflg = 1; 438 break; 439 case '@': 440 atflg++; 441 attrsilent = 0; 442 #ifdef XPG4 443 pflg = 0; 444 #endif 445 break; 446 case '/': 447 saflg++; 448 attrsilent = 0; 449 #ifdef XPG4 450 pflg = 0; 451 #endif 452 break; 453 default: 454 errflg++; 455 } 456 457 /* -R or -r must be specified with -H, -L, or -P */ 458 if ((Hflg || Lflg || Pflg) && !(Rflg || rflg)) { 459 errflg++; 460 } 461 462 } else if (mve) { 463 while ((c = getopt(argc, argv, "finsT")) != EOF) 464 switch (c) { 465 case 'f': 466 targact = TA_OVERWRITE; 467 break; 468 case 'i': 469 #ifdef XPG4 470 targact = TA_PROMPT; 471 #else 472 if (targact != TA_OVERWRITE) { 473 targact = TA_PROMPT; 474 } 475 #endif 476 break; 477 case 'n': 478 targact = TA_SKIP; 479 break; 480 case 'T': 481 Tflg = 1; 482 break; 483 default: 484 errflg++; 485 } 486 } else { /* ln */ 487 /* 488 * The XPG4 merge caused the default behavior of link(2) to 489 * change unfortunately. See the comment in libc for more 490 * information. This means that xpg4 ln and normal ln have 491 * different default behaviors. If we're in xpg4 mode, pre-set 492 * some options that may be overriden. 493 */ 494 #ifdef XPG4 495 Lflg = 1; 496 #endif 497 while ((c = getopt(argc, argv, "fiLnPsT")) != EOF) 498 switch (c) { 499 case 'f': 500 targact = TA_OVERWRITE; 501 break; 502 case 'i': 503 targact = TA_PROMPT; 504 break; 505 case 'L': 506 Lflg = 1; 507 Pflg = 0; 508 break; 509 case 'n': 510 /* silently ignored; this is the default */ 511 break; 512 case 'P': 513 Pflg = 1; 514 Lflg = 0; 515 break; 516 case 's': 517 sflg++; 518 break; 519 case 'T': 520 Tflg = 1; 521 break; 522 default: 523 errflg++; 524 } 525 } 526 527 /* 528 * For BSD compatibility allow - to delimit the end of 529 * options for mv. 530 */ 531 if (mve && optind < argc && (strcmp(argv[optind], "-") == 0)) 532 optind++; 533 534 /* 535 * Check for sufficient arguments 536 * or a usage error. 537 */ 538 539 argc -= optind; 540 argv = &argv[optind]; 541 542 if ((argc < 2 && lnk != TRUE) || (argc < 1 && lnk == TRUE)) { 543 (void) fprintf(stderr, 544 gettext("%s: Insufficient arguments (%d)\n"), 545 cmd, argc); 546 usage(); 547 } 548 549 if (errflg != 0) 550 usage(); 551 552 /* 553 * If there is more than a source and target, 554 * the last argument (the target) must be a directory 555 * which really exists. 556 */ 557 558 if (argc > 2) { 559 if (Tflg) { 560 (void) fprintf(stderr, gettext("%s: only a single " 561 "source and target can be used with -T\n"), cmd); 562 exit(2); 563 } 564 565 if (stat(argv[argc-1], &s2) < 0) { 566 (void) fprintf(stderr, 567 gettext("%s: %s not found\n"), 568 cmd, argv[argc-1]); 569 exit(2); 570 } 571 572 if (!ISDIR(s2)) { 573 (void) fprintf(stderr, 574 gettext("%s: Target %s must be a directory\n"), 575 cmd, argv[argc-1]); 576 usage(); 577 } 578 } 579 580 if (strlen(argv[argc-1]) >= PATH_MAX) { 581 (void) fprintf(stderr, 582 gettext("%s: Target %s file name length exceeds PATH_MAX" 583 " %d\n"), cmd, argv[argc-1], PATH_MAX); 584 exit(78); 585 } 586 587 if (argc == 1) { 588 if (!lnk) 589 usage(); 590 if (Tflg) { 591 (void) fprintf(stderr, gettext("%s: -T requires " 592 "specifying a target argument\n"), cmd); 593 exit(2); 594 } 595 (void) strcpy(target, "."); 596 } else { 597 (void) strcpy(target, argv[--argc]); 598 } 599 600 /* 601 * Perform a multiple argument mv|cp|ln by 602 * multiple invocations of cpymve() or lnkfil(). 603 */ 604 if (lnk) 605 move = lnkfil; 606 else 607 move = cpymve; 608 609 r = 0; 610 for (i = 0; i < argc; i++) { 611 stree = NULL; 612 cmdarg = 1; 613 r += move(argv[i], target); 614 } 615 616 /* 617 * Show errors by nonzero exit code. 618 */ 619 return (r ? 2 : 0); 620 } 621 622 static int 623 lnkfil(const char *source, char *target) 624 { 625 char *buf = NULL; 626 int flags; 627 628 if (sflg) { 629 /* 630 * If target is a directory make complete 631 * name of the new symbolic link within that 632 * directory. 633 */ 634 if ((stat(target, &s2) >= 0) && ISDIR(s2) && !Tflg) { 635 size_t len; 636 637 len = strlen(target) + strlen(dname(source)) + 4; 638 if ((buf = (char *)malloc(len)) == NULL) { 639 (void) fprintf(stderr, 640 gettext("%s: Insufficient memory " 641 "to %s %s\n"), cmd, cmd, source); 642 exit(3); 643 } 644 (void) snprintf(buf, len, "%s/%s", 645 target, dname(source)); 646 target = buf; 647 } 648 649 /* 650 * Check to see if the file exists already. 651 * In this case we use lstat() instead of stat(): 652 * unlink(2) and symlink(2) will operate on the file 653 * itself, not its reference, if the file is a symlink. 654 */ 655 if ((lstat(target, &s2) == 0)) { 656 /* 657 * Check what our current overwrite behavior is i.e. the 658 * -f or -n options. If prompting is set (-i), ask the 659 * user. If overwrite is set (-n) then we attempt to 660 * remove it. In both cases if the target is a directory 661 * then we refuse to remove this. Once this is done, the 662 * program will proceed with creating the symlink. 663 */ 664 switch (targact) { 665 case TA_OVERWRITE: 666 case TA_PROMPT: 667 if (ISDIR(s2)) { 668 (void) fprintf(stderr, 669 gettext("%s: cannot create link " 670 "over directory %s\n"), cmd, 671 target); 672 return (1); 673 } 674 675 /* 676 * See the longer discussion in chkfiles about 677 * the use of use_stdin() while prompting. 678 */ 679 if (targact == TA_PROMPT && use_stdin()) { 680 (void) fprintf(stderr, 681 gettext("%s: overwrite %s " 682 "(%s/%s)? "), cmd, target, yesstr, 683 nostr); 684 if (yes() == 0) { 685 return (0); 686 } 687 } 688 689 if (unlink(target) < 0) { 690 (void) fprintf(stderr, 691 gettext("%s: cannot unlink %s: "), 692 cmd, target); 693 perror(""); 694 return (1); 695 } 696 case TA_DEFAULT: 697 break; 698 case TA_SKIP: 699 /* 700 * This shouldn't be selectable. 701 */ 702 abort(); 703 } 704 } 705 706 /* 707 * Create a symbolic link to the source. 708 */ 709 if (symlink(source, target) < 0) { 710 (void) fprintf(stderr, 711 gettext("%s: cannot create %s: "), 712 cmd, target); 713 perror(""); 714 if (buf != NULL) 715 free(buf); 716 return (1); 717 } 718 if (buf != NULL) 719 free(buf); 720 return (0); 721 } 722 723 switch (chkfiles(source, &target)) { 724 case CHK_ERROR: 725 return (1); 726 case CHK_SKIP: 727 return (0); 728 case CHK_CONT: 729 break; 730 } 731 732 /* 733 * Make sure source file is not a directory, 734 * we cannot link directories... 735 */ 736 if (ISDIR(s1)) { 737 (void) fprintf(stderr, 738 gettext("%s: %s is a directory\n"), cmd, source); 739 return (1); 740 } 741 742 /* 743 * Create a hard link with the appropriate flags in question. POSIX 744 * calls out the explicit use of linkat() and the flags to use. The 745 * defaults are up to us. See the 'Symlink Behavior' section of the 746 * theory statement for more information. 747 */ 748 flags = Lflg ? AT_SYMLINK_FOLLOW : 0; 749 if (linkat(AT_FDCWD, source, AT_FDCWD, target, flags) < 0) { 750 if (errno == EXDEV) 751 (void) fprintf(stderr, 752 gettext("%s: %s is on a different file system\n"), 753 cmd, target); 754 else { 755 (void) fprintf(stderr, 756 gettext("%s: cannot create link %s: "), 757 cmd, target); 758 perror(""); 759 } 760 if (buf != NULL) 761 free(buf); 762 return (1); 763 } else { 764 if (buf != NULL) 765 free(buf); 766 return (0); 767 } 768 } 769 770 static int 771 cpymve(const char *source, char *target) 772 { 773 int n; 774 int fi, fo; 775 int ret = 0; 776 int attret = 0; 777 int sattret = 0; 778 int error = 0; 779 780 switch (chkfiles(source, &target)) { 781 case CHK_ERROR: 782 return (1); 783 case CHK_SKIP: 784 return (0); 785 case CHK_CONT: 786 break; 787 } 788 789 /* 790 * If it's a recursive copy and source 791 * is a directory, then call rcopy (from copydir). 792 */ 793 if (cpy) { 794 if (ISDIR(s1)) { 795 int rc; 796 avl_index_t where = 0; 797 tree_node_t *tnode; 798 tree_node_t *tptr; 799 dev_t save_dev = s1.st_dev; 800 ino_t save_ino = s1.st_ino; 801 802 /* 803 * We will be recursing into the directory so 804 * save the inode information to a search tree 805 * to avoid getting into an endless loop. 806 */ 807 if ((rc = add_tnode(&stree, save_dev, save_ino)) != 1) { 808 if (rc == 0) { 809 /* 810 * We've already visited this directory. 811 * Don't remove the search tree entry 812 * to make sure we don't get into an 813 * endless loop if revisited from a 814 * different part of the hierarchy. 815 */ 816 (void) fprintf(stderr, gettext( 817 "%s: cycle detected: %s\n"), 818 cmd, source); 819 } else { 820 Perror(source); 821 } 822 return (1); 823 } 824 825 cmdarg = 0; 826 rc = copydir(source, target); 827 828 /* 829 * Create a tnode to get an index to the matching 830 * node (same dev and inode) in the search tree, 831 * then use the index to remove the matching node 832 * so it we do not wrongly detect a cycle when 833 * revisiting this directory from another part of 834 * the hierarchy. 835 */ 836 if ((tnode = create_tnode(save_dev, 837 save_ino)) == NULL) { 838 Perror(source); 839 return (1); 840 } 841 if ((tptr = avl_find(stree, tnode, &where)) != NULL) { 842 avl_remove(stree, tptr); 843 } 844 free(tptr); 845 free(tnode); 846 return (rc); 847 848 } else if (ISDEV(s1) && Rflg) { 849 return (copyspecial(target)); 850 } else { 851 goto copy; 852 } 853 } 854 855 if (mve) { 856 if (rename(source, target) >= 0) 857 return (0); 858 if (errno != EXDEV) { 859 if (errno == ENOTDIR && ISDIR(s1)) { 860 (void) fprintf(stderr, 861 gettext("%s: %s is a directory\n"), 862 cmd, source); 863 return (1); 864 } 865 (void) fprintf(stderr, 866 gettext("%s: cannot rename %s to %s: "), 867 cmd, source, target); 868 perror(""); 869 return (1); 870 } 871 872 /* 873 * cannot move a non-directory (source) onto an existing 874 * directory (target) 875 * 876 */ 877 if (targetexists && ISDIR(s2) && (!ISDIR(s1))) { 878 (void) fprintf(stderr, 879 gettext("%s: cannot mv a non directory %s " 880 "over existing directory" 881 " %s \n"), cmd, source, target); 882 return (1); 883 } 884 if (ISDIR(s1)) { 885 #ifdef XPG4 886 if (targetexists && ISDIR(s2)) { 887 /* existing target dir must be empty */ 888 if (rmdir(target) < 0) { 889 int errno_save = errno; 890 (void) fprintf(stderr, 891 gettext("%s: cannot rmdir %s: "), 892 cmd, target); 893 errno = errno_save; 894 perror(""); 895 return (1); 896 } 897 } 898 #endif 899 if ((n = copydir(source, target)) == 0) 900 (void) rmdir(source); 901 return (n); 902 } 903 904 /* doors cannot be moved across filesystems */ 905 if (ISDOOR(s1)) { 906 (void) fprintf(stderr, 907 gettext("%s: %s: cannot move door " 908 "across file systems\n"), cmd, source); 909 return (1); 910 } 911 912 /* sockets cannot be moved across filesystems */ 913 if (ISSOCK(s1)) { 914 (void) fprintf(stderr, 915 gettext("%s: %s: cannot move socket " 916 "across file systems\n"), cmd, source); 917 return (1); 918 } 919 920 /* 921 * File cannot be renamed, try to recreate the symbolic 922 * link or special device, or copy the file wholesale 923 * between file systems. 924 */ 925 if (ISLNK(s1)) { 926 register int m; 927 register mode_t md; 928 char symln[PATH_MAX + 1]; 929 930 if (targetexists && unlink(target) < 0) { 931 (void) fprintf(stderr, 932 gettext("%s: cannot unlink %s: "), 933 cmd, target); 934 perror(""); 935 return (1); 936 } 937 938 if ((m = readlink(source, symln, 939 sizeof (symln) - 1)) < 0) { 940 Perror(source); 941 return (1); 942 } 943 symln[m] = '\0'; 944 945 md = umask(~(s1.st_mode & MODEBITS)); 946 if (symlink(symln, target) < 0) { 947 Perror(target); 948 return (1); 949 } 950 (void) umask(md); 951 m = lchown(target, UID(s1), GID(s1)); 952 #ifdef XPG4 953 if (m < 0) { 954 (void) fprintf(stderr, gettext("%s: cannot" 955 " change owner and group of" 956 " %s: "), cmd, target); 957 perror(""); 958 } 959 #endif 960 goto cleanup; 961 } 962 if (ISDEV(s1)) { 963 964 if (targetexists && unlink(target) < 0) { 965 (void) fprintf(stderr, 966 gettext("%s: cannot unlink %s: "), 967 cmd, target); 968 perror(""); 969 return (1); 970 } 971 972 if (mknod(target, s1.st_mode, s1.st_rdev) < 0) { 973 Perror(target); 974 return (1); 975 } 976 977 (void) chg_mode(target, UID(s1), GID(s1), FMODE(s1)); 978 (void) chg_time(target, s1); 979 goto cleanup; 980 } 981 982 if (ISREG(s1)) { 983 if (ISDIR(s2)) { 984 if (targetexists && rmdir(target) < 0) { 985 (void) fprintf(stderr, 986 gettext("%s: cannot rmdir %s: "), 987 cmd, target); 988 perror(""); 989 return (1); 990 } 991 } else { 992 if (targetexists && unlink(target) < 0) { 993 (void) fprintf(stderr, 994 gettext("%s: cannot unlink %s: "), 995 cmd, target); 996 perror(""); 997 return (1); 998 } 999 } 1000 1001 1002 copy: 1003 /* 1004 * If the source file is a symlink, and either 1005 * -P or -H flag (only if -H is specified and the 1006 * source file is not a command line argument) 1007 * were specified, then action is taken on the symlink 1008 * itself, not the file referenced by the symlink. 1009 * Note: this is executed for 'cp' only. 1010 */ 1011 if (cpy && (Pflg || (Hflg && !cmdarg)) && (ISLNK(s1))) { 1012 int m; 1013 mode_t md; 1014 char symln[PATH_MAX + 1]; 1015 1016 m = readlink(source, symln, sizeof (symln) - 1); 1017 1018 if (m < 0) { 1019 Perror(source); 1020 return (1); 1021 } 1022 symln[m] = '\0'; 1023 1024 /* 1025 * Copy the sym link to the target. 1026 * Note: If the target exists, write a 1027 * diagnostic message, do nothing more 1028 * with the source file, and return to 1029 * process any remaining files. 1030 */ 1031 md = umask(~(s1.st_mode & MODEBITS)); 1032 if (symlink(symln, target) < 0) { 1033 Perror(target); 1034 return (1); 1035 } 1036 (void) umask(md); 1037 m = lchown(target, UID(s1), GID(s1)); 1038 1039 if (m < 0) { 1040 (void) fprintf(stderr, gettext( 1041 "cp: cannot change owner and " 1042 "group of %s:"), target); 1043 perror(""); 1044 } 1045 } else { 1046 /* 1047 * Copy the file. If it happens to be a 1048 * symlink, copy the file referenced 1049 * by the symlink. 1050 */ 1051 fi = open(source, O_RDONLY); 1052 if (fi < 0) { 1053 (void) fprintf(stderr, 1054 gettext("%s: cannot open %s: "), 1055 cmd, source); 1056 perror(""); 1057 return (1); 1058 } 1059 1060 fo = creat(target, s1.st_mode & MODEBITS); 1061 if (fo < 0) { 1062 /* 1063 * If -f and creat() failed, unlink 1064 * and try again. 1065 */ 1066 if (fflg) { 1067 (void) unlink(target); 1068 fo = creat(target, 1069 s1.st_mode & MODEBITS); 1070 } 1071 } 1072 if (fo < 0) { 1073 (void) fprintf(stderr, 1074 gettext("%s: cannot create %s: "), 1075 cmd, target); 1076 perror(""); 1077 (void) close(fi); 1078 return (1); 1079 } else { 1080 /* stat the new file, its used below */ 1081 (void) stat(target, &s2); 1082 } 1083 1084 /* 1085 * Set target's permissions to the source 1086 * before any copying so that any partially 1087 * copied file will have the source's 1088 * permissions (at most) or umask permissions 1089 * whichever is the most restrictive. 1090 * 1091 * ACL for regular files 1092 */ 1093 1094 if (pflg || mve) { 1095 (void) chmod(target, FMODE(s1)); 1096 if (s1acl != NULL) { 1097 if ((acl_set(target, 1098 s1acl)) < 0) { 1099 error++; 1100 (void) fprintf(stderr, 1101 gettext("%s: " 1102 "Failed to set " 1103 "acl entries " 1104 "on %s\n"), cmd, 1105 target); 1106 acl_free(s1acl); 1107 s1acl = NULL; 1108 /* 1109 * else: silent and 1110 * continue 1111 */ 1112 } 1113 } 1114 } 1115 1116 if (fstat(fi, &s1) < 0) { 1117 (void) fprintf(stderr, 1118 gettext("%s: cannot access %s\n"), 1119 cmd, source); 1120 return (1); 1121 } 1122 if (IDENTICAL(s1, s2)) { 1123 (void) fprintf(stderr, 1124 gettext( 1125 "%s: %s and %s are identical\n"), 1126 cmd, source, target); 1127 return (1); 1128 } 1129 1130 if (writefile(fi, fo, source, target, NULL, 1131 NULL, &s1, &s2) != 0) { 1132 return (1); 1133 } 1134 1135 (void) close(fi); 1136 if (close(fo) < 0) { 1137 Perror2(target, "write"); 1138 return (1); 1139 } 1140 } 1141 /* Copy regular extended attributes */ 1142 if (pflg || atflg || mve || saflg) { 1143 attret = copyattributes(source, target); 1144 if (attret != 0 && !attrsilent) { 1145 (void) fprintf(stderr, gettext( 1146 "%s: Failed to preserve" 1147 " extended attributes of file" 1148 " %s\n"), cmd, source); 1149 } 1150 /* Copy extended system attributes */ 1151 if (pflg || mve || saflg) 1152 sattret = copy_sysattr(source, target); 1153 if (mve && attret != 0) { 1154 (void) unlink(target); 1155 return (1); 1156 } 1157 if (attrsilent) { 1158 attret = 0; 1159 } 1160 } 1161 1162 /* 1163 * XPG4: the write system call will clear setgid 1164 * and setuid bits, so set them again. 1165 */ 1166 if (pflg || mve) { 1167 if ((ret = chg_mode(target, UID(s1), GID(s1), 1168 FMODE(s1))) > 0) 1169 return (1); 1170 /* 1171 * Reapply ACL, since chmod may have 1172 * altered ACL 1173 */ 1174 if (s1acl != NULL) { 1175 if ((acl_set(target, s1acl)) < 0) { 1176 error++; 1177 (void) fprintf(stderr, 1178 gettext("%s: Failed to " 1179 "set acl entries " 1180 "on %s\n"), cmd, target); 1181 /* 1182 * else: silent and 1183 * continue 1184 */ 1185 } 1186 } 1187 if ((ret = chg_time(target, s1)) > 0) 1188 return (1); 1189 } 1190 if (cpy) { 1191 if (error != 0 || attret != 0 || sattret != 0) 1192 return (1); 1193 return (0); 1194 } 1195 goto cleanup; 1196 } 1197 (void) fprintf(stderr, 1198 gettext("%s: %s: unknown file type 0x%x\n"), cmd, 1199 source, (s1.st_mode & S_IFMT)); 1200 return (1); 1201 1202 cleanup: 1203 if (unlink(source) < 0) { 1204 (void) unlink(target); 1205 (void) fprintf(stderr, 1206 gettext("%s: cannot unlink %s: "), 1207 cmd, source); 1208 perror(""); 1209 return (1); 1210 } 1211 if (error != 0 || attret != 0 || sattret != 0) 1212 return (1); 1213 return (ret); 1214 } 1215 /*NOTREACHED*/ 1216 return (ret); 1217 } 1218 1219 /* 1220 * create_tnode() 1221 * 1222 * Create a node for use with the search tree which contains the 1223 * inode information (device id and inode number). 1224 * 1225 * Input 1226 * dev - device id 1227 * ino - inode number 1228 * 1229 * Output 1230 * tnode - NULL on error, otherwise returns a tnode structure 1231 * which contains the input device id and inode number. 1232 */ 1233 static tree_node_t * 1234 create_tnode(dev_t dev, ino_t ino) 1235 { 1236 tree_node_t *tnode; 1237 1238 if ((tnode = (tree_node_t *)malloc(sizeof (tree_node_t))) != NULL) { 1239 tnode->node_dev = dev; 1240 tnode->node_ino = ino; 1241 } 1242 1243 return (tnode); 1244 } 1245 1246 static chkfiles_t 1247 chkfiles(const char *source, char **to) 1248 { 1249 char *buf = (char *)NULL; 1250 int (*statf)(const char *, struct stat *) = lstat; 1251 char *target = *to; 1252 int error; 1253 1254 /* 1255 * See the Symlink Behavior section of the theory statement for more 1256 * information. 1257 */ 1258 if (cpy && !(Pflg || (Hflg && !cmdarg))) { 1259 statf = stat; 1260 } else if (lnk && !sflg && Lflg) { 1261 statf = stat; 1262 } 1263 1264 /* 1265 * Make sure source file exists. 1266 */ 1267 if ((*statf)(source, &s1) < 0) { 1268 /* 1269 * Keep the old error message except when someone tries to 1270 * mv/cp/ln a symbolic link that has a trailing slash and 1271 * points to a file. 1272 */ 1273 if (errno == ENOTDIR) 1274 (void) fprintf(stderr, "%s: %s: %s\n", cmd, source, 1275 strerror(errno)); 1276 else 1277 (void) fprintf(stderr, 1278 gettext("%s: cannot access %s\n"), cmd, source); 1279 return (CHK_ERROR); 1280 } 1281 1282 /* 1283 * Get ACL info: don't bother with ln or cp/mv'ing symlinks 1284 */ 1285 if (!lnk && !ISLNK(s1)) { 1286 if (s1acl != NULL) { 1287 acl_free(s1acl); 1288 s1acl = NULL; 1289 } 1290 if ((error = acl_get(source, ACL_NO_TRIVIAL, &s1acl)) != 0) { 1291 (void) fprintf(stderr, 1292 "%s: failed to get acl entries: %s\n", source, 1293 acl_strerror(error)); 1294 return (CHK_ERROR); 1295 } 1296 /* else: just permission bits */ 1297 } 1298 1299 /* 1300 * If stat fails, then the target doesn't exist, 1301 * we will create a new target with default file type of regular. 1302 */ 1303 1304 FTYPE(s2) = S_IFREG; 1305 targetexists = 0; 1306 if ((*statf)(target, &s2) >= 0) { 1307 if (ISLNK(s2)) 1308 (void) stat(target, &s2); 1309 1310 /* 1311 * If target is a directory, make complete name of new file 1312 * within that directory unless -T is set. 1313 */ 1314 if (ISDIR(s2) && !Tflg) { 1315 size_t len; 1316 1317 len = strlen(target) + strlen(dname(source)) + 4; 1318 if ((buf = (char *)malloc(len)) == NULL) { 1319 (void) fprintf(stderr, 1320 gettext("%s: Insufficient memory to " 1321 "%s %s\n "), cmd, cmd, source); 1322 exit(3); 1323 } 1324 (void) snprintf(buf, len, "%s/%s", 1325 target, dname(source)); 1326 *to = target = buf; 1327 } 1328 1329 if ((*statf)(target, &s2) >= 0) { 1330 boolean_t prompt = B_FALSE; 1331 boolean_t overwrite = B_FALSE; 1332 boolean_t override = B_FALSE; 1333 1334 targetexists++; 1335 if (cpy || mve) { 1336 /* 1337 * For cp and mv, it is an error if the 1338 * source and target are the same file. 1339 * Check for the same inode and file 1340 * system, but don't check for the same 1341 * absolute pathname because it is an 1342 * error when the source and target are 1343 * hard links to the same file. 1344 */ 1345 if (IDENTICAL(s1, s2)) { 1346 (void) fprintf(stderr, 1347 gettext( 1348 "%s: %s and %s are identical\n"), 1349 cmd, source, target); 1350 if (buf != NULL) 1351 free(buf); 1352 return (CHK_ERROR); 1353 } 1354 } 1355 if (lnk) { 1356 /* 1357 * For ln, it is an error if the source and 1358 * target are identical files (same inode, 1359 * same file system, and filenames resolve 1360 * to same absolute pathname). 1361 */ 1362 if (!chk_different(source, target)) { 1363 if (buf != NULL) 1364 free(buf); 1365 return (CHK_ERROR); 1366 } 1367 } 1368 1369 /* 1370 * Determine if we need to prompt for overwriting the 1371 * file or for overriding its permissions. There is a 1372 * lot of thorny history here. 1373 * 1374 * The action we take depends on targact, which is the 1375 * user's selection or the command's default behavior. 1376 * If the user has explicitly opted into prompting, 1377 * explicitly asked invoked a force option, or said to 1378 * ignore things when there is a file here, then our 1379 * options are straightforward. When we're with the 1380 * program defaults, things get a bit more nuanced and 1381 * vary by program: 1382 * 1383 * ln: by default always fail with an error if target 1384 * exists, regardless of what kind of entity it is. 1385 * 1386 * cp: overwriting is allowed by default, overriding is 1387 * not. To override the -f flag will be specified which 1388 * will force removal. 1389 * 1390 * mv: overwriting is allowed by default, overriding 1391 * requires prompting if on stdin, otherwise it 1392 * proceeds. Note, "on stdin" varies based on XPG4 or 1393 * not. 1394 * 1395 * The history here is messy. Logically speaking the way 1396 * that overwriting and overriding was checked in the 1397 * past was the following rough logic: 1398 * 1399 * 1) Overwriting is considered if -i is set, -f (mv 1400 * only) wasn't set, and use_stdin() was true (always 1401 * true for XPG4, otherwise only if it was a tty). 1402 * 1403 * 2) Overriding is considered if it was mv, the file 1404 * was not write accessible, -f wasn't specified and the 1405 * target wasn't a symbolic link. 1406 * 1407 * 3) If both overwrite and override were set, it would 1408 * always prompt. If just override was set, it would 1409 * always prompt. However, if only overwrite was set, it 1410 * would only prompt if the target was a regular file! 1411 * 1412 * Based on this, you can see that cp/mv -i didn't 1413 * actually prompt for any number of cases as it didn't 1414 * consider if -i had been specified, which is 1415 * definitely against the spirit of -i (and POSIX). If 1416 * -i is specified we will **always** consider the 1417 * prompt based on use_stdin() because of history. If we 1418 * are looking at defaults, then we will honor the 1419 * historical conditions that were used to check for 1420 * overwriting and overriding. 1421 */ 1422 switch (targact) { 1423 case TA_SKIP: 1424 if (buf != NULL) 1425 free(buf); 1426 return (CHK_SKIP); 1427 case TA_OVERWRITE: 1428 break; 1429 case TA_PROMPT: 1430 if (use_stdin()) { 1431 prompt = B_TRUE; 1432 overwrite = B_TRUE; 1433 if (mve && access(target, W_OK) < 0 && 1434 !ISLNK(s2)) { 1435 override = B_TRUE; 1436 } 1437 } 1438 break; 1439 case TA_DEFAULT: 1440 if (lnk) { 1441 (void) fprintf(stderr, 1442 gettext("%s: %s: File exists\n"), 1443 cmd, target); 1444 if (buf != NULL) 1445 free(buf); 1446 return (CHK_ERROR); 1447 } 1448 1449 /* 1450 * Now we have to figure out what we're going to 1451 * do here. Determine if this meets the 1452 * traditional prompting guidelines. 1453 */ 1454 if (mve && access(target, W_OK) < 0 && 1455 use_stdin() && !ISLNK(s2)) { 1456 prompt = B_TRUE; 1457 override = B_TRUE; 1458 } 1459 break; 1460 } 1461 1462 /* 1463 * We've been asked to prompt. Determine the appropriate 1464 * message for the command and the type of action that 1465 * is going on. 1466 */ 1467 if (prompt) { 1468 assert(overwrite || override); 1469 if (overwrite && override) { 1470 (void) fprintf(stderr, gettext("%s: " 1471 "overwrite %s and override " 1472 "protection %o (%s/%s)? "), cmd, 1473 target, FMODE(s2) & MODEBITS, 1474 yesstr, nostr); 1475 } else if (overwrite) { 1476 (void) fprintf(stderr, gettext("%s: " 1477 "overwrite %s (%s/%s)? "), cmd, 1478 target, yesstr, nostr); 1479 } else if (override) { 1480 (void) fprintf(stderr, gettext("%s: " 1481 "%s: override protection %o " 1482 "(%s/%s)? "), cmd, target, 1483 FMODE(s2) & MODEBITS, yesstr, 1484 nostr); 1485 } 1486 if (yes() == 0) { 1487 if (buf != NULL) 1488 free(buf); 1489 return (CHK_SKIP); 1490 } 1491 } 1492 1493 if (lnk && unlink(target) < 0) { 1494 (void) fprintf(stderr, 1495 gettext("%s: cannot unlink %s: "), 1496 cmd, target); 1497 perror(""); 1498 return (CHK_ERROR); 1499 } 1500 } 1501 } 1502 return (CHK_CONT); 1503 } 1504 1505 /* 1506 * check whether source and target are different 1507 * return 1 when they are different 1508 * return 0 when they are identical, or when unable to resolve a pathname 1509 */ 1510 static int 1511 chk_different(const char *source, const char *target) 1512 { 1513 char rtarget[PATH_MAX], rsource[PATH_MAX]; 1514 1515 if (IDENTICAL(s1, s2)) { 1516 /* 1517 * IDENTICAL will be true for hard links, therefore 1518 * check whether the filenames are different 1519 */ 1520 if ((getrealpath(source, rsource) == 0) || 1521 (getrealpath(target, rtarget) == 0)) { 1522 return (0); 1523 } 1524 if (strncmp(rsource, rtarget, PATH_MAX) == 0) { 1525 (void) fprintf(stderr, gettext( 1526 "%s: %s and %s are identical\n"), 1527 cmd, source, target); 1528 return (0); 1529 } 1530 } 1531 return (1); 1532 } 1533 1534 /* 1535 * get real path (resolved absolute pathname) 1536 * return 1 on success, 0 on failure 1537 */ 1538 static int 1539 getrealpath(const char *path, char *rpath) 1540 { 1541 if (realpath(path, rpath) == NULL) { 1542 int errno_save = errno; 1543 (void) fprintf(stderr, gettext( 1544 "%s: cannot resolve path %s: "), cmd, path); 1545 errno = errno_save; 1546 perror(""); 1547 return (0); 1548 } 1549 return (1); 1550 } 1551 1552 static int 1553 rcopy(const char *from, char *to) 1554 { 1555 DIR *fold = opendir(from); 1556 struct dirent *dp; 1557 struct stat statb, s1save; 1558 int errs = 0; 1559 char fromname[PATH_MAX]; 1560 1561 if (fold == 0 || ((pflg || mve) && fstat(fold->dd_fd, &statb) < 0)) { 1562 Perror(from); 1563 return (1); 1564 } 1565 if (pflg || mve) { 1566 /* 1567 * Save s1 (stat information for source dir) so that 1568 * mod and access times can be reserved during "cp -p" 1569 * or mv, since s1 gets overwritten. 1570 */ 1571 s1save = s1; 1572 } 1573 for (;;) { 1574 dp = readdir(fold); 1575 if (dp == 0) { 1576 (void) closedir(fold); 1577 if (pflg || mve) 1578 return (chg_time(to, s1save) + errs); 1579 return (errs); 1580 } 1581 if (dp->d_ino == 0) 1582 continue; 1583 if ((strcmp(dp->d_name, ".") == 0) || 1584 (strcmp(dp->d_name, "..") == 0)) 1585 continue; 1586 if (strlen(from)+1+strlen(dp->d_name) >= 1587 sizeof (fromname) - 1) { 1588 (void) fprintf(stderr, 1589 gettext("%s : %s/%s: Name too long\n"), 1590 cmd, from, dp->d_name); 1591 errs++; 1592 continue; 1593 } 1594 (void) snprintf(fromname, sizeof (fromname), 1595 "%s/%s", from, dp->d_name); 1596 errs += cpymve(fromname, to); 1597 } 1598 } 1599 1600 static const char * 1601 dname(const char *name) 1602 { 1603 const char *p; 1604 1605 /* 1606 * Return just the file name given the complete path. 1607 * Like basename(1). 1608 */ 1609 1610 p = name; 1611 1612 /* 1613 * While there are characters left, 1614 * set name to start after last 1615 * delimiter. 1616 */ 1617 1618 while (*p) 1619 if (*p++ == DELIM && *p) 1620 name = p; 1621 return (name); 1622 } 1623 1624 static void 1625 usage(void) 1626 { 1627 /* 1628 * Display usage message. 1629 */ 1630 1631 if (mve) { 1632 (void) fprintf(stderr, gettext( 1633 "Usage: mv [-fin] source target_file\n" 1634 " mv [-fin] source... target_dir\n" 1635 " mv [-fin] -T source target\n")); 1636 } else if (lnk) { 1637 #ifdef XPG4 1638 (void) fprintf(stderr, gettext( 1639 "Usage: ln [-fis] [-L|-P] source_file [target]\n" 1640 " ln [-fis] [-L|-P] source_file... target\n" 1641 " ln [-fis] [-L|-P] -T source_file target\n")); 1642 #else 1643 (void) fprintf(stderr, gettext( 1644 "Usage: ln [-fins] [-L|-P] source_file [target]\n" 1645 " ln [-fins] [-L|-P] source_file... target\n" 1646 " ln [-fins] [-L|-P] -T source_file target\n")); 1647 #endif 1648 } else if (cpy) { 1649 (void) fprintf(stderr, gettext( 1650 "Usage: cp [-afinpT@/] source_file target_file\n" 1651 " cp [-afinp@/] source_file... target\n" 1652 " cp [-afinp@/] -T source_file target\n" 1653 " cp [-r|-R [-H|-L|-P]] [-afinp@/] " 1654 "source_dir... target\n")); 1655 } 1656 exit(2); 1657 } 1658 1659 /* 1660 * chg_time() 1661 * 1662 * Try to preserve modification and access time. 1663 * If 1) pflg is not set, or 2) pflg is set and this is the Solaris version, 1664 * don't report a utimensat() failure. 1665 * If this is the XPG4 version and utimensat fails, if 1) pflg is set (cp -p) 1666 * or 2) we are doing a mv, print a diagnostic message; arrange for a non-zero 1667 * exit status only if pflg is set. 1668 * utimensat(2) is being used to achieve granularity in nanoseconds 1669 * (if supported by the underlying file system) while setting file times. 1670 */ 1671 static int 1672 chg_time(const char *to, struct stat ss) 1673 { 1674 struct timespec times[2]; 1675 #ifdef XPG4 1676 int rc; 1677 #endif 1678 1679 times[0] = ss.st_atim; 1680 times[1] = ss.st_mtim; 1681 1682 #ifdef XPG4 1683 rc = utimensat(AT_FDCWD, to, times, 1684 ISLNK(s1) ? AT_SYMLINK_NOFOLLOW : 0); 1685 if ((pflg || mve) && rc != 0) { 1686 (void) fprintf(stderr, 1687 gettext("%s: cannot set times for %s: "), cmd, to); 1688 perror(""); 1689 if (pflg) 1690 return (1); 1691 } 1692 #else 1693 (void) utimensat(AT_FDCWD, to, times, 1694 ISLNK(s1) ? AT_SYMLINK_NOFOLLOW : 0); 1695 #endif 1696 1697 return (0); 1698 1699 } 1700 1701 /* 1702 * chg_mode() 1703 * 1704 * This function is called upon "cp -p" or mv across filesystems. 1705 * 1706 * Try to preserve the owner and group id. If chown() fails, 1707 * only print a diagnostic message if doing a mv in the XPG4 version; 1708 * try to clear S_ISUID and S_ISGID bits in the target. If unable to clear 1709 * S_ISUID and S_ISGID bits, print a diagnostic message and arrange for a 1710 * non-zero exit status because this is a security violation. 1711 * Try to preserve permissions. 1712 * If this is the XPG4 version and chmod() fails, print a diagnostic message 1713 * and arrange for a non-zero exit status. 1714 * If this is the Solaris version and chmod() fails, do not print a 1715 * diagnostic message or exit with a non-zero value. 1716 */ 1717 static int 1718 chg_mode(const char *target, uid_t uid, gid_t gid, mode_t mode) 1719 { 1720 int clearflg = 0; /* controls message printed upon chown() error */ 1721 struct stat st; 1722 1723 /* Don't change mode if target is symlink */ 1724 if (lstat(target, &st) == 0 && ISLNK(st)) 1725 return (0); 1726 1727 if (chown(target, uid, gid) != 0) { 1728 #ifdef XPG4 1729 if (mve) { 1730 (void) fprintf(stderr, gettext("%s: cannot change" 1731 " owner and group of %s: "), cmd, target); 1732 perror(""); 1733 } 1734 #endif 1735 if (mode & (S_ISUID | S_ISGID)) { 1736 /* try to clear S_ISUID and S_ISGID */ 1737 mode &= ~S_ISUID & ~S_ISGID; 1738 ++clearflg; 1739 } 1740 } 1741 if (chmod(target, mode) != 0) { 1742 if (clearflg) { 1743 (void) fprintf(stderr, gettext( 1744 "%s: cannot clear S_ISUID and S_ISGID bits in" 1745 " %s: "), cmd, target); 1746 perror(""); 1747 /* cp -p should get non-zero exit; mv should not */ 1748 if (pflg) 1749 return (1); 1750 } 1751 #ifdef XPG4 1752 else { 1753 (void) fprintf(stderr, gettext( 1754 "%s: cannot set permissions for %s: "), cmd, target); 1755 perror(""); 1756 /* cp -p should get non-zero exit; mv should not */ 1757 if (pflg) 1758 return (1); 1759 } 1760 #endif 1761 } 1762 return (0); 1763 1764 } 1765 1766 static void 1767 Perror(const char *s) 1768 { 1769 char buf[PATH_MAX + 10]; 1770 1771 (void) snprintf(buf, sizeof (buf), "%s: %s", cmd, s); 1772 perror(buf); 1773 } 1774 1775 static void 1776 Perror2(const char *s1, const char *s2) 1777 { 1778 char buf[PATH_MAX + 20]; 1779 1780 (void) snprintf(buf, sizeof (buf), "%s: %s: %s", 1781 cmd, gettext(s1), gettext(s2)); 1782 perror(buf); 1783 } 1784 1785 /* 1786 * used for cp -R and for mv across file systems 1787 */ 1788 static int 1789 copydir(const char *source, char *target) 1790 { 1791 int ret, attret = 0; 1792 int sattret = 0; 1793 int pret = 0; /* need separate flag if -p is specified */ 1794 mode_t fixmode = (mode_t)0; /* cleanup mode after copy */ 1795 struct stat s1save; 1796 acl_t *s1acl_save; 1797 int error = 0; 1798 1799 s1acl_save = NULL; 1800 1801 if (cpy && !rflg) { 1802 (void) fprintf(stderr, 1803 gettext("%s: %s: is a directory\n"), cmd, source); 1804 return (1); 1805 } 1806 1807 if (stat(target, &s2) < 0) { 1808 if (mkdir(target, (s1.st_mode & MODEBITS)) < 0) { 1809 (void) fprintf(stderr, "%s: ", cmd); 1810 perror(target); 1811 return (1); 1812 } 1813 if (stat(target, &s2) == 0) { 1814 fixmode = s2.st_mode; 1815 } else { 1816 fixmode = s1.st_mode; 1817 } 1818 (void) chmod(target, ((fixmode & MODEBITS) | S_IRWXU)); 1819 } else if (!(ISDIR(s2))) { 1820 (void) fprintf(stderr, 1821 gettext("%s: %s: not a directory.\n"), cmd, target); 1822 return (1); 1823 } 1824 if (pflg || mve) { 1825 /* 1826 * Save s1 (stat information for source dir) and acl info, 1827 * if any, so that ownership, modes, times, and acl's can 1828 * be reserved during "cp -p" or mv. 1829 * s1 gets overwritten when doing the recursive copy. 1830 */ 1831 s1save = s1; 1832 if (s1acl != NULL) { 1833 s1acl_save = acl_dup(s1acl); 1834 if (s1acl_save == NULL) { 1835 (void) fprintf(stderr, gettext("%s: " 1836 "Insufficient memory to save acl" 1837 " entry\n"), cmd); 1838 if (pflg) 1839 return (1); 1840 1841 } 1842 #ifdef XPG4 1843 else { 1844 (void) fprintf(stderr, gettext("%s: " 1845 "Insufficient memory to save acl" 1846 " entry\n"), cmd); 1847 if (pflg) 1848 return (1); 1849 } 1850 #endif 1851 } 1852 } 1853 1854 ret = rcopy(source, target); 1855 1856 /* 1857 * Once we created a directory, go ahead and set 1858 * its attributes, e.g. acls and time. The info 1859 * may get overwritten if we continue traversing 1860 * down the tree. 1861 * 1862 * ACL for directory 1863 */ 1864 if (pflg || mve) { 1865 if ((pret = chg_mode(target, UID(s1save), GID(s1save), 1866 FMODE(s1save))) == 0) 1867 pret = chg_time(target, s1save); 1868 ret += pret; 1869 if (s1acl_save != NULL) { 1870 if (acl_set(target, s1acl_save) < 0) { 1871 error++; 1872 #ifdef XPG4 1873 if (pflg || mve) { 1874 #else 1875 if (pflg) { 1876 #endif 1877 (void) fprintf(stderr, gettext( 1878 "%s: failed to set acl entries " 1879 "on %s\n"), cmd, target); 1880 if (pflg) { 1881 acl_free(s1acl_save); 1882 s1acl_save = NULL; 1883 ret++; 1884 } 1885 } 1886 /* else: silent and continue */ 1887 } 1888 acl_free(s1acl_save); 1889 s1acl_save = NULL; 1890 } 1891 } else if (fixmode != (mode_t)0) 1892 (void) chmod(target, fixmode & MODEBITS); 1893 1894 if (pflg || atflg || mve || saflg) { 1895 attret = copyattributes(source, target); 1896 if (!attrsilent && attret != 0) { 1897 (void) fprintf(stderr, gettext("%s: Failed to preserve" 1898 " extended attributes of directory" 1899 " %s\n"), cmd, source); 1900 } else { 1901 /* 1902 * Otherwise ignore failure. 1903 */ 1904 attret = 0; 1905 } 1906 /* Copy extended system attributes */ 1907 if (pflg || mve || saflg) { 1908 sattret = copy_sysattr(source, target); 1909 if (sattret != 0) { 1910 (void) fprintf(stderr, gettext( 1911 "%s: Failed to preserve " 1912 "extended system attributes " 1913 "of directory %s\n"), cmd, source); 1914 } 1915 } 1916 } 1917 if (attret != 0 || sattret != 0 || error != 0) 1918 return (1); 1919 return (ret); 1920 } 1921 1922 static int 1923 copyspecial(const char *target) 1924 { 1925 int ret = 0; 1926 1927 if (mknod(target, s1.st_mode, s1.st_rdev) != 0) { 1928 (void) fprintf(stderr, gettext( 1929 "cp: cannot create special file %s: "), target); 1930 perror(""); 1931 return (1); 1932 } 1933 1934 if (pflg) { 1935 if ((ret = chg_mode(target, UID(s1), GID(s1), FMODE(s1))) == 0) 1936 ret = chg_time(target, s1); 1937 } 1938 1939 return (ret); 1940 } 1941 1942 static int 1943 use_stdin(void) 1944 { 1945 #ifdef XPG4 1946 return (1); 1947 #else 1948 return (isatty(fileno(stdin))); 1949 #endif 1950 } 1951 1952 /* Copy non-system extended attributes */ 1953 1954 static int 1955 copyattributes(const char *source, const char *target) 1956 { 1957 struct dirent *dp; 1958 int error = 0; 1959 int aclerror; 1960 mode_t mode; 1961 int clearflg = 0; 1962 acl_t *xacl = NULL; 1963 acl_t *attrdiracl = NULL; 1964 struct timespec times[2]; 1965 1966 1967 if (pathconf(source, _PC_XATTR_EXISTS) != 1) 1968 return (0); 1969 1970 if (pathconf(target, _PC_XATTR_ENABLED) != 1) { 1971 if (!attrsilent) { 1972 (void) fprintf(stderr, 1973 gettext( 1974 "%s: cannot preserve extended attributes, " 1975 "operation not supported on file" 1976 " %s\n"), cmd, target); 1977 } 1978 return (1); 1979 } 1980 if (open_source(source) != 0) 1981 return (1); 1982 if (open_target_srctarg_attrdirs(source, target) != 0) 1983 return (1); 1984 if (open_attrdirp(source) != 0) 1985 return (1); 1986 1987 if (pflg || mve) { 1988 if (fchmod(targetdirfd, attrdir.st_mode) == -1) { 1989 if (!attrsilent) { 1990 (void) fprintf(stderr, 1991 gettext("%s: failed to set file mode" 1992 " correctly on attribute directory of" 1993 " file %s: "), cmd, target); 1994 perror(""); 1995 ++error; 1996 } 1997 } 1998 1999 if (fchown(targetdirfd, attrdir.st_uid, attrdir.st_gid) == -1) { 2000 if (!attrsilent) { 2001 (void) fprintf(stderr, 2002 gettext("%s: failed to set file" 2003 " ownership correctly on attribute" 2004 " directory of file %s: "), cmd, target); 2005 perror(""); 2006 ++error; 2007 } 2008 } 2009 /* 2010 * Now that we are the owner we can update st_ctime by calling 2011 * utimensat. 2012 */ 2013 times[0] = attrdir.st_atim; 2014 times[1] = attrdir.st_mtim; 2015 if (utimensat(targetdirfd, ".", times, 0) < 0) { 2016 if (!attrsilent) { 2017 (void) fprintf(stderr, 2018 gettext("%s: cannot set attribute times" 2019 " for %s: "), cmd, target); 2020 perror(""); 2021 ++error; 2022 } 2023 } 2024 2025 /* 2026 * Now set owner and group of attribute directory, implies 2027 * changing the ACL of the hidden attribute directory first. 2028 */ 2029 if ((aclerror = facl_get(sourcedirfd, 2030 ACL_NO_TRIVIAL, &attrdiracl)) != 0) { 2031 if (!attrsilent) { 2032 (void) fprintf(stderr, gettext( 2033 "%s: failed to get acl entries of" 2034 " attribute directory for" 2035 " %s : %s\n"), cmd, 2036 source, acl_strerror(aclerror)); 2037 ++error; 2038 } 2039 } 2040 2041 if (attrdiracl) { 2042 if (facl_set(targetdirfd, attrdiracl) != 0) { 2043 if (!attrsilent) { 2044 (void) fprintf(stderr, gettext( 2045 "%s: failed to set acl entries" 2046 " on attribute directory " 2047 "for %s\n"), cmd, target); 2048 ++error; 2049 } 2050 acl_free(attrdiracl); 2051 attrdiracl = NULL; 2052 } 2053 } 2054 } 2055 2056 while ((dp = readdir(srcdirp)) != NULL) { 2057 int ret; 2058 2059 if ((ret = traverse_attrfile(dp, source, target, 1)) == -1) 2060 continue; 2061 else if (ret > 0) { 2062 ++error; 2063 goto out; 2064 } 2065 2066 if (pflg || mve) { 2067 if ((aclerror = facl_get(srcattrfd, 2068 ACL_NO_TRIVIAL, &xacl)) != 0) { 2069 if (!attrsilent) { 2070 (void) fprintf(stderr, gettext( 2071 "%s: failed to get acl entries of" 2072 " attribute %s for" 2073 " %s: %s"), cmd, dp->d_name, 2074 source, acl_strerror(aclerror)); 2075 ++error; 2076 } 2077 } 2078 } 2079 2080 /* 2081 * preserve ACL 2082 */ 2083 if ((pflg || mve) && xacl != NULL) { 2084 if ((facl_set(targattrfd, xacl)) < 0) { 2085 if (!attrsilent) { 2086 (void) fprintf(stderr, gettext( 2087 "%s: failed to set acl entries on" 2088 " attribute %s for" 2089 "%s\n"), cmd, dp->d_name, target); 2090 ++error; 2091 } 2092 acl_free(xacl); 2093 xacl = NULL; 2094 } 2095 } 2096 2097 if (writefile(srcattrfd, targattrfd, source, target, 2098 dp->d_name, dp->d_name, &s3, &s4) != 0) { 2099 if (!attrsilent) { 2100 ++error; 2101 } 2102 goto next; 2103 } 2104 2105 if (pflg || mve) { 2106 mode = FMODE(s3); 2107 2108 if (fchown(targattrfd, UID(s3), GID(s3)) != 0) { 2109 if (!attrsilent) { 2110 (void) fprintf(stderr, 2111 gettext("%s: cannot change" 2112 " owner and group of" 2113 " attribute %s for" " file" 2114 " %s: "), cmd, dp->d_name, target); 2115 perror(""); 2116 ++error; 2117 } 2118 if (mode & (S_ISUID | S_ISGID)) { 2119 /* try to clear S_ISUID and S_ISGID */ 2120 mode &= ~S_ISUID & ~S_ISGID; 2121 ++clearflg; 2122 } 2123 } 2124 times[0] = s3.st_atim; 2125 times[1] = s3.st_mtim; 2126 if (utimensat(targetdirfd, dp->d_name, times, 0) < 0) { 2127 if (!attrsilent) { 2128 (void) fprintf(stderr, 2129 gettext("%s: cannot set attribute" 2130 " times for %s: "), cmd, target); 2131 perror(""); 2132 ++error; 2133 } 2134 } 2135 if (fchmod(targattrfd, mode) != 0) { 2136 if (clearflg) { 2137 (void) fprintf(stderr, gettext( 2138 "%s: cannot clear S_ISUID and " 2139 "S_ISGID bits in attribute %s" 2140 " for file" 2141 " %s: "), cmd, dp->d_name, target); 2142 } else { 2143 if (!attrsilent) { 2144 (void) fprintf(stderr, 2145 gettext( 2146 "%s: cannot set permissions of attribute" 2147 " %s for %s: "), cmd, dp->d_name, target); 2148 perror(""); 2149 ++error; 2150 } 2151 } 2152 } 2153 if (xacl && ((facl_set(targattrfd, xacl)) < 0)) { 2154 if (!attrsilent) { 2155 (void) fprintf(stderr, gettext( 2156 "%s: failed to set acl entries on" 2157 " attribute %s for" 2158 "%s\n"), cmd, dp->d_name, target); 2159 ++error; 2160 } 2161 acl_free(xacl); 2162 xacl = NULL; 2163 } 2164 } 2165 next: 2166 if (xacl != NULL) { 2167 acl_free(xacl); 2168 xacl = NULL; 2169 } 2170 if (srcattrfd != -1) 2171 (void) close(srcattrfd); 2172 if (targattrfd != -1) 2173 (void) close(targattrfd); 2174 srcattrfd = targattrfd = -1; 2175 } 2176 out: 2177 if (xacl != NULL) { 2178 acl_free(xacl); 2179 xacl = NULL; 2180 } 2181 if (attrdiracl != NULL) { 2182 acl_free(attrdiracl); 2183 attrdiracl = NULL; 2184 } 2185 2186 if (!saflg && !pflg && !mve) 2187 close_all(); 2188 return (error == 0 ? 0 : 1); 2189 } 2190 2191 /* Copy extended system attributes from source to target */ 2192 2193 static int 2194 copy_sysattr(const char *source, const char *target) 2195 { 2196 struct dirent *dp; 2197 nvlist_t *response; 2198 int error = 0; 2199 int target_sa_support = 0; 2200 2201 if (sysattr_support(source, _PC_SATTR_EXISTS) != 1) 2202 return (0); 2203 2204 if (open_source(source) != 0) 2205 return (1); 2206 2207 /* 2208 * Gets non default extended system attributes from the 2209 * source file to copy to the target. The target has 2210 * the defaults set when its created and thus no need 2211 * to copy the defaults. 2212 */ 2213 response = sysattr_list(cmd, srcfd, source); 2214 2215 if (sysattr_support(target, _PC_SATTR_ENABLED) != 1) { 2216 if (response != NULL) { 2217 (void) fprintf(stderr, 2218 gettext( 2219 "%s: cannot preserve extended system " 2220 "attribute, operation not supported on file" 2221 " %s\n"), cmd, target); 2222 error++; 2223 goto out; 2224 } 2225 } else { 2226 target_sa_support = 1; 2227 } 2228 2229 if (target_sa_support) { 2230 if (srcdirp == NULL) { 2231 if (open_target_srctarg_attrdirs(source, 2232 target) != 0) { 2233 error++; 2234 goto out; 2235 } 2236 if (open_attrdirp(source) != 0) { 2237 error++; 2238 goto out; 2239 } 2240 } else { 2241 rewind_attrdir(srcdirp); 2242 } 2243 while ((dp = readdir(srcdirp)) != NULL) { 2244 nvlist_t *res; 2245 int ret; 2246 2247 if ((ret = traverse_attrfile(dp, source, target, 2248 0)) == -1) 2249 continue; 2250 else if (ret > 0) { 2251 ++error; 2252 goto out; 2253 } 2254 /* 2255 * Gets non default extended system attributes from the 2256 * attribute file to copy to the target. The target has 2257 * the defaults set when its created and thus no need 2258 * to copy the defaults. 2259 */ 2260 res = sysattr_list(cmd, srcattrfd, dp->d_name); 2261 if (res == NULL) 2262 goto next; 2263 2264 /* 2265 * Copy non default extended system attributes of named 2266 * attribute file. 2267 */ 2268 if (fsetattr(targattrfd, 2269 XATTR_VIEW_READWRITE, res) != 0) { 2270 ++error; 2271 (void) fprintf(stderr, gettext("%s: " 2272 "Failed to copy extended system " 2273 "attributes from attribute file " 2274 "%s of %s to %s\n"), cmd, 2275 dp->d_name, source, target); 2276 } 2277 2278 next: 2279 if (srcattrfd != -1) 2280 (void) close(srcattrfd); 2281 if (targattrfd != -1) 2282 (void) close(targattrfd); 2283 srcattrfd = targattrfd = -1; 2284 nvlist_free(res); 2285 } 2286 } 2287 /* Copy source file non default extended system attributes to target */ 2288 if (target_sa_support && (response != NULL) && 2289 (fsetattr(targfd, XATTR_VIEW_READWRITE, response)) != 0) { 2290 ++error; 2291 (void) fprintf(stderr, gettext("%s: Failed to " 2292 "copy extended system attributes from " 2293 "%s to %s\n"), cmd, source, target); 2294 } 2295 out: 2296 nvlist_free(response); 2297 close_all(); 2298 return (error == 0 ? 0 : 1); 2299 } 2300 2301 /* Open the source file */ 2302 2303 static int 2304 open_source(const char *src) 2305 { 2306 int error = 0; 2307 2308 srcfd = -1; 2309 if ((srcfd = open(src, O_RDONLY)) == -1) { 2310 if (pflg && attrsilent) { 2311 error++; 2312 goto out; 2313 } 2314 if (!attrsilent) { 2315 (void) fprintf(stderr, 2316 gettext("%s: cannot open file" 2317 " %s: "), cmd, src); 2318 perror(""); 2319 } 2320 ++error; 2321 } 2322 out: 2323 if (error) 2324 close_all(); 2325 return (error == 0 ? 0 : 1); 2326 } 2327 2328 /* Open source attribute dir, target and target attribute dir. */ 2329 2330 static int 2331 open_target_srctarg_attrdirs(const char *src, const char *targ) 2332 { 2333 int error = 0; 2334 2335 targfd = sourcedirfd = targetdirfd = -1; 2336 2337 if ((targfd = open(targ, O_RDONLY)) == -1) { 2338 if (pflg && attrsilent) { 2339 error++; 2340 goto out; 2341 } 2342 if (!attrsilent) { 2343 (void) fprintf(stderr, 2344 gettext("%s: cannot open file" 2345 " %s: "), cmd, targ); 2346 perror(""); 2347 } 2348 ++error; 2349 goto out; 2350 } 2351 2352 if ((sourcedirfd = openat(srcfd, ".", O_RDONLY|O_XATTR)) == -1) { 2353 if (pflg && attrsilent) { 2354 error++; 2355 goto out; 2356 } 2357 if (!attrsilent) { 2358 (void) fprintf(stderr, 2359 gettext("%s: cannot open attribute" 2360 " directory for %s: "), cmd, src); 2361 perror(""); 2362 } 2363 ++error; 2364 goto out; 2365 } 2366 2367 if (fstat(sourcedirfd, &attrdir) == -1) { 2368 if (pflg && attrsilent) { 2369 error++; 2370 goto out; 2371 } 2372 2373 if (!attrsilent) { 2374 (void) fprintf(stderr, 2375 gettext("%s: could not retrieve stat" 2376 " information for attribute directory" 2377 "of file %s: "), cmd, src); 2378 perror(""); 2379 } 2380 ++error; 2381 goto out; 2382 } 2383 if ((targetdirfd = openat(targfd, ".", O_RDONLY|O_XATTR)) == -1) { 2384 if (pflg && attrsilent) { 2385 error++; 2386 goto out; 2387 } 2388 if (!attrsilent) { 2389 (void) fprintf(stderr, 2390 gettext("%s: cannot open attribute" 2391 " directory for %s: "), cmd, targ); 2392 perror(""); 2393 } 2394 ++error; 2395 } 2396 out: 2397 if (error) 2398 close_all(); 2399 return (error == 0 ? 0 : 1); 2400 } 2401 2402 static int 2403 open_attrdirp(const char *source) 2404 { 2405 int tmpfd = -1; 2406 int error = 0; 2407 2408 /* 2409 * dup sourcedirfd for use by fdopendir(). 2410 * fdopendir will take ownership of given fd and will close 2411 * it when closedir() is called. 2412 */ 2413 2414 if ((tmpfd = dup(sourcedirfd)) == -1) { 2415 if (pflg && attrsilent) { 2416 error++; 2417 goto out; 2418 } 2419 if (!attrsilent) { 2420 (void) fprintf(stderr, 2421 gettext( 2422 "%s: unable to dup attribute directory" 2423 " file descriptor for %s: "), cmd, source); 2424 perror(""); 2425 ++error; 2426 } 2427 goto out; 2428 } 2429 if ((srcdirp = fdopendir(tmpfd)) == NULL) { 2430 if (pflg && attrsilent) { 2431 error++; 2432 goto out; 2433 } 2434 if (!attrsilent) { 2435 (void) fprintf(stderr, 2436 gettext("%s: failed to open attribute" 2437 " directory for %s: "), cmd, source); 2438 perror(""); 2439 ++error; 2440 } 2441 } 2442 out: 2443 if (error) 2444 close_all(); 2445 return (error == 0 ? 0 : 1); 2446 } 2447 2448 /* Skips through ., .., and system attribute 'view' files */ 2449 static int 2450 traverse_attrfile(struct dirent *dp, const char *source, const char *target, 2451 int first) 2452 { 2453 int error = 0; 2454 2455 srcattrfd = targattrfd = -1; 2456 2457 if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') || 2458 (dp->d_name[0] == '.' && dp->d_name[1] == '.' && 2459 dp->d_name[2] == '\0') || 2460 (sysattr_type(dp->d_name) == _RO_SATTR) || 2461 (sysattr_type(dp->d_name) == _RW_SATTR)) 2462 return (-1); 2463 2464 if ((srcattrfd = openat(sourcedirfd, dp->d_name, 2465 O_RDONLY)) == -1) { 2466 if (!attrsilent) { 2467 (void) fprintf(stderr, 2468 gettext("%s: cannot open attribute %s on" 2469 " file %s: "), cmd, dp->d_name, source); 2470 perror(""); 2471 ++error; 2472 goto out; 2473 } 2474 } 2475 2476 if (fstat(srcattrfd, &s3) < 0) { 2477 if (!attrsilent) { 2478 (void) fprintf(stderr, 2479 gettext("%s: could not stat attribute" 2480 " %s on file" 2481 " %s: "), cmd, dp->d_name, source); 2482 perror(""); 2483 ++error; 2484 } 2485 goto out; 2486 } 2487 2488 if (first) { 2489 (void) unlinkat(targetdirfd, dp->d_name, 0); 2490 if ((targattrfd = openat(targetdirfd, dp->d_name, 2491 O_RDWR|O_CREAT|O_TRUNC, s3.st_mode & MODEBITS)) == -1) { 2492 if (!attrsilent) { 2493 (void) fprintf(stderr, 2494 gettext("%s: could not create attribute" 2495 " %s on file %s: "), cmd, dp->d_name, 2496 target); 2497 perror(""); 2498 ++error; 2499 } 2500 goto out; 2501 } 2502 } else { 2503 if ((targattrfd = openat(targetdirfd, dp->d_name, 2504 O_RDONLY)) == -1) { 2505 if (!attrsilent) { 2506 (void) fprintf(stderr, 2507 gettext("%s: could not open attribute" 2508 " %s on file %s: "), cmd, dp->d_name, 2509 target); 2510 perror(""); 2511 ++error; 2512 } 2513 goto out; 2514 } 2515 } 2516 2517 2518 if (fstat(targattrfd, &s4) < 0) { 2519 if (!attrsilent) { 2520 (void) fprintf(stderr, 2521 gettext("%s: could not stat attribute" 2522 " %s on file" 2523 " %s: "), cmd, dp->d_name, target); 2524 perror(""); 2525 ++error; 2526 } 2527 } 2528 2529 out: 2530 if (error) { 2531 if (srcattrfd != -1) 2532 (void) close(srcattrfd); 2533 if (targattrfd != -1) 2534 (void) close(targattrfd); 2535 srcattrfd = targattrfd = -1; 2536 } 2537 return (error == 0 ? 0 :1); 2538 } 2539 2540 static void 2541 rewind_attrdir(DIR * sdp) 2542 { 2543 int pwdfd; 2544 2545 pwdfd = open(".", O_RDONLY); 2546 if ((pwdfd != -1) && (fchdir(sourcedirfd) == 0)) { 2547 rewinddir(sdp); 2548 (void) fchdir(pwdfd); 2549 (void) close(pwdfd); 2550 } else { 2551 if (!attrsilent) { 2552 (void) fprintf(stderr, gettext("%s: " 2553 "failed to rewind attribute dir\n"), 2554 cmd); 2555 } 2556 } 2557 } 2558 2559 static void 2560 close_all(void) 2561 { 2562 if (srcattrfd != -1) 2563 (void) close(srcattrfd); 2564 if (targattrfd != -1) 2565 (void) close(targattrfd); 2566 if (sourcedirfd != -1) 2567 (void) close(sourcedirfd); 2568 if (targetdirfd != -1) 2569 (void) close(targetdirfd); 2570 if (srcdirp != NULL) { 2571 (void) closedir(srcdirp); 2572 srcdirp = NULL; 2573 } 2574 if (srcfd != -1) 2575 (void) close(srcfd); 2576 if (targfd != -1) 2577 (void) close(targfd); 2578 } 2579