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