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