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