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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 /* 43 * Combined mv/cp/ln command: 44 * mv file1 file2 45 * mv dir1 dir2 46 * mv file1 ... filen dir1 47 */ 48 #include <stdio.h> 49 #include <sys/types.h> 50 #include <sys/stat.h> 51 #include <sys/avl.h> 52 #include <sys/mman.h> 53 #include <fcntl.h> 54 #include <sys/time.h> 55 #include <signal.h> 56 #include <errno.h> 57 #include <dirent.h> 58 #include <stdlib.h> 59 #include <locale.h> 60 #include <langinfo.h> 61 #include <stdarg.h> 62 #include <string.h> 63 #include <unistd.h> 64 #include <limits.h> 65 #include <sys/acl.h> 66 #include <libcmdutils.h> 67 #include <aclutils.h> 68 69 #define FTYPE(A) (A.st_mode) 70 #define FMODE(A) (A.st_mode) 71 #define UID(A) (A.st_uid) 72 #define GID(A) (A.st_gid) 73 #define IDENTICAL(A, B) (A.st_dev == B.st_dev && A.st_ino == B.st_ino) 74 #define ISBLK(A) ((A.st_mode & S_IFMT) == S_IFBLK) 75 #define ISCHR(A) ((A.st_mode & S_IFMT) == S_IFCHR) 76 #define ISDIR(A) ((A.st_mode & S_IFMT) == S_IFDIR) 77 #define ISDOOR(A) ((A.st_mode & S_IFMT) == S_IFDOOR) 78 #define ISFIFO(A) ((A.st_mode & S_IFMT) == S_IFIFO) 79 #define ISLNK(A) ((A.st_mode & S_IFMT) == S_IFLNK) 80 #define ISREG(A) (((A).st_mode & S_IFMT) == S_IFREG) 81 #define ISDEV(A) ((A.st_mode & S_IFMT) == S_IFCHR || \ 82 (A.st_mode & S_IFMT) == S_IFBLK || \ 83 (A.st_mode & S_IFMT) == S_IFIFO) 84 85 #define BLKSIZE 4096 86 #define PATHSIZE 1024 87 #define DOT "." 88 #define DOTDOT ".." 89 #define DELIM '/' 90 #define EQ(x, y) (strcmp(x, y) == 0) 91 #define FALSE 0 92 #define MODEBITS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) 93 #define TRUE 1 94 #define MAXMAPSIZE (1024*1024*8) /* map at most 8MB */ 95 #define SMALLFILESIZE (32*1024) /* don't use mmap on little files */ 96 97 static char *dname(char *); 98 static int getresp(void); 99 static int lnkfil(char *, char *); 100 static int cpymve(char *, char *); 101 static int chkfiles(char *, char **); 102 static int rcopy(char *, char *); 103 static int chk_different(char *, char *); 104 static int chg_time(char *, struct stat); 105 static int chg_mode(char *, uid_t, gid_t, mode_t); 106 static int copydir(char *, char *); 107 static int copyspecial(char *); 108 static int getrealpath(char *, char *); 109 static void usage(void); 110 static void Perror(char *); 111 static void Perror2(char *, char *); 112 static int writefile(int, int, char *, char *, 113 struct stat *, struct stat *); 114 static int use_stdin(void); 115 static int copyattributes(char *, char *); 116 static void timestruc_to_timeval(timestruc_t *, struct timeval *); 117 static tree_node_t *create_tnode(dev_t, ino_t); 118 119 extern int errno; 120 extern char *optarg; 121 extern int optind, opterr; 122 static struct stat s1, s2; 123 static int cpy = FALSE; 124 static int mve = FALSE; 125 static int lnk = FALSE; 126 static char *cmd; 127 static int silent = 0; 128 static int fflg = 0; 129 static int iflg = 0; 130 static int pflg = 0; 131 static int Rflg = 0; /* recursive copy */ 132 static int rflg = 0; /* recursive copy */ 133 static int sflg = 0; 134 static int Hflg = 0; /* follow cmd line arg symlink to dir */ 135 static int Lflg = 0; /* follow symlinks */ 136 static int Pflg = 0; /* do not follow symlinks */ 137 static int atflg = 0; 138 static int attrsilent = 0; 139 static int targetexists = 0; 140 static char yeschr[SCHAR_MAX + 2]; 141 static char nochr[SCHAR_MAX + 2]; 142 static int cmdarg; /* command line argument */ 143 static avl_tree_t *stree = NULL; /* source file inode search tree */ 144 static acl_t *s1acl; 145 146 int 147 main(int argc, char *argv[]) 148 { 149 int c, i, r, errflg = 0; 150 char target[PATH_MAX]; 151 int (*move)(char *, char *); 152 153 /* 154 * Determine command invoked (mv, cp, or ln) 155 */ 156 157 if (cmd = strrchr(argv[0], '/')) 158 ++cmd; 159 else 160 cmd = argv[0]; 161 162 /* 163 * Set flags based on command. 164 */ 165 166 (void) setlocale(LC_ALL, ""); 167 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 168 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 169 #endif 170 (void) textdomain(TEXT_DOMAIN); 171 172 (void) strncpy(yeschr, nl_langinfo(YESSTR), SCHAR_MAX + 2); 173 (void) strncpy(nochr, nl_langinfo(NOSTR), SCHAR_MAX + 2); 174 175 if (EQ(cmd, "mv")) 176 mve = TRUE; 177 else if (EQ(cmd, "ln")) 178 lnk = TRUE; 179 else if (EQ(cmd, "cp")) 180 cpy = TRUE; 181 else { 182 (void) fprintf(stderr, 183 gettext("Invalid command name (%s); expecting " 184 "mv, cp, or ln.\n"), cmd); 185 exit(1); 186 } 187 188 /* 189 * Check for options: 190 * cp -r|-R [-H|-L|-P] [-fip@] file1 [file2 ...] target 191 * cp [-fiprR@] file1 [file2 ...] target 192 * ln [-f] [-n] [-s] file1 [file2 ...] target 193 * ln [-f] [-n] [-s] file1 [file2 ...] 194 * mv [-f|i] file1 [file2 ...] target 195 * mv [-f|i] dir1 target 196 */ 197 198 if (cpy) { 199 while ((c = getopt(argc, argv, "fHiLpPrR@")) != EOF) 200 switch (c) { 201 case 'f': 202 fflg++; 203 break; 204 case 'i': 205 iflg++; 206 break; 207 case 'p': 208 pflg++; 209 #ifdef XPG4 210 attrsilent = 1; 211 atflg = 0; 212 #else 213 if (atflg == 0) 214 attrsilent = 1; 215 #endif 216 break; 217 case 'H': 218 /* 219 * If more than one of -H, -L, or -P are 220 * specified, only the last option specified 221 * determines the behavior. 222 */ 223 Lflg = Pflg = 0; 224 Hflg++; 225 break; 226 case 'L': 227 Hflg = Pflg = 0; 228 Lflg++; 229 break; 230 case 'P': 231 Lflg = Hflg = 0; 232 Pflg++; 233 break; 234 case 'R': 235 /* 236 * The default behavior of cp -R|-r 237 * when specified without -H|-L|-P 238 * is -L. 239 */ 240 Rflg++; 241 /*FALLTHROUGH*/ 242 case 'r': 243 rflg++; 244 break; 245 case '@': 246 atflg++; 247 attrsilent = 0; 248 #ifdef XPG4 249 pflg = 0; 250 #endif 251 break; 252 default: 253 errflg++; 254 } 255 256 /* -R or -r must be specified with -H, -L, or -P */ 257 if ((Hflg || Lflg || Pflg) && !(Rflg || rflg)) { 258 errflg++; 259 } 260 261 } else if (mve) { 262 while ((c = getopt(argc, argv, "fis")) != EOF) 263 switch (c) { 264 case 'f': 265 silent++; 266 #ifdef XPG4 267 iflg = 0; 268 #endif 269 break; 270 case 'i': 271 iflg++; 272 #ifdef XPG4 273 silent = 0; 274 #endif 275 break; 276 default: 277 errflg++; 278 } 279 } else { /* ln */ 280 while ((c = getopt(argc, argv, "fns")) != EOF) 281 switch (c) { 282 case 'f': 283 silent++; 284 break; 285 case 'n': 286 /* silently ignored; this is the default */ 287 break; 288 case 's': 289 sflg++; 290 break; 291 default: 292 errflg++; 293 } 294 } 295 296 /* 297 * For BSD compatibility allow - to delimit the end of 298 * options for mv. 299 */ 300 if (mve && optind < argc && (strcmp(argv[optind], "-") == 0)) 301 optind++; 302 303 /* 304 * Check for sufficient arguments 305 * or a usage error. 306 */ 307 308 argc -= optind; 309 argv = &argv[optind]; 310 311 if ((argc < 2 && lnk != TRUE) || (argc < 1 && lnk == TRUE)) { 312 (void) fprintf(stderr, 313 gettext("%s: Insufficient arguments (%d)\n"), 314 cmd, argc); 315 usage(); 316 } 317 318 if (errflg != 0) 319 usage(); 320 321 /* 322 * If there is more than a source and target, 323 * the last argument (the target) must be a directory 324 * which really exists. 325 */ 326 327 if (argc > 2) { 328 if (stat(argv[argc-1], &s2) < 0) { 329 (void) fprintf(stderr, 330 gettext("%s: %s not found\n"), 331 cmd, argv[argc-1]); 332 exit(2); 333 } 334 335 if (!ISDIR(s2)) { 336 (void) fprintf(stderr, 337 gettext("%s: Target %s must be a directory\n"), 338 cmd, argv[argc-1]); 339 usage(); 340 } 341 } 342 343 if (strlen(argv[argc-1]) >= PATH_MAX) { 344 (void) fprintf(stderr, 345 gettext("%s: Target %s file name length exceeds PATH_MAX" 346 " %d\n"), cmd, argv[argc-1], PATH_MAX); 347 exit(78); 348 } 349 350 if (argc == 1) { 351 if (!lnk) 352 usage(); 353 (void) strcpy(target, "."); 354 } else { 355 (void) strcpy(target, argv[--argc]); 356 } 357 358 /* 359 * Perform a multiple argument mv|cp|ln by 360 * multiple invocations of cpymve() or lnkfil(). 361 */ 362 if (lnk) 363 move = lnkfil; 364 else 365 move = cpymve; 366 367 r = 0; 368 for (i = 0; i < argc; i++) { 369 stree = NULL; 370 cmdarg = 1; 371 r += move(argv[i], target); 372 } 373 374 /* 375 * Show errors by nonzero exit code. 376 */ 377 378 return (r?2:0); 379 } 380 381 static int 382 lnkfil(char *source, char *target) 383 { 384 char *buf = NULL; 385 386 if (sflg) { 387 388 /* 389 * If target is a directory make complete 390 * name of the new symbolic link within that 391 * directory. 392 */ 393 394 if ((stat(target, &s2) >= 0) && ISDIR(s2)) { 395 size_t len; 396 397 len = strlen(target) + strlen(dname(source)) + 4; 398 if ((buf = (char *)malloc(len)) == NULL) { 399 (void) fprintf(stderr, 400 gettext("%s: Insufficient memory " 401 "to %s %s\n"), cmd, cmd, source); 402 exit(3); 403 } 404 (void) snprintf(buf, len, "%s/%s", 405 target, dname(source)); 406 target = buf; 407 } 408 409 /* 410 * Check to see if the file exists already 411 */ 412 413 if ((stat(target, &s2) == 0)) { 414 /* 415 * Check if the silent flag is set ie. the -f option 416 * is used. If so, use unlink to remove the current 417 * target to replace with the new target, specified 418 * on the command line. Proceed with symlink. 419 */ 420 if (silent) { 421 if (unlink(target) < 0) { 422 (void) fprintf(stderr, 423 gettext("%s: cannot unlink %s: "), 424 cmd, target); 425 perror(""); 426 return (1); 427 } 428 } 429 } 430 431 432 /* 433 * Create a symbolic link to the source. 434 */ 435 436 if (symlink(source, target) < 0) { 437 (void) fprintf(stderr, 438 gettext("%s: cannot create %s: "), 439 cmd, target); 440 perror(""); 441 if (buf != NULL) 442 free(buf); 443 return (1); 444 } 445 if (buf != NULL) 446 free(buf); 447 return (0); 448 } 449 450 switch (chkfiles(source, &target)) { 451 case 1: return (1); 452 case 2: return (0); 453 /* default - fall through */ 454 } 455 456 /* 457 * Make sure source file is not a directory, 458 * we can't link directories... 459 */ 460 461 if (ISDIR(s1)) { 462 (void) fprintf(stderr, 463 gettext("%s: %s is a directory\n"), cmd, source); 464 return (1); 465 } 466 467 /* 468 * hard link, call link() and return. 469 */ 470 471 if (link(source, target) < 0) { 472 if (errno == EXDEV) 473 (void) fprintf(stderr, 474 gettext("%s: %s is on a different file system\n"), 475 cmd, target); 476 else { 477 (void) fprintf(stderr, 478 gettext("%s: cannot create link %s: "), 479 cmd, target); 480 perror(""); 481 } 482 if (buf != NULL) 483 free(buf); 484 return (1); 485 } else { 486 if (buf != NULL) 487 free(buf); 488 return (0); 489 } 490 } 491 492 static int 493 cpymve(char *source, char *target) 494 { 495 int n; 496 int fi, fo; 497 int ret = 0; 498 int attret = 0; 499 int errno_save; 500 501 switch (chkfiles(source, &target)) { 502 case 1: return (1); 503 case 2: return (0); 504 /* default - fall through */ 505 } 506 507 /* 508 * If it's a recursive copy and source 509 * is a directory, then call rcopy (from copydir). 510 */ 511 if (cpy) { 512 if (ISDIR(s1)) { 513 int rc; 514 avl_index_t where = 0; 515 tree_node_t *tnode; 516 tree_node_t *tptr; 517 dev_t save_dev = s1.st_dev; 518 ino_t save_ino = s1.st_ino; 519 520 /* 521 * We will be recursing into the directory so 522 * save the inode information to a search tree 523 * to avoid getting into an endless loop. 524 */ 525 if ((rc = add_tnode(&stree, save_dev, save_ino)) != 1) { 526 if (rc == 0) { 527 /* 528 * We've already visited this directory. 529 * Don't remove the search tree entry 530 * to make sure we don't get into an 531 * endless loop if revisited from a 532 * different part of the hierarchy. 533 */ 534 (void) fprintf(stderr, gettext( 535 "%s: cycle detected: %s\n"), 536 cmd, source); 537 } else { 538 Perror(source); 539 } 540 return (1); 541 } 542 543 cmdarg = 0; 544 rc = copydir(source, target); 545 546 /* 547 * Create a tnode to get an index to the matching 548 * node (same dev and inode) in the search tree, 549 * then use the index to remove the matching node 550 * so it we do not wrongly detect a cycle when 551 * revisiting this directory from another part of 552 * the hierarchy. 553 */ 554 if ((tnode = create_tnode(save_dev, 555 save_ino)) == NULL) { 556 Perror(source); 557 return (1); 558 } 559 if ((tptr = avl_find(stree, tnode, &where)) != NULL) { 560 avl_remove(stree, tptr); 561 } 562 free(tptr); 563 free(tnode); 564 return (rc); 565 566 } else if (ISDEV(s1) && Rflg) { 567 return (copyspecial(target)); 568 } else { 569 goto copy; 570 } 571 } 572 573 if (mve) { 574 if (rename(source, target) >= 0) 575 return (0); 576 if (errno != EXDEV) { 577 if (errno == ENOTDIR && ISDIR(s1)) { 578 (void) fprintf(stderr, 579 gettext("%s: %s is a directory\n"), 580 cmd, source); 581 return (1); 582 } 583 (void) fprintf(stderr, 584 gettext("%s: cannot rename %s to %s: "), 585 cmd, source, target); 586 perror(""); 587 return (1); 588 } 589 590 /* 591 * cannot move a non-directory (source) onto an existing 592 * directory (target) 593 * 594 */ 595 if (targetexists && ISDIR(s2) && (!ISDIR(s1))) { 596 (void) fprintf(stderr, 597 gettext("%s: cannot mv a non directory %s " 598 "over existing directory" 599 " %s \n"), cmd, source, target); 600 return (1); 601 } 602 if (ISDIR(s1)) { 603 #ifdef XPG4 604 if (targetexists && ISDIR(s2)) { 605 /* existing target dir must be empty */ 606 if (rmdir(target) < 0) { 607 errno_save = errno; 608 (void) fprintf(stderr, 609 gettext("%s: cannot rmdir %s: "), 610 cmd, target); 611 errno = errno_save; 612 perror(""); 613 return (1); 614 } 615 } 616 #endif 617 if ((n = copydir(source, target)) == 0) 618 (void) rmdir(source); 619 return (n); 620 } 621 622 /* doors can't be moved across filesystems */ 623 if (ISDOOR(s1)) { 624 (void) fprintf(stderr, 625 gettext("%s: %s: can't move door " 626 "across file systems\n"), cmd, source); 627 return (1); 628 } 629 /* 630 * File can't be renamed, try to recreate the symbolic 631 * link or special device, or copy the file wholesale 632 * between file systems. 633 */ 634 if (ISLNK(s1)) { 635 register int m; 636 register mode_t md; 637 char symln[PATH_MAX + 1]; 638 639 if (targetexists && unlink(target) < 0) { 640 (void) fprintf(stderr, 641 gettext("%s: cannot unlink %s: "), 642 cmd, target); 643 perror(""); 644 return (1); 645 } 646 647 if ((m = readlink(source, symln, 648 sizeof (symln) - 1)) < 0) { 649 Perror(source); 650 return (1); 651 } 652 symln[m] = '\0'; 653 654 md = umask(~(s1.st_mode & MODEBITS)); 655 if (symlink(symln, target) < 0) { 656 Perror(target); 657 return (1); 658 } 659 (void) umask(md); 660 m = lchown(target, UID(s1), GID(s1)); 661 #ifdef XPG4 662 if (m < 0) { 663 (void) fprintf(stderr, gettext("%s: cannot" 664 " change owner and group of" 665 " %s: "), cmd, target); 666 perror(""); 667 } 668 #endif 669 goto cleanup; 670 } 671 if (ISDEV(s1)) { 672 673 if (targetexists && unlink(target) < 0) { 674 (void) fprintf(stderr, 675 gettext("%s: cannot unlink %s: "), 676 cmd, target); 677 perror(""); 678 return (1); 679 } 680 681 if (mknod(target, s1.st_mode, s1.st_rdev) < 0) { 682 Perror(target); 683 return (1); 684 } 685 686 (void) chg_mode(target, UID(s1), GID(s1), FMODE(s1)); 687 (void) chg_time(target, s1); 688 goto cleanup; 689 } 690 691 if (ISREG(s1)) { 692 if (ISDIR(s2)) { 693 if (targetexists && rmdir(target) < 0) { 694 (void) fprintf(stderr, 695 gettext("%s: cannot rmdir %s: "), 696 cmd, target); 697 perror(""); 698 return (1); 699 } 700 } else { 701 if (targetexists && unlink(target) < 0) { 702 (void) fprintf(stderr, 703 gettext("%s: cannot unlink %s: "), 704 cmd, target); 705 perror(""); 706 return (1); 707 } 708 } 709 710 711 copy: 712 /* 713 * If the source file is a symlink, and either 714 * -P or -H flag (only if -H is specified and the 715 * source file is not a command line argument) 716 * were specified, then action is taken on the symlink 717 * itself, not the file referenced by the symlink. 718 * Note: this is executed for 'cp' only. 719 */ 720 if (cpy && (Pflg || (Hflg && !cmdarg)) && (ISLNK(s1))) { 721 int m; 722 mode_t md; 723 char symln[PATH_MAX + 1]; 724 725 m = readlink(source, symln, sizeof (symln) - 1); 726 727 if (m < 0) { 728 Perror(source); 729 return (1); 730 } 731 symln[m] = '\0'; 732 733 /* 734 * Copy the sym link to the target. 735 * Note: If the target exists, write a 736 * diagnostic message, do nothing more 737 * with the source file, and return to 738 * process any remaining files. 739 */ 740 md = umask(~(s1.st_mode & MODEBITS)); 741 if (symlink(symln, target) < 0) { 742 Perror(target); 743 return (1); 744 } 745 (void) umask(md); 746 m = lchown(target, UID(s1), GID(s1)); 747 748 if (m < 0) { 749 (void) fprintf(stderr, gettext( 750 "cp: cannot change owner and " 751 "group of %s:"), target); 752 perror(""); 753 } 754 } else { 755 /* 756 * Copy the file. If it happens to be a 757 * symlink, copy the file referenced 758 * by the symlink. 759 */ 760 fi = open(source, O_RDONLY); 761 if (fi < 0) { 762 (void) fprintf(stderr, 763 gettext("%s: cannot open %s: "), 764 cmd, source); 765 perror(""); 766 return (1); 767 } 768 769 fo = creat(target, s1.st_mode & MODEBITS); 770 if (fo < 0) { 771 /* 772 * If -f and creat() failed, unlink 773 * and try again. 774 */ 775 if (fflg) { 776 (void) unlink(target); 777 fo = creat(target, 778 s1.st_mode & MODEBITS); 779 } 780 } 781 if (fo < 0) { 782 (void) fprintf(stderr, 783 gettext("%s: cannot create %s: "), 784 cmd, target); 785 perror(""); 786 (void) close(fi); 787 return (1); 788 } else { 789 /* stat the new file, its used below */ 790 (void) stat(target, &s2); 791 } 792 793 /* 794 * Set target's permissions to the source 795 * before any copying so that any partially 796 * copied file will have the source's 797 * permissions (at most) or umask permissions 798 * whichever is the most restrictive. 799 * 800 * ACL for regular files 801 */ 802 803 if (pflg || mve) { 804 (void) chmod(target, FMODE(s1)); 805 if (s1acl != NULL) { 806 if ((acl_set(target, 807 s1acl)) < 0) { 808 if (pflg || mve) { 809 (void) fprintf( 810 stderr, 811 "%s: failed to set acl entries on %s\n", 812 cmd, 813 target); 814 } 815 /* 816 * else: silent and 817 * continue 818 */ 819 } 820 } 821 } 822 823 if (fstat(fi, &s1) < 0) { 824 (void) fprintf(stderr, 825 gettext("%s: cannot access %s\n"), 826 cmd, source); 827 return (1); 828 } 829 if (IDENTICAL(s1, s2)) { 830 (void) fprintf(stderr, 831 gettext( 832 "%s: %s and %s are identical\n"), 833 cmd, source, target); 834 return (1); 835 } 836 837 if (writefile(fi, fo, source, target, 838 &s1, &s2) != 0) { 839 return (1); 840 } 841 842 (void) close(fi); 843 if (close(fo) < 0) { 844 Perror2(target, "write"); 845 return (1); 846 } 847 } 848 849 if (pflg || atflg || mve) { 850 attret = copyattributes(source, target); 851 if (attret != 0 && !attrsilent) { 852 (void) fprintf(stderr, gettext( 853 "%s: Failed to preserve" 854 " extended attributes of file" 855 " %s\n"), cmd, source); 856 } 857 858 if (mve && attret != 0) { 859 (void) unlink(target); 860 return (1); 861 } 862 863 if (attrsilent) 864 attret = 0; 865 } 866 867 /* 868 * XPG4: the write system call will clear setgid 869 * and setuid bits, so set them again. 870 */ 871 if (pflg || mve) { 872 if ((ret = chg_mode(target, UID(s1), GID(s1), 873 FMODE(s1))) > 0) 874 return (1); 875 if ((ret = chg_time(target, s1)) > 0) 876 return (1); 877 } 878 if (cpy) { 879 if (attret != 0) 880 return (1); 881 return (0); 882 } 883 goto cleanup; 884 } 885 (void) fprintf(stderr, 886 gettext("%s: %s: unknown file type 0x%x\n"), cmd, 887 source, (s1.st_mode & S_IFMT)); 888 return (1); 889 890 cleanup: 891 if (unlink(source) < 0) { 892 (void) unlink(target); 893 (void) fprintf(stderr, 894 gettext("%s: cannot unlink %s: "), 895 cmd, source); 896 perror(""); 897 return (1); 898 } 899 if (attret != 0) 900 return (attret); 901 return (ret); 902 } 903 /*NOTREACHED*/ 904 return (ret); 905 } 906 907 static int 908 writefile(int fi, int fo, char *source, char *target, 909 struct stat *s1p, struct stat *s2p) 910 { 911 int mapsize, munmapsize; 912 caddr_t cp; 913 off_t filesize = s1p->st_size; 914 off_t offset; 915 int nbytes; 916 int remains; 917 int n; 918 919 if (ISREG(*s1p) && s1p->st_size > SMALLFILESIZE) { 920 /* 921 * Determine size of initial mapping. This will determine the 922 * size of the address space chunk we work with. This initial 923 * mapping size will be used to perform munmap() in the future. 924 */ 925 mapsize = MAXMAPSIZE; 926 if (s1p->st_size < mapsize) mapsize = s1p->st_size; 927 munmapsize = mapsize; 928 929 /* 930 * Mmap time! 931 */ 932 if ((cp = mmap((caddr_t)NULL, mapsize, PROT_READ, 933 MAP_SHARED, fi, (off_t)0)) == MAP_FAILED) 934 mapsize = 0; /* can't mmap today */ 935 } else 936 mapsize = 0; 937 938 if (mapsize != 0) { 939 offset = 0; 940 941 for (;;) { 942 nbytes = write(fo, cp, mapsize); 943 /* 944 * if we write less than the mmaped size it's due to a 945 * media error on the input file or out of space on 946 * the output file. So, try again, and look for errno. 947 */ 948 if ((nbytes >= 0) && (nbytes != (int)mapsize)) { 949 remains = mapsize - nbytes; 950 while (remains > 0) { 951 nbytes = write(fo, 952 cp + mapsize - remains, remains); 953 if (nbytes < 0) { 954 if (errno == ENOSPC) 955 Perror(target); 956 else 957 Perror(source); 958 (void) close(fi); 959 (void) close(fo); 960 (void) munmap(cp, munmapsize); 961 if (ISREG(*s2p)) 962 (void) unlink(target); 963 return (1); 964 } 965 remains -= nbytes; 966 if (remains == 0) 967 nbytes = mapsize; 968 } 969 } 970 /* 971 * although the write manual page doesn't specify this 972 * as a possible errno, it is set when the nfs read 973 * via the mmap'ed file is accessed, so report the 974 * problem as a source access problem, not a target file 975 * problem 976 */ 977 if (nbytes < 0) { 978 if (errno == EACCES) 979 Perror(source); 980 else 981 Perror(target); 982 (void) close(fi); 983 (void) close(fo); 984 (void) munmap(cp, munmapsize); 985 if (ISREG(*s2p)) 986 (void) unlink(target); 987 return (1); 988 } 989 filesize -= nbytes; 990 if (filesize == 0) 991 break; 992 offset += nbytes; 993 if (filesize < mapsize) 994 mapsize = filesize; 995 if (mmap(cp, mapsize, PROT_READ, MAP_SHARED | MAP_FIXED, 996 fi, offset) == MAP_FAILED) { 997 Perror(source); 998 (void) close(fi); 999 (void) close(fo); 1000 (void) munmap(cp, munmapsize); 1001 if (ISREG(*s2p)) 1002 (void) unlink(target); 1003 return (1); 1004 } 1005 } 1006 (void) munmap(cp, munmapsize); 1007 } else { 1008 char buf[SMALLFILESIZE]; 1009 for (;;) { 1010 n = read(fi, buf, sizeof (buf)); 1011 if (n == 0) { 1012 return (0); 1013 } else if (n < 0) { 1014 Perror2(source, "read"); 1015 (void) close(fi); 1016 (void) close(fo); 1017 if (ISREG(*s2p)) 1018 (void) unlink(target); 1019 return (1); 1020 } else if (write(fo, buf, n) != n) { 1021 Perror2(target, "write"); 1022 (void) close(fi); 1023 (void) close(fo); 1024 if (ISREG(*s2p)) 1025 (void) unlink(target); 1026 return (1); 1027 } 1028 } 1029 } 1030 return (0); 1031 } 1032 1033 /* 1034 * create_tnode() 1035 * 1036 * Create a node for use with the search tree which contains the 1037 * inode information (device id and inode number). 1038 * 1039 * Input 1040 * dev - device id 1041 * ino - inode number 1042 * 1043 * Output 1044 * tnode - NULL on error, otherwise returns a tnode structure 1045 * which contains the input device id and inode number. 1046 */ 1047 static tree_node_t * 1048 create_tnode(dev_t dev, ino_t ino) 1049 { 1050 tree_node_t *tnode; 1051 1052 if ((tnode = (tree_node_t *)malloc(sizeof (tree_node_t))) != NULL) { 1053 tnode->node_dev = dev; 1054 tnode->node_ino = ino; 1055 } 1056 1057 return (tnode); 1058 } 1059 1060 static int 1061 chkfiles(char *source, char **to) 1062 { 1063 char *buf = (char *)NULL; 1064 int (*statf)() = (cpy && 1065 !(Pflg || (Hflg && !cmdarg))) ? stat : lstat; 1066 char *target = *to; 1067 int error; 1068 1069 /* 1070 * Make sure source file exists. 1071 */ 1072 if ((*statf)(source, &s1) < 0) { 1073 /* 1074 * Keep the old error message except when someone tries to 1075 * mv/cp/ln a symbolic link that has a trailing slash and 1076 * points to a file. 1077 */ 1078 if (errno == ENOTDIR) 1079 (void) fprintf(stderr, "%s: %s: %s\n", cmd, source, 1080 strerror(errno)); 1081 else 1082 (void) fprintf(stderr, 1083 gettext("%s: cannot access %s\n"), cmd, source); 1084 return (1); 1085 } 1086 1087 /* 1088 * Get ACL info: don't bother with ln or mv'ing symlinks 1089 */ 1090 if ((!lnk) && !(mve && ISLNK(s1))) { 1091 if (s1acl != NULL) { 1092 acl_free(s1acl); 1093 s1acl = NULL; 1094 } 1095 if ((error = acl_get(source, ACL_NO_TRIVIAL, &s1acl)) != 0) { 1096 (void) fprintf(stderr, 1097 "%s: failed to get acl entries: %s\n", source, 1098 acl_strerror(error)); 1099 return (1); 1100 } 1101 /* else: just permission bits */ 1102 } 1103 1104 /* 1105 * If stat fails, then the target doesn't exist, 1106 * we will create a new target with default file type of regular. 1107 */ 1108 1109 FTYPE(s2) = S_IFREG; 1110 targetexists = 0; 1111 if ((*statf)(target, &s2) >= 0) { 1112 if (ISLNK(s2)) 1113 (void) stat(target, &s2); 1114 /* 1115 * If target is a directory, 1116 * make complete name of new file 1117 * within that directory. 1118 */ 1119 if (ISDIR(s2)) { 1120 size_t len; 1121 1122 len = strlen(target) + strlen(dname(source)) + 4; 1123 if ((buf = (char *)malloc(len)) == NULL) { 1124 (void) fprintf(stderr, 1125 gettext("%s: Insufficient memory to " 1126 "%s %s\n "), cmd, cmd, source); 1127 exit(3); 1128 } 1129 (void) snprintf(buf, len, "%s/%s", 1130 target, dname(source)); 1131 *to = target = buf; 1132 } 1133 1134 if ((*statf)(target, &s2) >= 0) { 1135 int overwrite = FALSE; 1136 int override = FALSE; 1137 1138 targetexists++; 1139 if (cpy || mve) { 1140 /* 1141 * For cp and mv, it is an error if the 1142 * source and target are the same file. 1143 * Check for the same inode and file 1144 * system, but don't check for the same 1145 * absolute pathname because it is an 1146 * error when the source and target are 1147 * hard links to the same file. 1148 */ 1149 if (IDENTICAL(s1, s2)) { 1150 (void) fprintf(stderr, 1151 gettext( 1152 "%s: %s and %s are identical\n"), 1153 cmd, source, target); 1154 if (buf != NULL) 1155 free(buf); 1156 return (1); 1157 } 1158 } 1159 if (lnk) { 1160 /* 1161 * For ln, it is an error if the source and 1162 * target are identical files (same inode, 1163 * same file system, and filenames resolve 1164 * to same absolute pathname). 1165 */ 1166 if (!chk_different(source, target)) { 1167 if (buf != NULL) 1168 free(buf); 1169 return (1); 1170 } 1171 } 1172 if (lnk && !silent) { 1173 (void) fprintf(stderr, 1174 gettext("%s: %s: File exists\n"), 1175 cmd, target); 1176 if (buf != NULL) 1177 free(buf); 1178 return (1); 1179 } 1180 1181 /* 1182 * overwrite: 1183 * If the user does not have access to 1184 * the target, ask ----if it is not 1185 * silent and user invoked command 1186 * interactively. 1187 * 1188 * override: 1189 * If not silent, and stdin is a terminal, and 1190 * there's no write access, and the file isn't a 1191 * symbolic link, ask for permission. 1192 * 1193 * XPG4: both overwrite and override: 1194 * ask only one question. 1195 * 1196 * TRANSLATION_NOTE - The following messages will 1197 * contain the first character of the strings for 1198 * "yes" and "no" defined in the file 1199 * "nl_langinfo.po". After substitution, the 1200 * message will appear as follows: 1201 * <cmd>: overwrite <filename> (y/n)? 1202 * where <cmd> is the name of the command 1203 * (cp, mv) and <filename> is the destination file 1204 */ 1205 1206 1207 overwrite = iflg && !silent && use_stdin(); 1208 override = !cpy && (access(target, 2) < 0) && 1209 !silent && use_stdin() && !ISLNK(s2); 1210 1211 if (overwrite && override) 1212 (void) fprintf(stderr, 1213 gettext("%s: overwrite %s and override " 1214 "protection %o (%s/%s)? "), cmd, target, 1215 FMODE(s2) & MODEBITS, yeschr, nochr); 1216 else if (overwrite && ISREG(s2)) 1217 (void) fprintf(stderr, 1218 gettext("%s: overwrite %s (%s/%s)? "), 1219 cmd, target, yeschr, nochr); 1220 else if (override) 1221 (void) fprintf(stderr, 1222 gettext("%s: %s: override protection " 1223 /*CSTYLED*/ 1224 "%o (%s/%s)? "), 1225 /*CSTYLED*/ 1226 cmd, target, FMODE(s2) & MODEBITS, 1227 yeschr, nochr); 1228 if (overwrite || override) { 1229 if (ISREG(s2)) { 1230 if (getresp()) { 1231 if (buf != NULL) 1232 free(buf); 1233 return (2); 1234 } 1235 } 1236 } 1237 if (lnk && unlink(target) < 0) { 1238 (void) fprintf(stderr, 1239 gettext("%s: cannot unlink %s: "), 1240 cmd, target); 1241 perror(""); 1242 return (1); 1243 } 1244 } 1245 } 1246 return (0); 1247 } 1248 1249 /* 1250 * check whether source and target are different 1251 * return 1 when they are different 1252 * return 0 when they are identical, or when unable to resolve a pathname 1253 */ 1254 static int 1255 chk_different(char *source, char *target) 1256 { 1257 char rtarget[PATH_MAX], rsource[PATH_MAX]; 1258 1259 if (IDENTICAL(s1, s2)) { 1260 /* 1261 * IDENTICAL will be true for hard links, therefore 1262 * check whether the filenames are different 1263 */ 1264 if ((getrealpath(source, rsource) == 0) || 1265 (getrealpath(target, rtarget) == 0)) { 1266 return (0); 1267 } 1268 if (strncmp(rsource, rtarget, PATH_MAX) == 0) { 1269 (void) fprintf(stderr, gettext( 1270 "%s: %s and %s are identical\n"), 1271 cmd, source, target); 1272 return (0); 1273 } 1274 } 1275 return (1); 1276 } 1277 1278 /* 1279 * get real path (resolved absolute pathname) 1280 * return 1 on success, 0 on failure 1281 */ 1282 static int 1283 getrealpath(char *path, char *rpath) 1284 { 1285 if (realpath(path, rpath) == NULL) { 1286 int errno_save = errno; 1287 (void) fprintf(stderr, gettext( 1288 "%s: can't resolve path %s: "), cmd, path); 1289 errno = errno_save; 1290 perror(""); 1291 return (0); 1292 } 1293 return (1); 1294 } 1295 1296 static int 1297 rcopy(char *from, char *to) 1298 { 1299 DIR *fold = opendir(from); 1300 struct dirent *dp; 1301 struct stat statb, s1save; 1302 int errs = 0; 1303 char fromname[PATH_MAX]; 1304 1305 if (fold == 0 || ((pflg || mve) && fstat(fold->dd_fd, &statb) < 0)) { 1306 Perror(from); 1307 return (1); 1308 } 1309 if (pflg || mve) { 1310 /* 1311 * Save s1 (stat information for source dir) so that 1312 * mod and access times can be reserved during "cp -p" 1313 * or mv, since s1 gets overwritten. 1314 */ 1315 s1save = s1; 1316 } 1317 for (;;) { 1318 dp = readdir(fold); 1319 if (dp == 0) { 1320 (void) closedir(fold); 1321 if (pflg || mve) 1322 return (chg_time(to, s1save) + errs); 1323 return (errs); 1324 } 1325 if (dp->d_ino == 0) 1326 continue; 1327 if ((strcmp(dp->d_name, ".") == 0) || 1328 (strcmp(dp->d_name, "..") == 0)) 1329 continue; 1330 if (strlen(from)+1+strlen(dp->d_name) >= 1331 sizeof (fromname) - 1) { 1332 (void) fprintf(stderr, 1333 gettext("%s : %s/%s: Name too long\n"), 1334 cmd, from, dp->d_name); 1335 errs++; 1336 continue; 1337 } 1338 (void) snprintf(fromname, sizeof (fromname), 1339 "%s/%s", from, dp->d_name); 1340 errs += cpymve(fromname, to); 1341 } 1342 } 1343 1344 static char * 1345 dname(char *name) 1346 { 1347 register char *p; 1348 1349 /* 1350 * Return just the file name given the complete path. 1351 * Like basename(1). 1352 */ 1353 1354 p = name; 1355 1356 /* 1357 * While there are characters left, 1358 * set name to start after last 1359 * delimiter. 1360 */ 1361 1362 while (*p) 1363 if (*p++ == DELIM && *p) 1364 name = p; 1365 return (name); 1366 } 1367 1368 static int 1369 getresp(void) 1370 { 1371 register int c, i; 1372 char ans_buf[SCHAR_MAX + 1]; 1373 1374 /* 1375 * Get response from user. Based on 1376 * first character, make decision. 1377 * Discard rest of line. 1378 */ 1379 for (i = 0; ; i++) { 1380 c = getchar(); 1381 if (c == '\n' || c == 0 || c == EOF) { 1382 ans_buf[i] = 0; 1383 break; 1384 } 1385 if (i < SCHAR_MAX) 1386 ans_buf[i] = c; 1387 } 1388 if (i >= SCHAR_MAX) { 1389 i = SCHAR_MAX; 1390 ans_buf[SCHAR_MAX] = 0; 1391 } 1392 if ((i == 0) | (strncmp(yeschr, ans_buf, i))) 1393 return (1); 1394 return (0); 1395 } 1396 1397 static void 1398 usage(void) 1399 { 1400 /* 1401 * Display usage message. 1402 */ 1403 1404 if (mve) { 1405 (void) fprintf(stderr, gettext( 1406 "Usage: mv [-f] [-i] f1 f2\n" 1407 " mv [-f] [-i] f1 ... fn d1\n" 1408 " mv [-f] [-i] d1 d2\n")); 1409 } else if (lnk) { 1410 (void) fprintf(stderr, gettext( 1411 #ifdef XPG4 1412 "Usage: ln [-f] [-s] f1 [f2]\n" 1413 " ln [-f] [-s] f1 ... fn d1\n" 1414 " ln [-f] -s d1 d2\n")); 1415 #else 1416 "Usage: ln [-f] [-n] [-s] f1 [f2]\n" 1417 " ln [-f] [-n] [-s] f1 ... fn d1\n" 1418 " ln [-f] [-n] -s d1 d2\n")); 1419 #endif 1420 } else if (cpy) { 1421 (void) fprintf(stderr, gettext( 1422 "Usage: cp [-f] [-i] [-p] [-@] f1 f2\n" 1423 " cp [-f] [-i] [-p] [-@] f1 ... fn d1\n" 1424 " cp -r|-R [-H|-L|-P] [-f] [-i] [-p] [-@] " 1425 "d1 ... dn-1 dn\n")); 1426 } 1427 exit(2); 1428 } 1429 1430 /* 1431 * chg_time() 1432 * 1433 * Try to preserve modification and access time. 1434 * If 1) pflg is not set, or 2) pflg is set and this is the Solaris version, 1435 * don't report a utime() failure. 1436 * If this is the XPG4 version and utime fails, if 1) pflg is set (cp -p) 1437 * or 2) we are doing a mv, print a diagnostic message; arrange for a non-zero 1438 * exit status only if pflg is set. 1439 * utimes(2) is being used to achieve granularity in 1440 * microseconds while setting file times. 1441 */ 1442 static int 1443 chg_time(char *to, struct stat ss) 1444 { 1445 struct timeval times[2]; 1446 int rc; 1447 1448 timestruc_to_timeval(&ss.st_atim, times); 1449 timestruc_to_timeval(&ss.st_mtim, times + 1); 1450 1451 rc = utimes(to, times); 1452 #ifdef XPG4 1453 if ((pflg || mve) && rc != 0) { 1454 (void) fprintf(stderr, 1455 gettext("%s: cannot set times for %s: "), cmd, to); 1456 perror(""); 1457 if (pflg) 1458 return (1); 1459 } 1460 #endif 1461 1462 return (0); 1463 1464 } 1465 1466 /* 1467 * chg_mode() 1468 * 1469 * This function is called upon "cp -p" or mv across filesystems. 1470 * 1471 * Try to preserve the owner and group id. If chown() fails, 1472 * only print a diagnostic message if doing a mv in the XPG4 version; 1473 * try to clear S_ISUID and S_ISGID bits in the target. If unable to clear 1474 * S_ISUID and S_ISGID bits, print a diagnostic message and arrange for a 1475 * non-zero exit status because this is a security violation. 1476 * Try to preserve permissions. 1477 * If this is the XPG4 version and chmod() fails, print a diagnostic message 1478 * and arrange for a non-zero exit status. 1479 * If this is the Solaris version and chmod() fails, do not print a 1480 * diagnostic message or exit with a non-zero value. 1481 */ 1482 static int 1483 chg_mode(char *target, uid_t uid, gid_t gid, mode_t mode) 1484 { 1485 int clearflg = 0; /* controls message printed upon chown() error */ 1486 1487 if (chown(target, uid, gid) != 0) { 1488 #ifdef XPG4 1489 if (mve) { 1490 (void) fprintf(stderr, gettext("%s: cannot change" 1491 " owner and group of %s: "), cmd, target); 1492 perror(""); 1493 } 1494 #endif 1495 if (mode & (S_ISUID | S_ISGID)) { 1496 /* try to clear S_ISUID and S_ISGID */ 1497 mode &= ~S_ISUID & ~S_ISGID; 1498 ++clearflg; 1499 } 1500 } 1501 if (chmod(target, mode) != 0) { 1502 if (clearflg) { 1503 (void) fprintf(stderr, gettext( 1504 "%s: cannot clear S_ISUID and S_ISGID bits in" 1505 " %s: "), cmd, target); 1506 perror(""); 1507 /* cp -p should get non-zero exit; mv should not */ 1508 if (pflg) 1509 return (1); 1510 } 1511 #ifdef XPG4 1512 else { 1513 (void) fprintf(stderr, gettext( 1514 "%s: cannot set permissions for %s: "), cmd, target); 1515 perror(""); 1516 /* cp -p should get non-zero exit; mv should not */ 1517 if (pflg) 1518 return (1); 1519 } 1520 #endif 1521 } 1522 return (0); 1523 1524 } 1525 1526 static void 1527 Perror(char *s) 1528 { 1529 char buf[PATH_MAX + 10]; 1530 1531 (void) snprintf(buf, sizeof (buf), "%s: %s", cmd, s); 1532 perror(buf); 1533 } 1534 1535 static void 1536 Perror2(char *s1, char *s2) 1537 { 1538 char buf[PATH_MAX + 20]; 1539 1540 (void) snprintf(buf, sizeof (buf), "%s: %s: %s", 1541 cmd, gettext(s1), gettext(s2)); 1542 perror(buf); 1543 } 1544 1545 /* 1546 * used for cp -R and for mv across file systems 1547 */ 1548 static int 1549 copydir(char *source, char *target) 1550 { 1551 int ret, attret = 0; 1552 int pret = 0; /* need separate flag if -p is specified */ 1553 mode_t fixmode = (mode_t)0; /* cleanup mode after copy */ 1554 struct stat s1save; 1555 acl_t *s1acl_save; 1556 1557 s1acl_save = NULL; 1558 1559 if (cpy && !rflg) { 1560 (void) fprintf(stderr, 1561 gettext("%s: %s: is a directory\n"), cmd, source); 1562 return (1); 1563 } 1564 1565 if (stat(target, &s2) < 0) { 1566 if (mkdir(target, (s1.st_mode & MODEBITS)) < 0) { 1567 (void) fprintf(stderr, "%s: ", cmd); 1568 perror(target); 1569 return (1); 1570 } 1571 if (stat(target, &s2) == 0) { 1572 fixmode = s2.st_mode; 1573 } else { 1574 fixmode = s1.st_mode; 1575 } 1576 (void) chmod(target, ((fixmode & MODEBITS) | S_IRWXU)); 1577 } else if (!(ISDIR(s2))) { 1578 (void) fprintf(stderr, 1579 gettext("%s: %s: not a directory.\n"), cmd, target); 1580 return (1); 1581 } 1582 if (pflg || mve) { 1583 /* 1584 * Save s1 (stat information for source dir) and acl info, 1585 * if any, so that ownership, modes, times, and acl's can 1586 * be reserved during "cp -p" or mv. 1587 * s1 gets overwritten when doing the recursive copy. 1588 */ 1589 s1save = s1; 1590 if (s1acl != NULL) { 1591 s1acl_save = acl_dup(s1acl); 1592 if (s1acl_save == NULL) { 1593 (void) fprintf(stderr, gettext("%s: " 1594 "Insufficient memory to save acl" 1595 " entry\n"), cmd); 1596 if (pflg) 1597 return (1); 1598 1599 } 1600 #ifdef XPG4 1601 else { 1602 (void) fprintf(stderr, gettext("%s: " 1603 "Insufficient memory to save acl" 1604 " entry\n"), cmd); 1605 if (pflg) 1606 return (1); 1607 } 1608 #endif 1609 } 1610 } 1611 1612 ret = rcopy(source, target); 1613 1614 /* 1615 * Once we created a directory, go ahead and set 1616 * its attributes, e.g. acls and time. The info 1617 * may get overwritten if we continue traversing 1618 * down the tree. 1619 * 1620 * ACL for directory 1621 */ 1622 if (pflg || mve) { 1623 if (s1acl_save != NULL) { 1624 if (acl_set(target, s1acl_save) < 0) { 1625 #ifdef XPG4 1626 if (pflg || mve) { 1627 #else 1628 if (pflg) { 1629 #endif 1630 (void) fprintf(stderr, gettext( 1631 "%s: failed to set acl entries " 1632 "on %s\n"), cmd, target); 1633 if (pflg) { 1634 acl_free(s1acl_save); 1635 s1acl_save = NULL; 1636 ret++; 1637 } 1638 } 1639 /* else: silent and continue */ 1640 } 1641 acl_free(s1acl_save); 1642 s1acl_save = NULL; 1643 } 1644 if ((pret = chg_mode(target, UID(s1save), GID(s1save), 1645 FMODE(s1save))) == 0) 1646 pret = chg_time(target, s1save); 1647 ret += pret; 1648 } else if (fixmode != (mode_t)0) 1649 (void) chmod(target, fixmode & MODEBITS); 1650 1651 if (pflg || atflg || mve) { 1652 attret = copyattributes(source, target); 1653 if (!attrsilent && attret != 0) { 1654 (void) fprintf(stderr, gettext("%s: Failed to preserve" 1655 " extended attributes of directory" 1656 " %s\n"), cmd, source); 1657 } else { 1658 /* 1659 * Otherwise ignore failure. 1660 */ 1661 attret = 0; 1662 } 1663 } 1664 if (attret != 0) 1665 return (attret); 1666 return (ret); 1667 } 1668 1669 static int 1670 copyspecial(char *target) 1671 { 1672 int ret = 0; 1673 1674 if (mknod(target, s1.st_mode, s1.st_rdev) != 0) { 1675 (void) fprintf(stderr, gettext( 1676 "cp: cannot create special file %s: "), target); 1677 perror(""); 1678 return (1); 1679 } 1680 1681 if (pflg) { 1682 if ((ret = chg_mode(target, UID(s1), GID(s1), FMODE(s1))) == 0) 1683 ret = chg_time(target, s1); 1684 } 1685 1686 return (ret); 1687 } 1688 1689 static int 1690 use_stdin(void) 1691 { 1692 #ifdef XPG4 1693 return (1); 1694 #else 1695 return (isatty(fileno(stdin))); 1696 #endif 1697 } 1698 1699 static int 1700 copyattributes(char *source, char *target) 1701 { 1702 int sourcedirfd, targetdirfd; 1703 int srcfd, targfd; 1704 int tmpfd; 1705 DIR *srcdirp; 1706 int srcattrfd, targattrfd; 1707 struct dirent *dp; 1708 char *attrstr; 1709 char *srcbuf, *targbuf; 1710 size_t src_size, targ_size; 1711 int error = 0; 1712 int aclerror; 1713 mode_t mode; 1714 int clearflg = 0; 1715 acl_t *xacl = NULL; 1716 acl_t *attrdiracl = NULL; 1717 struct stat attrdir, s3, s4; 1718 struct timeval times[2]; 1719 mode_t targmode; 1720 1721 srcdirp = NULL; 1722 srcfd = targfd = tmpfd = -1; 1723 sourcedirfd = targetdirfd = srcattrfd = targattrfd = -1; 1724 srcbuf = targbuf = NULL; 1725 1726 if (pathconf(source, _PC_XATTR_EXISTS) != 1) 1727 return (0); 1728 1729 if (pathconf(target, _PC_XATTR_ENABLED) != 1) { 1730 if (!attrsilent) { 1731 (void) fprintf(stderr, 1732 gettext( 1733 "%s: cannot preserve extended attributes, " 1734 "operation not supported on file" 1735 " %s\n"), cmd, target); 1736 } 1737 return (1); 1738 } 1739 1740 1741 if ((srcfd = open(source, O_RDONLY)) == -1) { 1742 if (pflg && attrsilent) { 1743 error = 0; 1744 goto out; 1745 } 1746 if (!attrsilent) { 1747 (void) fprintf(stderr, 1748 gettext("%s: cannot open file" 1749 " %s: "), cmd, source); 1750 perror(""); 1751 } 1752 ++error; 1753 goto out; 1754 } 1755 if ((targfd = open(target, O_RDONLY)) == -1) { 1756 1757 if (pflg && attrsilent) { 1758 error = 0; 1759 goto out; 1760 } 1761 if (!attrsilent) { 1762 (void) fprintf(stderr, 1763 gettext("%s: cannot open file" 1764 " %s: "), cmd, source); 1765 perror(""); 1766 } 1767 ++error; 1768 goto out; 1769 } 1770 1771 if ((sourcedirfd = openat(srcfd, ".", O_RDONLY|O_XATTR)) == -1) { 1772 if (pflg && attrsilent) { 1773 error = 0; 1774 goto out; 1775 } 1776 if (!attrsilent) { 1777 (void) fprintf(stderr, 1778 gettext("%s: cannot open attribute" 1779 " directory for %s: "), cmd, source); 1780 perror(""); 1781 ++error; 1782 } 1783 goto out; 1784 } 1785 1786 if (fstat(sourcedirfd, &attrdir) == -1) { 1787 if (pflg && attrsilent) { 1788 error = 0; 1789 goto out; 1790 } 1791 1792 if (!attrsilent) { 1793 (void) fprintf(stderr, 1794 gettext("%s: could not retrieve stat" 1795 " information for attribute directory" 1796 "of file %s: "), cmd, source); 1797 perror(""); 1798 ++error; 1799 } 1800 goto out; 1801 } 1802 if ((targetdirfd = openat(targfd, ".", O_RDONLY|O_XATTR)) == -1) { 1803 /* 1804 * We couldn't create the attribute directory 1805 * 1806 * Lets see if we can add write support to the mode 1807 * and create the directory and then put the mode back 1808 * to way it should be. 1809 */ 1810 1811 targmode = FMODE(s1) | S_IWUSR; 1812 if (fchmod(targfd, targmode) == 0) { 1813 targetdirfd = openat(targfd, ".", O_RDONLY|O_XATTR); 1814 /* 1815 * Put mode back to what it was 1816 */ 1817 targmode = FMODE(s1) & MODEBITS; 1818 if (fchmod(targfd, targmode) == -1) { 1819 if (pflg && attrsilent) { 1820 error = 0; 1821 goto out; 1822 } 1823 if (!attrsilent) { 1824 (void) fprintf(stderr, 1825 gettext("%s: failed to set" 1826 " mode correctly on file" 1827 " %s: "), cmd, target); 1828 perror(""); 1829 ++error; 1830 goto out; 1831 } 1832 } 1833 } else { 1834 if (pflg && attrsilent) { 1835 error = 0; 1836 goto out; 1837 } 1838 if (!attrsilent) { 1839 (void) fprintf(stderr, 1840 gettext("%s: cannot open attribute" 1841 " directory for %s: "), cmd, target); 1842 perror(""); 1843 ++error; 1844 } 1845 goto out; 1846 } 1847 } 1848 1849 if (targetdirfd == -1) { 1850 if (pflg && attrsilent) { 1851 error = 0; 1852 goto out; 1853 } 1854 if (!attrsilent) { 1855 (void) fprintf(stderr, 1856 gettext("%s: cannot open attribute directory" 1857 " for %s: "), cmd, target); 1858 perror(""); 1859 ++error; 1860 } 1861 goto out; 1862 } 1863 1864 /* 1865 * Set mode of attribute directory same as on source, 1866 * if pflg set or this is a move. 1867 */ 1868 1869 if (pflg || mve) { 1870 if (fchmod(targetdirfd, attrdir.st_mode) == -1) { 1871 if (!attrsilent) { 1872 (void) fprintf(stderr, 1873 gettext("%s: failed to set file mode" 1874 " correctly on attribute directory of" 1875 " file %s: "), cmd, target); 1876 perror(""); 1877 ++error; 1878 } 1879 } 1880 1881 if (fchown(targetdirfd, attrdir.st_uid, attrdir.st_gid) == -1) { 1882 if (!attrsilent) { 1883 (void) fprintf(stderr, 1884 gettext("%s: failed to set file" 1885 " ownership correctly on attribute" 1886 " directory of file %s: "), cmd, target); 1887 perror(""); 1888 ++error; 1889 } 1890 } 1891 /* 1892 * Now that we are the owner we can update st_ctime by calling 1893 * futimesat. 1894 */ 1895 times[0].tv_sec = attrdir.st_atime; 1896 times[0].tv_usec = 0; 1897 times[1].tv_sec = attrdir.st_mtime; 1898 times[1].tv_usec = 0; 1899 if (futimesat(targetdirfd, ".", times) < 0) { 1900 if (!attrsilent) { 1901 (void) fprintf(stderr, 1902 gettext("%s: cannot set attribute times" 1903 " for %s: "), cmd, target); 1904 perror(""); 1905 ++error; 1906 } 1907 } 1908 1909 /* 1910 * Now set owner and group of attribute directory, implies 1911 * changing the ACL of the hidden attribute directory first. 1912 */ 1913 if ((aclerror = facl_get(sourcedirfd, 1914 ACL_NO_TRIVIAL, &attrdiracl)) != 0) { 1915 if (!attrsilent) { 1916 (void) fprintf(stderr, gettext( 1917 "%s: failed to get acl entries of" 1918 " attribute directory for" 1919 " %s : %s\n"), cmd, 1920 source, acl_strerror(aclerror)); 1921 ++error; 1922 } 1923 } 1924 1925 if (attrdiracl) { 1926 if (facl_set(targetdirfd, attrdiracl) != 0) { 1927 if (!attrsilent) { 1928 (void) fprintf(stderr, gettext( 1929 "%s: failed to set acl entries" 1930 " on attribute directory " 1931 "for %s\n"), cmd, target); 1932 ++error; 1933 } 1934 acl_free(attrdiracl); 1935 attrdiracl = NULL; 1936 } 1937 } 1938 } 1939 1940 /* 1941 * dup sourcedirfd for use by fdopendir(). 1942 * fdopendir will take ownership of given fd and will close 1943 * it when closedir() is called. 1944 */ 1945 1946 if ((tmpfd = dup(sourcedirfd)) == -1) { 1947 if (pflg && attrsilent) { 1948 error = 0; 1949 goto out; 1950 } 1951 if (!attrsilent) { 1952 (void) fprintf(stderr, 1953 gettext( 1954 "%s: unable to dup attribute directory" 1955 " file descriptor for %s: "), cmd, source); 1956 perror(""); 1957 ++error; 1958 } 1959 goto out; 1960 } 1961 if ((srcdirp = fdopendir(tmpfd)) == NULL) { 1962 if (pflg && attrsilent) { 1963 error = 0; 1964 goto out; 1965 } 1966 if (!attrsilent) { 1967 (void) fprintf(stderr, 1968 gettext("%s: failed to open attribute" 1969 " directory for %s: "), cmd, source); 1970 perror(""); 1971 ++error; 1972 } 1973 goto out; 1974 } 1975 1976 while (dp = readdir(srcdirp)) { 1977 if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') || 1978 (dp->d_name[0] == '.' && dp->d_name[1] == '.' && 1979 dp->d_name[2] == '\0')) 1980 continue; 1981 1982 if ((srcattrfd = openat(sourcedirfd, dp->d_name, 1983 O_RDONLY)) == -1) { 1984 if (!attrsilent) { 1985 (void) fprintf(stderr, 1986 gettext("%s: cannot open attribute %s on" 1987 " file %s: "), cmd, dp->d_name, source); 1988 perror(""); 1989 ++error; 1990 goto next; 1991 } 1992 } 1993 1994 if (fstat(srcattrfd, &s3) < 0) { 1995 if (!attrsilent) { 1996 (void) fprintf(stderr, 1997 gettext("%s: could not stat attribute" 1998 " %s on file" 1999 " %s: "), cmd, dp->d_name, source); 2000 perror(""); 2001 ++error; 2002 } 2003 goto next; 2004 } 2005 2006 if (pflg || mve) { 2007 if ((aclerror = facl_get(srcattrfd, 2008 ACL_NO_TRIVIAL, &xacl)) != 0) { 2009 if (!attrsilent) { 2010 (void) fprintf(stderr, gettext( 2011 "%s: failed to get acl entries of" 2012 " attribute %s for" 2013 " %s: %s"), cmd, dp->d_name, 2014 source, acl_strerror(aclerror)); 2015 ++error; 2016 } 2017 } 2018 } 2019 2020 (void) unlinkat(targetdirfd, dp->d_name, 0); 2021 if ((targattrfd = openat(targetdirfd, dp->d_name, 2022 O_RDWR|O_CREAT|O_TRUNC, s3.st_mode & MODEBITS)) == -1) { 2023 if (!attrsilent) { 2024 (void) fprintf(stderr, 2025 gettext("%s: could not create attribute" 2026 " %s on file" 2027 " %s: "), cmd, dp->d_name, target); 2028 perror(""); 2029 ++error; 2030 } 2031 goto next; 2032 } 2033 2034 /* 2035 * preserve ACL 2036 */ 2037 if ((pflg || mve) && xacl != NULL) { 2038 if ((facl_set(targattrfd, xacl)) < 0) { 2039 if (!attrsilent) { 2040 (void) fprintf(stderr, gettext( 2041 "%s: failed to set acl entries on" 2042 " attribute %s for" 2043 "%s\n"), cmd, dp->d_name, target); 2044 ++error; 2045 } 2046 acl_free(xacl); 2047 xacl = NULL; 2048 } 2049 } 2050 2051 if (fstat(targattrfd, &s4) < 0) { 2052 if (!attrsilent) { 2053 (void) fprintf(stderr, 2054 gettext("%s: could not stat attribute" 2055 " %s on file" 2056 " %s: "), cmd, dp->d_name, source); 2057 perror(""); 2058 ++error; 2059 } 2060 goto next; 2061 } 2062 2063 /* 2064 * setup path string to be passed to writefile 2065 * 2066 * We need to include attribute in the string so that 2067 * a useful error message can be printed in the case of a failure. 2068 */ 2069 attrstr = gettext(" attribute "); 2070 src_size = strlen(source) + 2071 strlen(dp->d_name) + strlen(attrstr) + 1; 2072 srcbuf = malloc(src_size); 2073 2074 if (srcbuf == NULL) { 2075 if (!attrsilent) { 2076 (void) fprintf(stderr, 2077 gettext("%s: could not allocate memory" 2078 " for path buffer: "), cmd); 2079 perror(""); 2080 ++error; 2081 } 2082 goto next; 2083 } 2084 targ_size = strlen(target) + 2085 strlen(dp->d_name) + strlen(attrstr) + 1; 2086 targbuf = malloc(targ_size); 2087 if (targbuf == NULL) { 2088 if (!attrsilent) { 2089 (void) fprintf(stderr, 2090 gettext("%s: could not allocate memory" 2091 " for path buffer: "), cmd); 2092 perror(""); 2093 ++error; 2094 } 2095 goto next; 2096 } 2097 2098 (void) snprintf(srcbuf, src_size, "%s%s%s", 2099 source, attrstr, dp->d_name); 2100 (void) snprintf(targbuf, targ_size, "%s%s%s", 2101 target, attrstr, dp->d_name); 2102 2103 if (writefile(srcattrfd, targattrfd, 2104 srcbuf, targbuf, &s3, &s4) != 0) { 2105 if (!attrsilent) { 2106 ++error; 2107 } 2108 goto next; 2109 } 2110 2111 if (pflg || mve) { 2112 mode = FMODE(s3); 2113 2114 if (fchown(targattrfd, UID(s3), GID(s3)) != 0) { 2115 if (!attrsilent) { 2116 (void) fprintf(stderr, 2117 gettext("%s: cannot change" 2118 " owner and group of" 2119 " attribute %s for" " file" 2120 " %s: "), cmd, dp->d_name, target); 2121 perror(""); 2122 ++error; 2123 } 2124 if (mode & (S_ISUID | S_ISGID)) { 2125 /* try to clear S_ISUID and S_ISGID */ 2126 mode &= ~S_ISUID & ~S_ISGID; 2127 ++clearflg; 2128 } 2129 } 2130 /* tv_usec were cleared above */ 2131 times[0].tv_sec = s3.st_atime; 2132 times[1].tv_sec = s3.st_mtime; 2133 if (futimesat(targetdirfd, dp->d_name, times) < 0) { 2134 if (!attrsilent) { 2135 (void) fprintf(stderr, 2136 gettext("%s: cannot set attribute" 2137 " times for %s: "), cmd, target); 2138 perror(""); 2139 ++error; 2140 } 2141 } 2142 if (fchmod(targattrfd, mode) != 0) { 2143 if (clearflg) { 2144 (void) fprintf(stderr, gettext( 2145 "%s: cannot clear S_ISUID and " 2146 "S_ISGID bits in attribute %s" 2147 " for file" 2148 " %s: "), cmd, dp->d_name, target); 2149 } else { 2150 if (!attrsilent) { 2151 (void) fprintf(stderr, 2152 gettext( 2153 "%s: cannot set permissions of attribute" 2154 " %s for %s: "), cmd, dp->d_name, target); 2155 perror(""); 2156 ++error; 2157 } 2158 } 2159 } 2160 } 2161 next: 2162 if (xacl != NULL) { 2163 acl_free(xacl); 2164 xacl = NULL; 2165 } 2166 if (srcbuf != NULL) 2167 free(srcbuf); 2168 if (targbuf != NULL) 2169 free(targbuf); 2170 if (srcattrfd != -1) 2171 (void) close(srcattrfd); 2172 if (targattrfd != -1) 2173 (void) close(targattrfd); 2174 srcattrfd = targattrfd = -1; 2175 srcbuf = targbuf = NULL; 2176 } 2177 out: 2178 if (xacl != NULL) { 2179 acl_free(xacl); 2180 xacl = NULL; 2181 } 2182 if (attrdiracl != NULL) { 2183 acl_free(attrdiracl); 2184 attrdiracl = NULL; 2185 } 2186 if (srcbuf) 2187 free(srcbuf); 2188 if (targbuf) 2189 free(targbuf); 2190 if (sourcedirfd != -1) 2191 (void) close(sourcedirfd); 2192 if (targetdirfd != -1) 2193 (void) close(targetdirfd); 2194 if (srcdirp != NULL) 2195 (void) closedir(srcdirp); 2196 if (srcfd != -1) 2197 (void) close(srcfd); 2198 if (targfd != -1) 2199 (void) close(targfd); 2200 return (error == 0 ? 0 : 1); 2201 } 2202 2203 /* 2204 * nanoseconds are rounded off to microseconds by flooring. 2205 */ 2206 static void 2207 timestruc_to_timeval(timestruc_t *ts, struct timeval *tv) 2208 { 2209 tv->tv_sec = ts->tv_sec; 2210 tv->tv_usec = ts->tv_nsec / 1000; 2211 } 2212