17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
594d2b9amarks * Common Development and Distribution License (the "License").
694d2b9amarks * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
2178cca7eRoger A. Faulkner
227c478bdstevel@tonic-gate/*
236cdb722Alexander Eremin * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
246cdb722Alexander Eremin */
256cdb722Alexander Eremin
266cdb722Alexander Eremin/*
27ee9c203Renaud Manus * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
287c478bdstevel@tonic-gate * Use is subject to license terms.
297c478bdstevel@tonic-gate */
307c478bdstevel@tonic-gate
317c478bdstevel@tonic-gate/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
327c478bdstevel@tonic-gate/*	  All Rights Reserved  	*/
337c478bdstevel@tonic-gate
347c478bdstevel@tonic-gate/*
3531b6814John Levon * Copyright (c) 2018, Joyent, Inc.
3631b6814John Levon */
3731b6814John Levon
3831b6814John Levon/*
397c478bdstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
407c478bdstevel@tonic-gate * The Regents of the University of California
417c478bdstevel@tonic-gate * All Rights Reserved
427c478bdstevel@tonic-gate *
437c478bdstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
447c478bdstevel@tonic-gate * software developed by the University of California, Berkeley, and its
457c478bdstevel@tonic-gate * contributors.
467c478bdstevel@tonic-gate */
477c478bdstevel@tonic-gate
487c478bdstevel@tonic-gate/*
497c478bdstevel@tonic-gate * Combined mv/cp/ln command:
507c478bdstevel@tonic-gate *	mv file1 file2
517c478bdstevel@tonic-gate *	mv dir1 dir2
527c478bdstevel@tonic-gate *	mv file1 ... filen dir1
537c478bdstevel@tonic-gate */
547c478bdstevel@tonic-gate#include <sys/time.h>
557c478bdstevel@tonic-gate#include <signal.h>
567c478bdstevel@tonic-gate#include <locale.h>
577c478bdstevel@tonic-gate#include <stdarg.h>
587c478bdstevel@tonic-gate#include <sys/acl.h>
597c478bdstevel@tonic-gate#include <libcmdutils.h>
60fa9e406ahrens#include <aclutils.h>
613d63ea0as#include "getresponse.h"
627c478bdstevel@tonic-gate
637c478bdstevel@tonic-gate#define	FTYPE(A)	(A.st_mode)
647c478bdstevel@tonic-gate#define	FMODE(A)	(A.st_mode)
657c478bdstevel@tonic-gate#define	UID(A)		(A.st_uid)
667c478bdstevel@tonic-gate#define	GID(A)		(A.st_gid)
677c478bdstevel@tonic-gate#define	IDENTICAL(A, B)	(A.st_dev == B.st_dev && A.st_ino == B.st_ino)
687c478bdstevel@tonic-gate#define	ISDIR(A)	((A.st_mode & S_IFMT) == S_IFDIR)
697c478bdstevel@tonic-gate#define	ISDOOR(A)	((A.st_mode & S_IFMT) == S_IFDOOR)
707c478bdstevel@tonic-gate#define	ISLNK(A)	((A.st_mode & S_IFMT) == S_IFLNK)
717c478bdstevel@tonic-gate#define	ISREG(A)	(((A).st_mode & S_IFMT) == S_IFREG)
727c478bdstevel@tonic-gate#define	ISDEV(A)	((A.st_mode & S_IFMT) == S_IFCHR || \
737c478bdstevel@tonic-gate			(A.st_mode & S_IFMT) == S_IFBLK || \
747c478bdstevel@tonic-gate			(A.st_mode & S_IFMT) == S_IFIFO)
75e1636a0danny webster#define	ISSOCK(A)	((A.st_mode & S_IFMT) == S_IFSOCK)
767c478bdstevel@tonic-gate
777c478bdstevel@tonic-gate#define	DELIM	'/'
787c478bdstevel@tonic-gate#define	EQ(x, y)	(strcmp(x, y) == 0)
797c478bdstevel@tonic-gate#define	FALSE	0
807c478bdstevel@tonic-gate#define	MODEBITS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
817c478bdstevel@tonic-gate#define	TRUE 1
827c478bdstevel@tonic-gate
837c478bdstevel@tonic-gatestatic char		*dname(char *);
847c478bdstevel@tonic-gatestatic int		lnkfil(char *, char *);
857c478bdstevel@tonic-gatestatic int		cpymve(char *, char *);
867c478bdstevel@tonic-gatestatic int		chkfiles(char *, char **);
877c478bdstevel@tonic-gatestatic int		rcopy(char *, char *);
887c478bdstevel@tonic-gatestatic int		chk_different(char *, char *);
897c478bdstevel@tonic-gatestatic int		chg_time(char *, struct stat);
907c478bdstevel@tonic-gatestatic int		chg_mode(char *, uid_t, gid_t, mode_t);
917c478bdstevel@tonic-gatestatic int		copydir(char *, char *);
927c478bdstevel@tonic-gatestatic int		copyspecial(char *);
937c478bdstevel@tonic-gatestatic int		getrealpath(char *, char *);
947c478bdstevel@tonic-gatestatic void		usage(void);
957c478bdstevel@tonic-gatestatic void		Perror(char *);
967c478bdstevel@tonic-gatestatic void		Perror2(char *, char *);
977c478bdstevel@tonic-gatestatic int		use_stdin(void);
987c478bdstevel@tonic-gatestatic int		copyattributes(char *, char *);
99da6c28aamwstatic int		copy_sysattr(char *, char *);
1007c478bdstevel@tonic-gatestatic tree_node_t	*create_tnode(dev_t, ino_t);
1017c478bdstevel@tonic-gate
102da6c28aamwstatic struct stat 	s1, s2, s3, s4;
1037c478bdstevel@tonic-gatestatic int 		cpy = FALSE;
1047c478bdstevel@tonic-gatestatic int 		mve = FALSE;
1057c478bdstevel@tonic-gatestatic int 		lnk = FALSE;
1067c478bdstevel@tonic-gatestatic char		*cmd;
1077c478bdstevel@tonic-gatestatic int		silent = 0;
1087c478bdstevel@tonic-gatestatic int		fflg = 0;
1097c478bdstevel@tonic-gatestatic int		iflg = 0;
1107c478bdstevel@tonic-gatestatic int		pflg = 0;
1117c478bdstevel@tonic-gatestatic int		Rflg = 0;	/* recursive copy */
1127c478bdstevel@tonic-gatestatic int		rflg = 0;	/* recursive copy */
1137c478bdstevel@tonic-gatestatic int		sflg = 0;
1147c478bdstevel@tonic-gatestatic int		Hflg = 0;	/* follow cmd line arg symlink to dir */
1157c478bdstevel@tonic-gatestatic int		Lflg = 0;	/* follow symlinks */
1167c478bdstevel@tonic-gatestatic int		Pflg = 0;	/* do not follow symlinks */
1177c478bdstevel@tonic-gatestatic int		atflg = 0;
1187c478bdstevel@tonic-gatestatic int		attrsilent = 0;
1197c478bdstevel@tonic-gatestatic int		targetexists = 0;
1207c478bdstevel@tonic-gatestatic int		cmdarg;		/* command line argument */
1217c478bdstevel@tonic-gatestatic avl_tree_t	*stree = NULL;	/* source file inode search tree */
122fa9e406ahrensstatic acl_t		*s1acl;
123da6c28aamwstatic int		saflg = 0;	/* 'cp' extended system attr. */
124beab021basabistatic int		srcfd = -1;
125beab021basabistatic int		targfd = -1;
126beab021basabistatic int		sourcedirfd = -1;
127beab021basabistatic int		targetdirfd = -1;
128beab021basabistatic DIR 		*srcdirp = NULL;
129beab021basabistatic int		srcattrfd = -1;
130beab021basabistatic int		targattrfd = -1;
131da6c28aamwstatic struct stat 	attrdir;
132da6c28aamw
133da6c28aamw/* Extended system attributes support */
134da6c28aamw
135da6c28aamwstatic int open_source(char  *);
136da6c28aamwstatic int open_target_srctarg_attrdirs(char  *, char *);
137da6c28aamwstatic int open_attrdirp(char *);
138da6c28aamwstatic int traverse_attrfile(struct dirent *, char *, char *, int);
139da6c28aamwstatic void rewind_attrdir(DIR *);
140da6c28aamwstatic void close_all();
141da6c28aamw
1427c478bdstevel@tonic-gate
143a77d64acfint
1447c478bdstevel@tonic-gatemain(int argc, char *argv[])
1457c478bdstevel@tonic-gate{
1467c478bdstevel@tonic-gate	int c, i, r, errflg = 0;
1477c478bdstevel@tonic-gate	char target[PATH_MAX];
1487c478bdstevel@tonic-gate	int (*move)(char *, char *);
1497c478bdstevel@tonic-gate
1507c478bdstevel@tonic-gate	/*
1517c478bdstevel@tonic-gate	 * Determine command invoked (mv, cp, or ln)
1527c478bdstevel@tonic-gate	 */
1537c478bdstevel@tonic-gate
1547c478bdstevel@tonic-gate	if (cmd = strrchr(argv[0], '/'))
1557c478bdstevel@tonic-gate		++cmd;
1567c478bdstevel@tonic-gate	else
1577c478bdstevel@tonic-gate		cmd = argv[0];
1587c478bdstevel@tonic-gate
1597c478bdstevel@tonic-gate	/*
1607c478bdstevel@tonic-gate	 * Set flags based on command.
1617c478bdstevel@tonic-gate	 */
1627c478bdstevel@tonic-gate
1637c478bdstevel@tonic-gate	(void) setlocale(LC_ALL, "");
1647c478bdstevel@tonic-gate#if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
1657c478bdstevel@tonic-gate#define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
1667c478bdstevel@tonic-gate#endif
1677c478bdstevel@tonic-gate	(void) textdomain(TEXT_DOMAIN);
1683d63ea0as	if (init_yes() < 0) {
1693d63ea0as		(void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
1703d63ea0as		    strerror(errno));
1713d63ea0as		exit(3);
1723d63ea0as	}
1737c478bdstevel@tonic-gate
1747c478bdstevel@tonic-gate	if (EQ(cmd, "mv"))
1757c478bdstevel@tonic-gate		mve = TRUE;
1767c478bdstevel@tonic-gate	else if (EQ(cmd, "ln"))
1777c478bdstevel@tonic-gate		lnk = TRUE;
1787c478bdstevel@tonic-gate	else if (EQ(cmd, "cp"))
1797c478bdstevel@tonic-gate		cpy = TRUE;
1807c478bdstevel@tonic-gate	else {
1817c478bdstevel@tonic-gate		(void) fprintf(stderr,
1827c478bdstevel@tonic-gate		    gettext("Invalid command name (%s); expecting "
1837c478bdstevel@tonic-gate		    "mv, cp, or ln.\n"), cmd);
1847c478bdstevel@tonic-gate		exit(1);
1857c478bdstevel@tonic-gate	}
1867c478bdstevel@tonic-gate
1877c478bdstevel@tonic-gate	/*
1887c478bdstevel@tonic-gate	 * Check for options:
1899e64776Alexander Eremin	 * 	cp [ -r|-R [-H|-L|-P]] [-afip@/] file1 [file2 ...] target
1909e64776Alexander Eremin	 * 	cp [-afiprR@/] file1 [file2 ...] target
1917c478bdstevel@tonic-gate	 *	ln [-f] [-n] [-s] file1 [file2 ...] target
1927c478bdstevel@tonic-gate	 *	ln [-f] [-n] [-s] file1 [file2 ...]
1937c478bdstevel@tonic-gate	 *	mv [-f|i] file1 [file2 ...] target
1947c478bdstevel@tonic-gate	 *	mv [-f|i] dir1 target
1957c478bdstevel@tonic-gate	 */
1967c478bdstevel@tonic-gate
1977c478bdstevel@tonic-gate	if (cpy) {
1989e64776Alexander Eremin		while ((c = getopt(argc, argv, "afHiLpPrR@/")) != EOF)
1997c478bdstevel@tonic-gate			switch (c) {
2007c478bdstevel@tonic-gate			case 'f':
2017c478bdstevel@tonic-gate				fflg++;
2027c478bdstevel@tonic-gate				break;
2037c478bdstevel@tonic-gate			case 'i':
2047c478bdstevel@tonic-gate				iflg++;
2057c478bdstevel@tonic-gate				break;
2067c478bdstevel@tonic-gate			case 'p':
2077c478bdstevel@tonic-gate				pflg++;
2087c478bdstevel@tonic-gate#ifdef XPG4
2097c478bdstevel@tonic-gate				attrsilent = 1;
2107c478bdstevel@tonic-gate				atflg = 0;
211da6c28aamw				saflg = 0;
2127c478bdstevel@tonic-gate#else
213cee1ddabasabi				if (atflg == 0)
2147c478bdstevel@tonic-gate					attrsilent = 1;
2157c478bdstevel@tonic-gate#endif
2167c478bdstevel@tonic-gate				break;
2177c478bdstevel@tonic-gate			case 'H':
2187c478bdstevel@tonic-gate				/*
2197c478bdstevel@tonic-gate				 * If more than one of -H, -L, or -P are
2207c478bdstevel@tonic-gate				 * specified, only the last option specified
2217c478bdstevel@tonic-gate				 * determines the behavior.
2227c478bdstevel@tonic-gate				 */
2237c478bdstevel@tonic-gate				Lflg = Pflg = 0;
2247c478bdstevel@tonic-gate				Hflg++;
2257c478bdstevel@tonic-gate				break;
2267c478bdstevel@tonic-gate			case 'L':
2277c478bdstevel@tonic-gate				Hflg = Pflg = 0;
2287c478bdstevel@tonic-gate				Lflg++;
2297c478bdstevel@tonic-gate				break;
2307c478bdstevel@tonic-gate			case 'P':
2317c478bdstevel@tonic-gate				Lflg = Hflg = 0;
2327c478bdstevel@tonic-gate				Pflg++;
2337c478bdstevel@tonic-gate				break;
2347c478bdstevel@tonic-gate			case 'R':
2357c478bdstevel@tonic-gate				/*
2367c478bdstevel@tonic-gate				 * The default behavior of cp -R|-r
2377c478bdstevel@tonic-gate				 * when specified without -H|-L|-P
2387c478bdstevel@tonic-gate				 * is -L.
2397c478bdstevel@tonic-gate				 */
2407c478bdstevel@tonic-gate				Rflg++;
2417c478bdstevel@tonic-gate				/*FALLTHROUGH*/
2427c478bdstevel@tonic-gate			case 'r':
2437c478bdstevel@tonic-gate				rflg++;
2447c478bdstevel@tonic-gate				break;
2459e64776Alexander Eremin			case 'a':
2469e64776Alexander Eremin				Lflg = Hflg = 0;
2479e64776Alexander Eremin				pflg++;
2489e64776Alexander Eremin				Pflg++;
2499e64776Alexander Eremin				Rflg++;
2509e64776Alexander Eremin				rflg++;
2519e64776Alexander Eremin				break;
2527c478bdstevel@tonic-gate			case '@':
2537c478bdstevel@tonic-gate				atflg++;
2547c478bdstevel@tonic-gate				attrsilent = 0;
2557c478bdstevel@tonic-gate#ifdef XPG4
2567c478bdstevel@tonic-gate				pflg = 0;
2577c478bdstevel@tonic-gate#endif
2587c478bdstevel@tonic-gate				break;
259da6c28aamw			case '/':
260da6c28aamw				saflg++;
261da6c28aamw				attrsilent = 0;
262da6c28aamw#ifdef XPG4
263da6c28aamw				pflg = 0;
264da6c28aamw#endif
265da6c28aamw				break;
2667c478bdstevel@tonic-gate			default:
2677c478bdstevel@tonic-gate				errflg++;
2687c478bdstevel@tonic-gate			}
2697c478bdstevel@tonic-gate
2707c478bdstevel@tonic-gate		/* -R or -r must be specified with -H, -L, or -P */
2717c478bdstevel@tonic-gate		if ((Hflg || Lflg || Pflg) && !(Rflg || rflg)) {
2727c478bdstevel@tonic-gate			errflg++;
2737c478bdstevel@tonic-gate		}
2747c478bdstevel@tonic-gate
2757c478bdstevel@tonic-gate	} else if (mve) {
2767c478bdstevel@tonic-gate		while ((c = getopt(argc, argv, "fis")) != EOF)
2777c478bdstevel@tonic-gate			switch (c) {
2787c478bdstevel@tonic-gate			case 'f':
2797c478bdstevel@tonic-gate				silent++;
2807c478bdstevel@tonic-gate#ifdef XPG4
2817c478bdstevel@tonic-gate				iflg = 0;
2827c478bdstevel@tonic-gate#endif
2837c478bdstevel@tonic-gate				break;
2847c478bdstevel@tonic-gate			case 'i':
2857c478bdstevel@tonic-gate				iflg++;
2867c478bdstevel@tonic-gate#ifdef XPG4
2877c478bdstevel@tonic-gate				silent = 0;
2887c478bdstevel@tonic-gate#endif
2897c478bdstevel@tonic-gate				break;
2907c478bdstevel@tonic-gate			default:
2917c478bdstevel@tonic-gate				errflg++;
2927c478bdstevel@tonic-gate			}
2937c478bdstevel@tonic-gate	} else { /* ln */
2947c478bdstevel@tonic-gate		while ((c = getopt(argc, argv, "fns")) != EOF)
2957c478bdstevel@tonic-gate			switch (c) {
2967c478bdstevel@tonic-gate			case 'f':
2977c478bdstevel@tonic-gate				silent++;
2987c478bdstevel@tonic-gate				break;
2997c478bdstevel@tonic-gate			case 'n':
3007c478bdstevel@tonic-gate				/* silently ignored; this is the default */
3017c478bdstevel@tonic-gate				break;
3027c478bdstevel@tonic-gate			case 's':
3037c478bdstevel@tonic-gate				sflg++;
3047c478bdstevel@tonic-gate				break;
3057c478bdstevel@tonic-gate			default:
3067c478bdstevel@tonic-gate				errflg++;
3077c478bdstevel@tonic-gate			}
3087c478bdstevel@tonic-gate	}
3097c478bdstevel@tonic-gate
3107c478bdstevel@tonic-gate	/*
3117c478bdstevel@tonic-gate	 * For BSD compatibility allow - to delimit the end of
3127c478bdstevel@tonic-gate	 * options for mv.
3137c478bdstevel@tonic-gate	 */
3147c478bdstevel@tonic-gate	if (mve && optind < argc && (strcmp(argv[optind], "-") == 0))
3157c478bdstevel@tonic-gate		optind++;
3167c478bdstevel@tonic-gate
3177c478bdstevel@tonic-gate	/*
3187c478bdstevel@tonic-gate	 * Check for sufficient arguments
3197c478bdstevel@tonic-gate	 * or a usage error.
3207c478bdstevel@tonic-gate	 */
3217c478bdstevel@tonic-gate
3227c478bdstevel@tonic-gate	argc -= optind;
3237c478bdstevel@tonic-gate	argv  = &argv[optind];
3247c478bdstevel@tonic-gate
3257c478bdstevel@tonic-gate	if ((argc < 2 && lnk != TRUE) || (argc < 1 && lnk == TRUE)) {
3267c478bdstevel@tonic-gate		(void) fprintf(stderr,
3277c478bdstevel@tonic-gate		    gettext("%s: Insufficient arguments (%d)\n"),
3287c478bdstevel@tonic-gate		    cmd, argc);
3297c478bdstevel@tonic-gate		usage();
3307c478bdstevel@tonic-gate	}
3317c478bdstevel@tonic-gate
3327c478bdstevel@tonic-gate	if (errflg != 0)
3337c478bdstevel@tonic-gate		usage();
3347c478bdstevel@tonic-gate
3357c478bdstevel@tonic-gate	/*
3367c478bdstevel@tonic-gate	 * If there is more than a source and target,
3377c478bdstevel@tonic-gate	 * the last argument (the target) must be a directory
3387c478bdstevel@tonic-gate	 * which really exists.
3397c478bdstevel@tonic-gate	 */
3407c478bdstevel@tonic-gate
3417c478bdstevel@tonic-gate	if (argc > 2) {
3427c478bdstevel@tonic-gate		if (stat(argv[argc-1], &s2) < 0) {
3437c478bdstevel@tonic-gate			(void) fprintf(stderr,
3447c478bdstevel@tonic-gate			    gettext("%s: %s not found\n"),
3457c478bdstevel@tonic-gate			    cmd, argv[argc-1]);
3467c478bdstevel@tonic-gate			exit(2);
3477c478bdstevel@tonic-gate		}
3487c478bdstevel@tonic-gate
3497c478bdstevel@tonic-gate		if (!ISDIR(s2)) {
3507c478bdstevel@tonic-gate			(void) fprintf(stderr,
3517c478bdstevel@tonic-gate			    gettext("%s: Target %s must be a directory\n"),
3527c478bdstevel@tonic-gate			    cmd, argv[argc-1]);
3537c478bdstevel@tonic-gate			usage();
3547c478bdstevel@tonic-gate		}
3557c478bdstevel@tonic-gate	}
3567c478bdstevel@tonic-gate
3577c478bdstevel@tonic-gate	if (strlen(argv[argc-1]) >= PATH_MAX) {
3587c478bdstevel@tonic-gate		(void) fprintf(stderr,
3597c478bdstevel@tonic-gate		    gettext("%s: Target %s file name length exceeds PATH_MAX"
3607c478bdstevel@tonic-gate		    " %d\n"), cmd, argv[argc-1], PATH_MAX);
3617c478bdstevel@tonic-gate		exit(78);
3627c478bdstevel@tonic-gate	}
3637c478bdstevel@tonic-gate
3647c478bdstevel@tonic-gate	if (argc == 1) {
3657c478bdstevel@tonic-gate		if (!lnk)
3667c478bdstevel@tonic-gate			usage();
3677c478bdstevel@tonic-gate		(void) strcpy(target, ".");
3687c478bdstevel@tonic-gate	} else {
3697c478bdstevel@tonic-gate		(void) strcpy(target, argv[--argc]);
3707c478bdstevel@tonic-gate	}
3717c478bdstevel@tonic-gate
3727c478bdstevel@tonic-gate	/*
3737c478bdstevel@tonic-gate	 * Perform a multiple argument mv|cp|ln by
3747c478bdstevel@tonic-gate	 * multiple invocations of cpymve() or lnkfil().
3757c478bdstevel@tonic-gate	 */
3767c478bdstevel@tonic-gate	if (lnk)
3777c478bdstevel@tonic-gate		move = lnkfil;
3787c478bdstevel@tonic-gate	else
3797c478bdstevel@tonic-gate		move = cpymve;
3807c478bdstevel@tonic-gate
3817c478bdstevel@tonic-gate	r = 0;
3827c478bdstevel@tonic-gate	for (i = 0; i < argc; i++) {
3837c478bdstevel@tonic-gate		stree = NULL;
3847c478bdstevel@tonic-gate		cmdarg = 1;
3857c478bdstevel@tonic-gate		r += move(argv[i], target);
3867c478bdstevel@tonic-gate	}
3877c478bdstevel@tonic-gate
3887c478bdstevel@tonic-gate	/*
3897c478bdstevel@tonic-gate	 * Show errors by nonzero exit code.
3907c478bdstevel@tonic-gate	 */
3917c478bdstevel@tonic-gate
392a77d64acf	return (r?2:0);
3937c478bdstevel@tonic-gate}
3947c478bdstevel@tonic-gate
3957c478bdstevel@tonic-gatestatic int
3967c478bdstevel@tonic-gatelnkfil(char *source, char *target)
3977c478bdstevel@tonic-gate{
3987c478bdstevel@tonic-gate	char	*buf = NULL;
3997c478bdstevel@tonic-gate
4007c478bdstevel@tonic-gate	if (sflg) {
4017c478bdstevel@tonic-gate
4027c478bdstevel@tonic-gate		/*
4037c478bdstevel@tonic-gate		 * If target is a directory make complete
4047c478bdstevel@tonic-gate		 * name of the new symbolic link within that
4057c478bdstevel@tonic-gate		 * directory.
4067c478bdstevel@tonic-gate		 */
4077c478bdstevel@tonic-gate
4087c478bdstevel@tonic-gate		if ((stat(target, &s2) >= 0) && ISDIR(s2)) {
4097c478bdstevel@tonic-gate			size_t len;
4107c478bdstevel@tonic-gate
4117c478bdstevel@tonic-gate			len = strlen(target) + strlen(dname(source)) + 4;
4127c478bdstevel@tonic-gate			if ((buf = (char *)malloc(len)) == NULL) {
4137c478bdstevel@tonic-gate				(void) fprintf(stderr,
4147c478bdstevel@tonic-gate				    gettext("%s: Insufficient memory "
4157c478bdstevel@tonic-gate				    "to %s %s\n"), cmd, cmd, source);
4167c478bdstevel@tonic-gate				exit(3);
4177c478bdstevel@tonic-gate			}
4187c478bdstevel@tonic-gate			(void) snprintf(buf, len, "%s/%s",
4197c478bdstevel@tonic-gate			    target, dname(source));
4207c478bdstevel@tonic-gate			target = buf;
4217c478bdstevel@tonic-gate		}
4227c478bdstevel@tonic-gate
4237c478bdstevel@tonic-gate		/*
4246fcd7f7chin		 * Check to see if the file exists already.
4256fcd7f7chin		 * In this case we use lstat() instead of stat():
4266fcd7f7chin		 * unlink(2) and symlink(2) will operate on the file
4276fcd7f7chin		 * itself, not its reference, if the file is a symlink.
4287c478bdstevel@tonic-gate		 */
4297c478bdstevel@tonic-gate
4306fcd7f7chin		if ((lstat(target, &s2) == 0)) {
4317c478bdstevel@tonic-gate			/*
4327c478bdstevel@tonic-gate			 * Check if the silent flag is set ie. the -f option
4337c478bdstevel@tonic-gate			 * is used.  If so, use unlink to remove the current
4347c478bdstevel@tonic-gate			 * target to replace with the new target, specified
4357c478bdstevel@tonic-gate			 * on the command line.  Proceed with symlink.
4367c478bdstevel@tonic-gate			 */
4377c478bdstevel@tonic-gate			if (silent) {
4386fcd7f7chin			/*
4396fcd7f7chin			 * Don't allow silent (-f) removal of an existing
4406fcd7f7chin			 * directory; could leave unreferenced directory
4416fcd7f7chin			 * entries.
4426fcd7f7chin			 */
4436fcd7f7chin				if (ISDIR(s2)) {
4446fcd7f7chin					(void) fprintf(stderr,
4456fcd7f7chin					    gettext("%s: cannot create link "
4466fcd7f7chin					    "over directory %s\n"), cmd,
4476fcd7f7chin					    target);
4486fcd7f7chin					return (1);
4496fcd7f7chin				}
4507c478bdstevel@tonic-gate				if (unlink(target) < 0) {
4517c478bdstevel@tonic-gate					(void) fprintf(stderr,
4527c478bdstevel@tonic-gate					    gettext("%s: cannot unlink %s: "),
4537c478bdstevel@tonic-gate					    cmd, target);
4547c478bdstevel@tonic-gate					perror("");
4557c478bdstevel@tonic-gate					return (1);
4567c478bdstevel@tonic-gate				}
4577c478bdstevel@tonic-gate			}
4587c478bdstevel@tonic-gate		}
4597c478bdstevel@tonic-gate
4607c478bdstevel@tonic-gate
4617c478bdstevel@tonic-gate		/*
4627c478bdstevel@tonic-gate		 * Create a symbolic link to the source.
4637c478bdstevel@tonic-gate		 */
4647c478bdstevel@tonic-gate
4657c478bdstevel@tonic-gate		if (symlink(source, target) < 0) {
4667c478bdstevel@tonic-gate			(void) fprintf(stderr,
4677c478bdstevel@tonic-gate			    gettext("%s: cannot create %s: "),
4687c478bdstevel@tonic-gate			    cmd, target);
4697c478bdstevel@tonic-gate			perror("");
4707c478bdstevel@tonic-gate			if (buf != NULL)
4717c478bdstevel@tonic-gate				free(buf);
4727c478bdstevel@tonic-gate			return (1);
4737c478bdstevel@tonic-gate		}
4747c478bdstevel@tonic-gate		if (buf != NULL)
4757c478bdstevel@tonic-gate			free(buf);
4767c478bdstevel@tonic-gate		return (0);
4777c478bdstevel@tonic-gate	}
4787c478bdstevel@tonic-gate
4797c478bdstevel@tonic-gate	switch (chkfiles(source, &target)) {
4807c478bdstevel@tonic-gate		case 1: return (1);
4817c478bdstevel@tonic-gate		case 2: return (0);
4827c478bdstevel@tonic-gate			/* default - fall through */
4837c478bdstevel@tonic-gate	}
4847c478bdstevel@tonic-gate
4857c478bdstevel@tonic-gate	/*
4867c478bdstevel@tonic-gate	 * Make sure source file is not a directory,
487e1636a0danny webster	 * we cannot link directories...
4887c478bdstevel@tonic-gate	 */
4897c478bdstevel@tonic-gate
4907c478bdstevel@tonic-gate	if (ISDIR(s1)) {
4917c478bdstevel@tonic-gate		(void) fprintf(stderr,
4927c478bdstevel@tonic-gate		    gettext("%s: %s is a directory\n"), cmd, source);
4937c478bdstevel@tonic-gate		return (1);
4947c478bdstevel@tonic-gate	}
4957c478bdstevel@tonic-gate
4967c478bdstevel@tonic-gate	/*
4977c478bdstevel@tonic-gate	 * hard link, call link() and return.
4987c478bdstevel@tonic-gate	 */
4997c478bdstevel@tonic-gate
5007c478bdstevel@tonic-gate	if (link(source, target) < 0) {
5017c478bdstevel@tonic-gate		if (errno == EXDEV)
5027c478bdstevel@tonic-gate			(void) fprintf(stderr,
5037c478bdstevel@tonic-gate			    gettext("%s: %s is on a different file system\n"),
5047c478bdstevel@tonic-gate			    cmd, target);
5057c478bdstevel@tonic-gate		else {
5067c478bdstevel@tonic-gate			(void) fprintf(stderr,
5077c478bdstevel@tonic-gate			    gettext("%s: cannot create link %s: "),
5087c478bdstevel@tonic-gate			    cmd, target);
5097c478bdstevel@tonic-gate			perror("");
5107c478bdstevel@tonic-gate		}
5117c478bdstevel@tonic-gate		if (buf != NULL)
5127c478bdstevel@tonic-gate			free(buf);
5137c478bdstevel@tonic-gate		return (1);
5147c478bdstevel@tonic-gate	} else {
5157c478bdstevel@tonic-gate		if (buf != NULL)
5167c478bdstevel@tonic-gate			free(buf);
5177c478bdstevel@tonic-gate		return (0);
5187c478bdstevel@tonic-gate	}
5197c478bdstevel@tonic-gate}
5207c478bdstevel@tonic-gate
5217c478bdstevel@tonic-gatestatic int
5227c478bdstevel@tonic-gatecpymve(char *source, char *target)
5237c478bdstevel@tonic-gate{
5247c478bdstevel@tonic-gate	int	n;
5257c478bdstevel@tonic-gate	int fi, fo;
5267c478bdstevel@tonic-gate	int ret = 0;
5277c478bdstevel@tonic-gate	int attret = 0;
528da6c28aamw	int sattret = 0;
5297c478bdstevel@tonic-gate	int errno_save;
530cee1ddabasabi	int error = 0;
5317c478bdstevel@tonic-gate
5327c478bdstevel@tonic-gate	switch (chkfiles(source, &target)) {
5337c478bdstevel@tonic-gate		case 1: return (1);
5347c478bdstevel@tonic-gate		case 2: return (0);
5357c478bdstevel@tonic-gate			/* default - fall through */
5367c478bdstevel@tonic-gate	}
5377c478bdstevel@tonic-gate
5387c478bdstevel@tonic-gate	/*
5397c478bdstevel@tonic-gate	 * If it's a recursive copy and source
5407c478bdstevel@tonic-gate	 * is a directory, then call rcopy (from copydir).
5417c478bdstevel@tonic-gate	 */
5427c478bdstevel@tonic-gate	if (cpy) {
5437c478bdstevel@tonic-gate		if (ISDIR(s1)) {
5447c478bdstevel@tonic-gate			int		rc;
5457c478bdstevel@tonic-gate			avl_index_t	where = 0;
5467c478bdstevel@tonic-gate			tree_node_t	*tnode;
5477c478bdstevel@tonic-gate			tree_node_t	*tptr;
5487c478bdstevel@tonic-gate			dev_t		save_dev = s1.st_dev;
5497c478bdstevel@tonic-gate			ino_t		save_ino = s1.st_ino;
5507c478bdstevel@tonic-gate
5517c478bdstevel@tonic-gate			/*
5527c478bdstevel@tonic-gate			 * We will be recursing into the directory so
5537c478bdstevel@tonic-gate			 * save the inode information to a search tree
5547c478bdstevel@tonic-gate			 * to avoid getting into an endless loop.
5557c478bdstevel@tonic-gate			 */
5567c478bdstevel@tonic-gate			if ((rc = add_tnode(&stree, save_dev, save_ino)) != 1) {
5577c478bdstevel@tonic-gate				if (rc == 0) {
5587c478bdstevel@tonic-gate					/*
5597c478bdstevel@tonic-gate					 * We've already visited this directory.
5607c478bdstevel@tonic-gate					 * Don't remove the search tree entry
5617c478bdstevel@tonic-gate					 * to make sure we don't get into an
5627c478bdstevel@tonic-gate					 * endless loop if revisited from a
5637c478bdstevel@tonic-gate					 * different part of the hierarchy.
5647c478bdstevel@tonic-gate					 */
5657c478bdstevel@tonic-gate					(void) fprintf(stderr, gettext(
5667c478bdstevel@tonic-gate					    "%s: cycle detected: %s\n"),
5677c478bdstevel@tonic-gate					    cmd, source);
5687c478bdstevel@tonic-gate				} else {
5697c478bdstevel@tonic-gate					Perror(source);
5707c478bdstevel@tonic-gate				}
5717c478bdstevel@tonic-gate				return (1);
5727c478bdstevel@tonic-gate			}
5737c478bdstevel@tonic-gate
5747c478bdstevel@tonic-gate			cmdarg = 0;
5757c478bdstevel@tonic-gate			rc = copydir(source, target);
5767c478bdstevel@tonic-gate
5777c478bdstevel@tonic-gate			/*
5787c478bdstevel@tonic-gate			 * Create a tnode to get an index to the matching
5797c478bdstevel@tonic-gate			 * node (same dev and inode) in the search tree,
5807c478bdstevel@tonic-gate			 * then use the index to remove the matching node
5817c478bdstevel@tonic-gate			 * so it we do not wrongly detect a cycle when
5827c478bdstevel@tonic-gate			 * revisiting this directory from another part of
5837c478bdstevel@tonic-gate			 * the hierarchy.
5847c478bdstevel@tonic-gate			 */
5857c478bdstevel@tonic-gate			if ((tnode = create_tnode(save_dev,
5867c478bdstevel@tonic-gate			    save_ino)) == NULL) {
5877c478bdstevel@tonic-gate				Perror(source);
5887c478bdstevel@tonic-gate				return (1);
5897c478bdstevel@tonic-gate			}
5907c478bdstevel@tonic-gate			if ((tptr = avl_find(stree, tnode, &where)) != NULL) {
5917c478bdstevel@tonic-gate				avl_remove(stree, tptr);
5927c478bdstevel@tonic-gate			}
5937c478bdstevel@tonic-gate			free(tptr);
5947c478bdstevel@tonic-gate			free(tnode);
5957c478bdstevel@tonic-gate			return (rc);
5967c478bdstevel@tonic-gate
5977c478bdstevel@tonic-gate		} else if (ISDEV(s1) && Rflg) {
5987c478bdstevel@tonic-gate			return (copyspecial(target));
5997c478bdstevel@tonic-gate		} else {
6007c478bdstevel@tonic-gate			goto copy;
6017c478bdstevel@tonic-gate		}
6027c478bdstevel@tonic-gate	}
6037c478bdstevel@tonic-gate
6047c478bdstevel@tonic-gate	if (mve) {
6057c478bdstevel@tonic-gate		if (rename(source, target) >= 0)
6067c478bdstevel@tonic-gate			return (0);
6077c478bdstevel@tonic-gate		if (errno != EXDEV) {
6087c478bdstevel@tonic-gate			if (errno == ENOTDIR && ISDIR(s1)) {
6097c478bdstevel@tonic-gate				(void) fprintf(stderr,
6107c478bdstevel@tonic-gate				    gettext("%s: %s is a directory\n"),
6117c478bdstevel@tonic-gate				    cmd, source);
6127c478bdstevel@tonic-gate				return (1);
6137c478bdstevel@tonic-gate			}
6147c478bdstevel@tonic-gate			(void) fprintf(stderr,
6157c478bdstevel@tonic-gate			    gettext("%s: cannot rename %s to %s: "),
6167c478bdstevel@tonic-gate			    cmd, source, target);
6177c478bdstevel@tonic-gate			perror("");
6187c478bdstevel@tonic-gate			return (1);
6197c478bdstevel@tonic-gate		}
6207c478bdstevel@tonic-gate
6217c478bdstevel@tonic-gate		/*
6227c478bdstevel@tonic-gate		 * cannot move a non-directory (source) onto an existing
6237c478bdstevel@tonic-gate		 * directory (target)
6247c478bdstevel@tonic-gate		 *
6257c478bdstevel@tonic-gate		 */
6267c478bdstevel@tonic-gate		if (targetexists && ISDIR(s2) && (!ISDIR(s1))) {
6277c478bdstevel@tonic-gate			(void) fprintf(stderr,
6287c478bdstevel@tonic-gate			    gettext("%s: cannot mv a non directory %s "
6297c478bdstevel@tonic-gate			    "over existing directory"
6307c478bdstevel@tonic-gate			    " %s \n"), cmd, source, target);
6317c478bdstevel@tonic-gate			return (1);
6327c478bdstevel@tonic-gate		}
6337c478bdstevel@tonic-gate		if (ISDIR(s1)) {
6347c478bdstevel@tonic-gate#ifdef XPG4
6357c478bdstevel@tonic-gate			if (targetexists && ISDIR(s2)) {
6367c478bdstevel@tonic-gate				/* existing target dir must be empty */
6377c478bdstevel@tonic-gate				if (rmdir(target) < 0) {
6387c478bdstevel@tonic-gate					errno_save = errno;
6397c478bdstevel@tonic-gate					(void) fprintf(stderr,
6407c478bdstevel@tonic-gate					    gettext("%s: cannot rmdir %s: "),
6417c478bdstevel@tonic-gate					    cmd, target);
6427c478bdstevel@tonic-gate					errno = errno_save;
6437c478bdstevel@tonic-gate					perror("");
6447c478bdstevel@tonic-gate					return (1);
6457c478bdstevel@tonic-gate				}
6467c478bdstevel@tonic-gate			}
6477c478bdstevel@tonic-gate#endif
6487c478bdstevel@tonic-gate			if ((n =  copydir(source, target)) == 0)
6497c478bdstevel@tonic-gate				(void) rmdir(source);
6507c478bdstevel@tonic-gate			return (n);
6517c478bdstevel@tonic-gate		}
6527c478bdstevel@tonic-gate
653e1636a0danny webster		/* doors cannot be moved across filesystems */
6547c478bdstevel@tonic-gate		if (ISDOOR(s1)) {
6557c478bdstevel@tonic-gate			(void) fprintf(stderr,
656e1636a0danny webster			    gettext("%s: %s: cannot move door "
6577c478bdstevel@tonic-gate			    "across file systems\n"), cmd, source);
6587c478bdstevel@tonic-gate			return (1);
6597c478bdstevel@tonic-gate		}
660e1636a0danny webster
661e1636a0danny webster		/* sockets cannot be moved across filesystems */
662e1636a0danny webster		if (ISSOCK(s1)) {
663e1636a0danny webster			(void) fprintf(stderr,
664e1636a0danny webster			    gettext("%s: %s: cannot move socket "
665e1636a0danny webster			    "across file systems\n"), cmd, source);
666e1636a0danny webster			return (1);
667e1636a0danny webster		}
668e1636a0danny webster
6697c478bdstevel@tonic-gate		/*
670e1636a0danny webster		 * File cannot be renamed, try to recreate the symbolic
6717c478bdstevel@tonic-gate		 * link or special device, or copy the file wholesale
6727c478bdstevel@tonic-gate		 * between file systems.
6737c478bdstevel@tonic-gate		 */
6747c478bdstevel@tonic-gate		if (ISLNK(s1)) {
6757c478bdstevel@tonic-gate			register int	m;
6767c478bdstevel@tonic-gate			register mode_t md;
6777c478bdstevel@tonic-gate			char symln[PATH_MAX + 1];
6787c478bdstevel@tonic-gate
6797c478bdstevel@tonic-gate			if (targetexists && unlink(target) < 0) {
6807c478bdstevel@tonic-gate				(void) fprintf(stderr,
6817c478bdstevel@tonic-gate				    gettext("%s: cannot unlink %s: "),
6827c478bdstevel@tonic-gate				    cmd, target);
6837c478bdstevel@tonic-gate				perror("");
6847c478bdstevel@tonic-gate				return (1);
6857c478bdstevel@tonic-gate			}
6867c478bdstevel@tonic-gate
6877c478bdstevel@tonic-gate			if ((m = readlink(source, symln,
6887c478bdstevel@tonic-gate			    sizeof (symln) - 1)) < 0) {
6897c478bdstevel@tonic-gate				Perror(source);
6907c478bdstevel@tonic-gate				return (1);
6917c478bdstevel@tonic-gate			}
6927c478bdstevel@tonic-gate			symln[m] = '\0';
6937c478bdstevel@tonic-gate
6947c478bdstevel@tonic-gate			md = umask(~(s1.st_mode & MODEBITS));
6957c478bdstevel@tonic-gate			if (symlink(symln, target) < 0) {
6967c478bdstevel@tonic-gate				Perror(target);
6977c478bdstevel@tonic-gate				return (1);
6987c478bdstevel@tonic-gate			}
6997c478bdstevel@tonic-gate			(void) umask(md);
7007c478bdstevel@tonic-gate			m = lchown(target, UID(s1), GID(s1));
7017c478bdstevel@tonic-gate#ifdef XPG4
7027c478bdstevel@tonic-gate			if (m < 0) {
7037c478bdstevel@tonic-gate				(void) fprintf(stderr, gettext("%s: cannot"
7047c478bdstevel@tonic-gate				    " change owner and group of"
7057c478bdstevel@tonic-gate				    " %s: "), cmd, target);
7067c478bdstevel@tonic-gate				perror("");
7077c478bdstevel@tonic-gate			}
7087c478bdstevel@tonic-gate#endif
7097c478bdstevel@tonic-gate			goto cleanup;
7107c478bdstevel@tonic-gate		}
7117c478bdstevel@tonic-gate		if (ISDEV(s1)) {
7127c478bdstevel@tonic-gate
7137c478bdstevel@tonic-gate			if (targetexists && unlink(target) < 0) {
7147c478bdstevel@tonic-gate				(void) fprintf(stderr,
7157c478bdstevel@tonic-gate				    gettext("%s: cannot unlink %s: "),
7167c478bdstevel@tonic-gate				    cmd, target);
7177c478bdstevel@tonic-gate				perror("");
7187c478bdstevel@tonic-gate				return (1);
7197c478bdstevel@tonic-gate			}
7207c478bdstevel@tonic-gate
7217c478bdstevel@tonic-gate			if (mknod(target, s1.st_mode, s1.st_rdev) < 0) {
7227c478bdstevel@tonic-gate				Perror(target);
7237c478bdstevel@tonic-gate				return (1);
7247c478bdstevel@tonic-gate			}
7257c478bdstevel@tonic-gate
7267c478bdstevel@tonic-gate			(void) chg_mode(target, UID(s1), GID(s1), FMODE(s1));
7277c478bdstevel@tonic-gate			(void) chg_time(target, s1);
7287c478bdstevel@tonic-gate			goto cleanup;
7297c478bdstevel@tonic-gate		}
7307c478bdstevel@tonic-gate
7317c478bdstevel@tonic-gate		if (ISREG(s1)) {
7327c478bdstevel@tonic-gate			if (ISDIR(s2)) {
7337c478bdstevel@tonic-gate				if (targetexists && rmdir(target) < 0) {
7347c478bdstevel@tonic-gate					(void) fprintf(stderr,
7357c478bdstevel@tonic-gate					    gettext("%s: cannot rmdir %s: "),
7367c478bdstevel@tonic-gate					    cmd, target);
7377c478bdstevel@tonic-gate					perror("");
7387c478bdstevel@tonic-gate					return (1);
7397c478bdstevel@tonic-gate				}
7407c478bdstevel@tonic-gate			} else {
7417c478bdstevel@tonic-gate				if (targetexists && unlink(target) < 0) {
7427c478bdstevel@tonic-gate					(void) fprintf(stderr,
7437c478bdstevel@tonic-gate					    gettext("%s: cannot unlink %s: "),
7447c478bdstevel@tonic-gate					    cmd, target);
7457c478bdstevel@tonic-gate					perror("");
7467c478bdstevel@tonic-gate					return (1);
7477c478bdstevel@tonic-gate				}
7487c478bdstevel@tonic-gate			}
7497c478bdstevel@tonic-gate
7507c478bdstevel@tonic-gate
7517c478bdstevel@tonic-gatecopy:
7527c478bdstevel@tonic-gate			/*
7537c478bdstevel@tonic-gate			 * If the source file is a symlink, and either
7547c478bdstevel@tonic-gate			 * -P or -H flag (only if -H is specified and the
7557c478bdstevel@tonic-gate			 * source file is not a command line argument)
7567c478bdstevel@tonic-gate			 * were specified, then action is taken on the symlink
7577c478bdstevel@tonic-gate			 * itself, not the file referenced by the symlink.
7587c478bdstevel@tonic-gate			 * Note: this is executed for 'cp' only.
7597c478bdstevel@tonic-gate			 */
7607c478bdstevel@tonic-gate			if (cpy && (Pflg || (Hflg && !cmdarg)) && (ISLNK(s1))) {
7617c478bdstevel@tonic-gate				int	m;
7627c478bdstevel@tonic-gate				mode_t	md;
7637c478bdstevel@tonic-gate				char symln[PATH_MAX + 1];
7647c478bdstevel@tonic-gate
7657c478bdstevel@tonic-gate				m = readlink(source, symln, sizeof (symln) - 1);
7667c478bdstevel@tonic-gate
7677c478bdstevel@tonic-gate				if (m < 0) {
7687c478bdstevel@tonic-gate					Perror(source);
7697c478bdstevel@tonic-gate					return (1);
7707c478bdstevel@tonic-gate				}
7717c478bdstevel@tonic-gate				symln[m] = '\0';
7727c478bdstevel@tonic-gate
7737c478bdstevel@tonic-gate				/*
7747c478bdstevel@tonic-gate				 * Copy the sym link to the target.
7757c478bdstevel@tonic-gate				 * Note: If the target exists, write a
7767c478bdstevel@tonic-gate				 * diagnostic message, do nothing more
7777c478bdstevel@tonic-gate				 * with the source file, and return to
7787c478bdstevel@tonic-gate				 * process any remaining files.
7797c478bdstevel@tonic-gate				 */
7807c478bdstevel@tonic-gate				md = umask(~(s1.st_mode & MODEBITS));
7817c478bdstevel@tonic-gate				if (symlink(symln, target) < 0) {
7827c478bdstevel@tonic-gate					Perror(target);
7837c478bdstevel@tonic-gate					return (1);
7847c478bdstevel@tonic-gate				}
7857c478bdstevel@tonic-gate				(void) umask(md);
7867c478bdstevel@tonic-gate				m = lchown(target, UID(s1), GID(s1));
7877c478bdstevel@tonic-gate
7887c478bdstevel@tonic-gate				if (m < 0) {
7897c478bdstevel@tonic-gate					(void) fprintf(stderr, gettext(
7907c478bdstevel@tonic-gate					    "cp: cannot change owner and "
7917c478bdstevel@tonic-gate					    "group of %s:"), target);
7927c478bdstevel@tonic-gate					perror("");
7937c478bdstevel@tonic-gate				}
7947c478bdstevel@tonic-gate			} else {
7957c478bdstevel@tonic-gate				/*
7967c478bdstevel@tonic-gate				 * Copy the file.  If it happens to be a
7977c478bdstevel@tonic-gate				 * symlink, copy the file referenced
7987c478bdstevel@tonic-gate				 * by the symlink.
7997c478bdstevel@tonic-gate				 */
8007c478bdstevel@tonic-gate				fi = open(source, O_RDONLY);
8017c478bdstevel@tonic-gate				if (fi < 0) {
8027c478bdstevel@tonic-gate					(void) fprintf(stderr,
8037c478bdstevel@tonic-gate					    gettext("%s: cannot open %s: "),
8047c478bdstevel@tonic-gate					    cmd, source);
8057c478bdstevel@tonic-gate					perror("");
8067c478bdstevel@tonic-gate					return (1);
8077c478bdstevel@tonic-gate				}
8087c478bdstevel@tonic-gate
8097c478bdstevel@tonic-gate				fo = creat(target, s1.st_mode & MODEBITS);
8107c478bdstevel@tonic-gate				if (fo < 0) {
8117c478bdstevel@tonic-gate					/*
8127c478bdstevel@tonic-gate					 * If -f and creat() failed, unlink
8137c478bdstevel@tonic-gate					 * and try again.
8147c478bdstevel@tonic-gate					 */
8157c478bdstevel@tonic-gate					if (fflg) {
8167c478bdstevel@tonic-gate						(void) unlink(target);
8177c478bdstevel@tonic-gate						fo = creat(target,
8187c478bdstevel@tonic-gate						    s1.st_mode & MODEBITS);
8197c478bdstevel@tonic-gate					}
8207c478bdstevel@tonic-gate				}
8217c478bdstevel@tonic-gate				if (fo < 0) {
8227c478bdstevel@tonic-gate					(void) fprintf(stderr,
8237c478bdstevel@tonic-gate					    gettext("%s: cannot create %s: "),
8247c478bdstevel@tonic-gate					    cmd, target);
8257c478bdstevel@tonic-gate					perror("");
8267c478bdstevel@tonic-gate					(void) close(fi);
8277c478bdstevel@tonic-gate					return (1);
8287c478bdstevel@tonic-gate				} else {
8297c478bdstevel@tonic-gate					/* stat the new file, its used below */
8307c478bdstevel@tonic-gate					(void) stat(target, &s2);
8317c478bdstevel@tonic-gate				}
8327c478bdstevel@tonic-gate
8337c478bdstevel@tonic-gate				/*
8347c478bdstevel@tonic-gate				 * Set target's permissions to the source
8357c478bdstevel@tonic-gate				 * before any copying so that any partially
8367c478bdstevel@tonic-gate				 * copied file will have the source's
8377c478bdstevel@tonic-gate				 * permissions (at most) or umask permissions
8387c478bdstevel@tonic-gate				 * whichever is the most restrictive.
8397c478bdstevel@tonic-gate				 *
8407c478bdstevel@tonic-gate				 * ACL for regular files
8417c478bdstevel@tonic-gate				 */
8427c478bdstevel@tonic-gate
8437c478bdstevel@tonic-gate				if (pflg || mve) {
8447c478bdstevel@tonic-gate					(void) chmod(target, FMODE(s1));
845fa9e406ahrens					if (s1acl != NULL) {
846fa9e406ahrens						if ((acl_set(target,
847fa9e406ahrens						    s1acl)) < 0) {
848cee1ddabasabi							error++;
849cee1ddabasabi							(void) fprintf(stderr,
850cee1ddabasabi							    gettext("%s: "
851cee1ddabasabi							    "Failed to set "
852cee1ddabasabi							    "acl entries "
853cee1ddabasabi							    "on %s\n"), cmd,
854cee1ddabasabi							    target);
85594d2b9amarks							acl_free(s1acl);
85694d2b9amarks							s1acl = NULL;
8577c478bdstevel@tonic-gate							/*
8587c478bdstevel@tonic-gate							 * else: silent and
8597c478bdstevel@tonic-gate							 * continue
8607c478bdstevel@tonic-gate							 */
8617c478bdstevel@tonic-gate						}
8627c478bdstevel@tonic-gate					}
8637c478bdstevel@tonic-gate				}
8647c478bdstevel@tonic-gate
8657c478bdstevel@tonic-gate				if (fstat(fi, &s1) < 0) {
8667c478bdstevel@tonic-gate					(void) fprintf(stderr,
8677c478bdstevel@tonic-gate					    gettext("%s: cannot access %s\n"),
8687c478bdstevel@tonic-gate					    cmd, source);
8697c478bdstevel@tonic-gate					return (1);
8707c478bdstevel@tonic-gate				}
8717c478bdstevel@tonic-gate				if (IDENTICAL(s1, s2)) {
8727c478bdstevel@tonic-gate					(void) fprintf(stderr,
8737c478bdstevel@tonic-gate					    gettext(
8747c478bdstevel@tonic-gate					    "%s: %s and %s are identical\n"),
8757c478bdstevel@tonic-gate					    cmd, source, target);
8767c478bdstevel@tonic-gate					return (1);
8777c478bdstevel@tonic-gate				}
8787c478bdstevel@tonic-gate
879da6c28aamw				if (writefile(fi, fo, source, target, NULL,
880da6c28aamw				    NULL, &s1, &s2) != 0) {
8817c478bdstevel@tonic-gate					return (1);
8827c478bdstevel@tonic-gate				}
8837c478bdstevel@tonic-gate
8847c478bdstevel@tonic-gate				(void) close(fi);
8857c478bdstevel@tonic-gate				if (close(fo) < 0) {
8867c478bdstevel@tonic-gate					Perror2(target, "write");
8877c478bdstevel@tonic-gate					return (1);
8887c478bdstevel@tonic-gate				}
8897c478bdstevel@tonic-gate			}
890da6c28aamw			/* Copy regular extended attributes */
891da6c28aamw			if (pflg || atflg || mve || saflg) {
8927c478bdstevel@tonic-gate				attret = copyattributes(source, target);
8937c478bdstevel@tonic-gate				if (attret != 0 && !attrsilent) {
8947c478bdstevel@tonic-gate					(void) fprintf(stderr, gettext(
8953d63ea0as					    "%s: Failed to preserve"
8963d63ea0as					    " extended attributes of file"
8973d63ea0as					    " %s\n"), cmd, source);
8987c478bdstevel@tonic-gate				}
899da6c28aamw				/* Copy extended system attributes */
900cee1ddabasabi				if (pflg || mve || saflg)
901da6c28aamw					sattret = copy_sysattr(source, target);
9027c478bdstevel@tonic-gate				if (mve && attret != 0) {
9037c478bdstevel@tonic-gate					(void) unlink(target);
9047c478bdstevel@tonic-gate					return (1);
9057c478bdstevel@tonic-gate				}
906da6c28aamw				if (attrsilent) {
9077c478bdstevel@tonic-gate					attret = 0;
908da6c28aamw				}
9097c478bdstevel@tonic-gate			}
9107c478bdstevel@tonic-gate
9117c478bdstevel@tonic-gate			/*
9127c478bdstevel@tonic-gate			 * XPG4: the write system call will clear setgid
9137c478bdstevel@tonic-gate			 * and setuid bits, so set them again.
9147c478bdstevel@tonic-gate			 */
9157c478bdstevel@tonic-gate			if (pflg || mve) {
9167c478bdstevel@tonic-gate				if ((ret = chg_mode(target, UID(s1), GID(s1),
9177c478bdstevel@tonic-gate				    FMODE(s1))) > 0)
9187c478bdstevel@tonic-gate					return (1);
919d2443e7marks				/*
920d2443e7marks				 * Reapply ACL, since chmod may have
921d2443e7marks				 * altered ACL
922d2443e7marks				 */
923d2443e7marks				if (s1acl != NULL) {
924d2443e7marks					if ((acl_set(target, s1acl)) < 0) {
925cee1ddabasabi						error++;
926cee1ddabasabi						(void) fprintf(stderr,
927cee1ddabasabi						    gettext("%s: Failed to "
928cee1ddabasabi						    "set acl entries "
929cee1ddabasabi						    "on %s\n"), cmd, target);
930d2443e7marks						/*
931d2443e7marks						 * else: silent and
932d2443e7marks						 * continue
933d2443e7marks						 */
934d2443e7marks					}
935d2443e7marks				}
9367c478bdstevel@tonic-gate				if ((ret = chg_time(target, s1)) > 0)
9377c478bdstevel@tonic-gate					return (1);
9387c478bdstevel@tonic-gate			}
9397c478bdstevel@tonic-gate			if (cpy) {
940cee1ddabasabi				if (error != 0 || attret != 0 || sattret != 0)
9417c478bdstevel@tonic-gate					return (1);
9427c478bdstevel@tonic-gate				return (0);
9437c478bdstevel@tonic-gate			}
9447c478bdstevel@tonic-gate			goto cleanup;
9457c478bdstevel@tonic-gate		}
9467c478bdstevel@tonic-gate		(void) fprintf(stderr,
9477c478bdstevel@tonic-gate		    gettext("%s: %s: unknown file type 0x%x\n"), cmd,
9483d63ea0as		    source, (s1.st_mode & S_IFMT));
9497c478bdstevel@tonic-gate		return (1);
9507c478bdstevel@tonic-gate
9517c478bdstevel@tonic-gatecleanup:
9527c478bdstevel@tonic-gate		if (unlink(source) < 0) {
9537c478bdstevel@tonic-gate			(void) unlink(target);
9547c478bdstevel@tonic-gate			(void) fprintf(stderr,
9557c478bdstevel@tonic-gate			    gettext("%s: cannot unlink %s: "),
9567c478bdstevel@tonic-gate			    cmd, source);
9577c478bdstevel@tonic-gate			perror("");
9587c478bdstevel@tonic-gate			return (1);
9597c478bdstevel@tonic-gate		}
960cee1ddabasabi		if (error != 0 || attret != 0 || sattret != 0)
961cee1ddabasabi			return (1);
9627c478bdstevel@tonic-gate		return (ret);
9637c478bdstevel@tonic-gate	}
9647c478bdstevel@tonic-gate	/*NOTREACHED*/
965a77d64acf	return (ret);
9667c478bdstevel@tonic-gate}
9677c478bdstevel@tonic-gate
9687c478bdstevel@tonic-gate/*
9697c478bdstevel@tonic-gate * create_tnode()
9707c478bdstevel@tonic-gate *
9717c478bdstevel@tonic-gate * Create a node for use with the search tree which contains the
9727c478bdstevel@tonic-gate * inode information (device id and inode number).
9737c478bdstevel@tonic-gate *
9747c478bdstevel@tonic-gate * Input
9757c478bdstevel@tonic-gate *	dev	- device id
9767c478bdstevel@tonic-gate *	ino	- inode number
9777c478bdstevel@tonic-gate *
9787c478bdstevel@tonic-gate * Output
9797c478bdstevel@tonic-gate *	tnode	- NULL on error, otherwise returns a tnode structure
9807c478bdstevel@tonic-gate *		  which contains the input device id and inode number.
9817c478bdstevel@tonic-gate */
9827c478bdstevel@tonic-gatestatic tree_node_t *
9837c478bdstevel@tonic-gatecreate_tnode(dev_t dev, ino_t ino)
9847c478bdstevel@tonic-gate{
9857c478bdstevel@tonic-gate	tree_node_t	*tnode;
9867c478bdstevel@tonic-gate
9877c478bdstevel@tonic-gate	if ((tnode = (tree_node_t *)malloc(sizeof (tree_node_t))) != NULL) {
9887c478bdstevel@tonic-gate		tnode->node_dev = dev;
9897c478bdstevel@tonic-gate		tnode->node_ino = ino;
9907c478bdstevel@tonic-gate	}
9917c478bdstevel@tonic-gate
9927c478bdstevel@tonic-gate	return (tnode);
9937c478bdstevel@tonic-gate}
9947c478bdstevel@tonic-gate
9957c478bdstevel@tonic-gatestatic int
9967c478bdstevel@tonic-gatechkfiles(char *source, char **to)
9977c478bdstevel@tonic-gate{
9987c478bdstevel@tonic-gate	char	*buf = (char *)NULL;
9997c478bdstevel@tonic-gate	int	(*statf)() = (cpy &&
10003d63ea0as	    !(Pflg || (Hflg && !cmdarg))) ? stat : lstat;
10017c478bdstevel@tonic-gate	char    *target = *to;
1002fa9e406ahrens	int	error;
10037c478bdstevel@tonic-gate
10047c478bdstevel@tonic-gate	/*
10057c478bdstevel@tonic-gate	 * Make sure source file exists.
10067c478bdstevel@tonic-gate	 */
10077c478bdstevel@tonic-gate	if ((*statf)(source, &s1) < 0) {
10087c478bdstevel@tonic-gate		/*
10097c478bdstevel@tonic-gate		 * Keep the old error message except when someone tries to
10107c478bdstevel@tonic-gate		 * mv/cp/ln a symbolic link that has a trailing slash and
10117c478bdstevel@tonic-gate		 * points to a file.
10127c478bdstevel@tonic-gate		 */
10137c478bdstevel@tonic-gate		if (errno == ENOTDIR)
10147c478bdstevel@tonic-gate			(void) fprintf(stderr, "%s: %s: %s\n", cmd, source,
10157c478bdstevel@tonic-gate			    strerror(errno));
10167c478bdstevel@tonic-gate		else
10177c478bdstevel@tonic-gate			(void) fprintf(stderr,
10187c478bdstevel@tonic-gate			    gettext("%s: cannot access %s\n"), cmd, source);
10197c478bdstevel@tonic-gate		return (1);
10207c478bdstevel@tonic-gate	}
10217c478bdstevel@tonic-gate
10227c478bdstevel@tonic-gate	/*
1023ee9c203Renaud Manus	 * Get ACL info: don't bother with ln or cp/mv'ing symlinks
10247c478bdstevel@tonic-gate	 */
1025ee9c203Renaud Manus	if (!lnk && !ISLNK(s1)) {
1026fa9e406ahrens		if (s1acl != NULL) {
1027fa9e406ahrens			acl_free(s1acl);
1028fa9e406ahrens			s1acl = NULL;
10297c478bdstevel@tonic-gate		}
1030fa9e406ahrens		if ((error = acl_get(source, ACL_NO_TRIVIAL, &s1acl)) != 0) {
10317c478bdstevel@tonic-gate			(void) fprintf(stderr,
1032fa9e406ahrens			    "%s: failed to get acl entries: %s\n", source,
1033fa9e406ahrens			    acl_strerror(error));
10347c478bdstevel@tonic-gate			return (1);
10357c478bdstevel@tonic-gate		}
10367c478bdstevel@tonic-gate		/* else: just permission bits */
10377c478bdstevel@tonic-gate	}
10387c478bdstevel@tonic-gate
10397c478bdstevel@tonic-gate	/*
10407c478bdstevel@tonic-gate	 * If stat fails, then the target doesn't exist,
10417c478bdstevel@tonic-gate	 * we will create a new target with default file type of regular.
10427c478bdstevel@tonic-gate	 */
10437c478bdstevel@tonic-gate
10447c478bdstevel@tonic-gate	FTYPE(s2) = S_IFREG;
10457c478bdstevel@tonic-gate	targetexists = 0;
10467c478bdstevel@tonic-gate	if ((*statf)(target, &s2) >= 0) {
10477c478bdstevel@tonic-gate		if (ISLNK(s2))
10487c478bdstevel@tonic-gate			(void) stat(target, &s2);
10497c478bdstevel@tonic-gate		/*
10507c478bdstevel@tonic-gate		 * If target is a directory,
10517c478bdstevel@tonic-gate		 * make complete name of new file
10527c478bdstevel@tonic-gate		 * within that directory.
10537c478bdstevel@tonic-gate		 */
10547c478bdstevel@tonic-gate		if (ISDIR(s2)) {
10557c478bdstevel@tonic-gate			size_t len;
10567c478bdstevel@tonic-gate
10577c478bdstevel@tonic-gate			len = strlen(target) + strlen(dname(source)) + 4;
10587c478bdstevel@tonic-gate			if ((buf = (char *)malloc(len)) == NULL) {
10597c478bdstevel@tonic-gate				(void) fprintf(stderr,
10607c478bdstevel@tonic-gate				    gettext("%s: Insufficient memory to "
10613d63ea0as				    "%s %s\n "), cmd, cmd, source);
10627c478bdstevel@tonic-gate				exit(3);
10637c478bdstevel@tonic-gate			}
10647c478bdstevel@tonic-gate			(void) snprintf(buf, len, "%s/%s",
10657c478bdstevel@tonic-gate			    target, dname(source));
10667c478bdstevel@tonic-gate			*to = target = buf;
10677c478bdstevel@tonic-gate		}
10687c478bdstevel@tonic-gate
10697c478bdstevel@tonic-gate		if ((*statf)(target, &s2) >= 0) {
10707c478bdstevel@tonic-gate			int overwrite	= FALSE;
10717c478bdstevel@tonic-gate			int override	= FALSE;
10727c478bdstevel@tonic-gate
10737c478bdstevel@tonic-gate			targetexists++;
10747c478bdstevel@tonic-gate			if (cpy || mve) {
10757c478bdstevel@tonic-gate				/*
10767c478bdstevel@tonic-gate				 * For cp and mv, it is an error if the
10777c478bdstevel@tonic-gate				 * source and target are the same file.
10787c478bdstevel@tonic-gate				 * Check for the same inode and file
10797c478bdstevel@tonic-gate				 * system, but don't check for the same
10807c478bdstevel@tonic-gate				 * absolute pathname because it is an
10817c478bdstevel@tonic-gate				 * error when the source and target are
10827c478bdstevel@tonic-gate				 * hard links to the same file.
10837c478bdstevel@tonic-gate				 */
10847c478bdstevel@tonic-gate				if (IDENTICAL(s1, s2)) {
10857c478bdstevel@tonic-gate					(void) fprintf(stderr,
10867c478bdstevel@tonic-gate					    gettext(
10877c478bdstevel@tonic-gate					    "%s: %s and %s are identical\n"),
10887c478bdstevel@tonic-gate					    cmd, source, target);
10897c478bdstevel@tonic-gate					if (buf != NULL)
10907c478bdstevel@tonic-gate						free(buf);
10917c478bdstevel@tonic-gate					return (1);
10927c478bdstevel@tonic-gate				}
10937c478bdstevel@tonic-gate			}
10947c478bdstevel@tonic-gate			if (lnk) {
10957c478bdstevel@tonic-gate				/*
10967c478bdstevel@tonic-gate				 * For ln, it is an error if the source and
10977c478bdstevel@tonic-gate				 * target are identical files (same inode,
10987c478bdstevel@tonic-gate				 * same file system, and filenames resolve
10997c478bdstevel@tonic-gate				 * to same absolute pathname).
11007c478bdstevel@tonic-gate				 */
11017c478bdstevel@tonic-gate				if (!chk_different(source, target)) {
11027c478bdstevel@tonic-gate					if (buf != NULL)
11037c478bdstevel@tonic-gate						free(buf);
11047c478bdstevel@tonic-gate					return (1);
11057c478bdstevel@tonic-gate				}
11067c478bdstevel@tonic-gate			}
11077c478bdstevel@tonic-gate			if (lnk && !silent) {
11087c478bdstevel@tonic-gate				(void) fprintf(stderr,
11097c478bdstevel@tonic-gate				    gettext("%s: %s: File exists\n"),
11107c478bdstevel@tonic-gate				    cmd, target);
11117c478bdstevel@tonic-gate				if (buf != NULL)
11127c478bdstevel@tonic-gate					free(buf);
11137c478bdstevel@tonic-gate				return (1);
11147c478bdstevel@tonic-gate			}
11157c478bdstevel@tonic-gate
11167c478bdstevel@tonic-gate			/*
11177c478bdstevel@tonic-gate			 * overwrite:
11187c478bdstevel@tonic-gate			 * If the user does not have access to
11197c478bdstevel@tonic-gate			 * the target, ask ----if it is not
11207c478bdstevel@tonic-gate			 * silent and user invoked command
11217c478bdstevel@tonic-gate			 * interactively.
11227c478bdstevel@tonic-gate			 *
11237c478bdstevel@tonic-gate			 * override:
11247c478bdstevel@tonic-gate			 * If not silent, and stdin is a terminal, and
11257c478bdstevel@tonic-gate			 * there's no write access, and the file isn't a
11267c478bdstevel@tonic-gate			 * symbolic link, ask for permission.
11277c478bdstevel@tonic-gate			 *
11287c478bdstevel@tonic-gate			 * XPG4: both overwrite and override:
11297c478bdstevel@tonic-gate			 * ask only one question.
11307c478bdstevel@tonic-gate			 *
11317c478bdstevel@tonic-gate			 * TRANSLATION_NOTE - The following messages will
11327c478bdstevel@tonic-gate			 * contain the first character of the strings for
11337c478bdstevel@tonic-gate			 * "yes" and "no" defined in the file
11347c478bdstevel@tonic-gate			 * "nl_langinfo.po".  After substitution, the
11357c478bdstevel@tonic-gate			 * message will appear as follows:
11367c478bdstevel@tonic-gate			 *	<cmd>: overwrite <filename> (y/n)?
11377c478bdstevel@tonic-gate			 * where <cmd> is the name of the command
11387c478bdstevel@tonic-gate			 * (cp, mv) and <filename> is the destination file
11397c478bdstevel@tonic-gate			 */
11407c478bdstevel@tonic-gate
11417c478bdstevel@tonic-gate
11427c478bdstevel@tonic-gate			overwrite = iflg && !silent && use_stdin();
11437c478bdstevel@tonic-gate			override = !cpy && (access(target, 2) < 0) &&
11447c478bdstevel@tonic-gate			    !silent && use_stdin() && !ISLNK(s2);
11457c478bdstevel@tonic-gate
11460f6e7baas			if (overwrite && override) {
11477c478bdstevel@tonic-gate				(void) fprintf(stderr,
11487c478bdstevel@tonic-gate				    gettext("%s: overwrite %s and override "
11497c478bdstevel@tonic-gate				    "protection %o (%s/%s)? "), cmd, target,
11503d63ea0as				    FMODE(s2) & MODEBITS, yesstr, nostr);
11513d63ea0as				if (yes() == 0) {
11520f6e7baas					if (buf != NULL)
11530f6e7baas						free(buf);
11540f6e7baas					return (2);
11550f6e7baas				}
11560f6e7baas			} else if (overwrite && ISREG(s2)) {
11577c478bdstevel@tonic-gate				(void) fprintf(stderr,
11587c478bdstevel@tonic-gate				    gettext("%s: overwrite %s (%s/%s)? "),
11593d63ea0as				    cmd, target, yesstr, nostr);
11603d63ea0as				if (yes() == 0) {
11610f6e7baas					if (buf != NULL)
11620f6e7baas						free(buf);
11630f6e7baas					return (2);
11640f6e7baas				}
11650f6e7baas			} else if (override) {
11667c478bdstevel@tonic-gate				(void) fprintf(stderr,
11677c478bdstevel@tonic-gate				    gettext("%s: %s: override protection "
11687c478bdstevel@tonic-gate				    /*CSTYLED*/
11697c478bdstevel@tonic-gate				    "%o (%s/%s)? "),
11707c478bdstevel@tonic-gate				    /*CSTYLED*/
11717c478bdstevel@tonic-gate				    cmd, target, FMODE(s2) & MODEBITS,
11723d63ea0as				    yesstr, nostr);
11733d63ea0as				if (yes() == 0) {
11740f6e7baas					if (buf != NULL)
11750f6e7baas						free(buf);
11760f6e7baas					return (2);
11777c478bdstevel@tonic-gate				}
11787c478bdstevel@tonic-gate			}
11790f6e7baas
11807c478bdstevel@tonic-gate			if (lnk && unlink(target) < 0) {
11817c478bdstevel@tonic-gate				(void) fprintf(stderr,
11827c478bdstevel@tonic-gate				    gettext("%s: cannot unlink %s: "),
11837c478bdstevel@tonic-gate				    cmd, target);
11847c478bdstevel@tonic-gate				perror("");
11857c478bdstevel@tonic-gate				return (1);
11867c478bdstevel@tonic-gate			}
11877c478bdstevel@tonic-gate		}
11887c478bdstevel@tonic-gate	}
11897c478bdstevel@tonic-gate	return (0);
11907c478bdstevel@tonic-gate}
11917c478bdstevel@tonic-gate
11927c478bdstevel@tonic-gate/*
11937c478bdstevel@tonic-gate * check whether source and target are different
11947c478bdstevel@tonic-gate * return 1 when they are different
11957c478bdstevel@tonic-gate * return 0 when they are identical, or when unable to resolve a pathname
11967c478bdstevel@tonic-gate */
11977c478bdstevel@tonic-gatestatic int
11987c478bdstevel@tonic-gatechk_different(char *source, char *target)
11997c478bdstevel@tonic-gate{
12007c478bdstevel@tonic-gate	char	rtarget[PATH_MAX], rsource[PATH_MAX];
12017c478bdstevel@tonic-gate
12027c478bdstevel@tonic-gate	if (IDENTICAL(s1, s2)) {
12037c478bdstevel@tonic-gate		/*
12047c478bdstevel@tonic-gate		 * IDENTICAL will be true for hard links, therefore
12057c478bdstevel@tonic-gate		 * check whether the filenames are different
12067c478bdstevel@tonic-gate		 */
12077c478bdstevel@tonic-gate		if ((getrealpath(source, rsource) == 0) ||
12087c478bdstevel@tonic-gate		    (getrealpath(target, rtarget) == 0)) {
12097c478bdstevel@tonic-gate			return (0);
12107c478bdstevel@tonic-gate		}
12117c478bdstevel@tonic-gate		if (strncmp(rsource, rtarget, PATH_MAX) == 0) {
12127c478bdstevel@tonic-gate			(void) fprintf(stderr, gettext(
12137c478bdstevel@tonic-gate			    "%s: %s and %s are identical\n"),
12147c478bdstevel@tonic-gate			    cmd, source, target);
12157c478bdstevel@tonic-gate			return (0);
12167c478bdstevel@tonic-gate		}
12177c478bdstevel@tonic-gate	}
12187c478bdstevel@tonic-gate	return (1);
12197c478bdstevel@tonic-gate}
12207c478bdstevel@tonic-gate
12217c478bdstevel@tonic-gate/*
12227c478bdstevel@tonic-gate * get real path (resolved absolute pathname)
12237c478bdstevel@tonic-gate * return 1 on success, 0 on failure
12247c478bdstevel@tonic-gate */
12257c478bdstevel@tonic-gatestatic int
12267c478bdstevel@tonic-gategetrealpath(char *path, char *rpath)
12277c478bdstevel@tonic-gate{
12287c478bdstevel@tonic-gate	if (realpath(path, rpath) == NULL) {
12297c478bdstevel@tonic-gate		int	errno_save = errno;
12307c478bdstevel@tonic-gate		(void) fprintf(stderr, gettext(
1231e1636a0danny webster		    "%s: cannot resolve path %s: "), cmd, path);
12327c478bdstevel@tonic-gate		errno = errno_save;
12337c478bdstevel@tonic-gate		perror("");
12347c478bdstevel@tonic-gate		return (0);
12357c478bdstevel@tonic-gate	}
12367c478bdstevel@tonic-gate	return (1);
12377c478bdstevel@tonic-gate}
12387c478bdstevel@tonic-gate
12397c478bdstevel@tonic-gatestatic int
12407c478bdstevel@tonic-gatercopy(char *from, char *to)
12417c478bdstevel@tonic-gate{
12427c478bdstevel@tonic-gate	DIR *fold = opendir(from);
12437c478bdstevel@tonic-gate	struct dirent *dp;
12447c478bdstevel@tonic-gate	struct stat statb, s1save;
12457c478bdstevel@tonic-gate	int errs = 0;
12467c478bdstevel@tonic-gate	char fromname[PATH_MAX];
12477c478bdstevel@tonic-gate
12487c478bdstevel@tonic-gate	if (fold == 0 || ((pflg || mve) && fstat(fold->dd_fd, &statb) < 0)) {
12497c478bdstevel@tonic-gate		Perror(from);
12507c478bdstevel@tonic-gate		return (1);
12517c478bdstevel@tonic-gate	}
12527c478bdstevel@tonic-gate	if (pflg || mve) {
12537c478bdstevel@tonic-gate		/*
12547c478bdstevel@tonic-gate		 * Save s1 (stat information for source dir) so that
12557c478bdstevel@tonic-gate		 * mod and access times can be reserved during "cp -p"
12567c478bdstevel@tonic-gate		 * or mv, since s1 gets overwritten.
12577c478bdstevel@tonic-gate		 */
12587c478bdstevel@tonic-gate		s1save = s1;
12597c478bdstevel@tonic-gate	}
12607c478bdstevel@tonic-gate	for (;;) {
12617c478bdstevel@tonic-gate		dp = readdir(fold);
12627c478bdstevel@tonic-gate		if (dp == 0) {
12637c478bdstevel@tonic-gate			(void) closedir(fold);
12647c478bdstevel@tonic-gate			if (pflg || mve)
12657c478bdstevel@tonic-gate				return (chg_time(to, s1save) + errs);
12667c478bdstevel@tonic-gate			return (errs);
12677c478bdstevel@tonic-gate		}
12687c478bdstevel@tonic-gate		if (dp->d_ino == 0)
12697c478bdstevel@tonic-gate			continue;
12707c478bdstevel@tonic-gate		if ((strcmp(dp->d_name, ".") == 0) ||
12717c478bdstevel@tonic-gate		    (strcmp(dp->d_name, "..") == 0))
12727c478bdstevel@tonic-gate			continue;
12737c478bdstevel@tonic-gate		if (strlen(from)+1+strlen(dp->d_name) >=
12747c478bdstevel@tonic-gate		    sizeof (fromname) - 1) {
12757c478bdstevel@tonic-gate			(void) fprintf(stderr,
12767c478bdstevel@tonic-gate			    gettext("%s : %s/%s: Name too long\n"),
12777c478bdstevel@tonic-gate			    cmd, from, dp->d_name);
12787c478bdstevel@tonic-gate			errs++;
12797c478bdstevel@tonic-gate			continue;
12807c478bdstevel@tonic-gate		}
12817c478bdstevel@tonic-gate		(void) snprintf(fromname, sizeof (fromname),
12827c478bdstevel@tonic-gate		    "%s/%s", from, dp->d_name);
12837c478bdstevel@tonic-gate		errs += cpymve(fromname, to);
12847c478bdstevel@tonic-gate	}
12857c478bdstevel@tonic-gate}
12867c478bdstevel@tonic-gate
12877c478bdstevel@tonic-gatestatic char *
12887c478bdstevel@tonic-gatedname(char *name)
12897c478bdstevel@tonic-gate{
12907c478bdstevel@tonic-gate	register char *p;
12917c478bdstevel@tonic-gate
12927c478bdstevel@tonic-gate	/*
12937c478bdstevel@tonic-gate	 * Return just the file name given the complete path.
12947c478bdstevel@tonic-gate	 * Like basename(1).
12957c478bdstevel@tonic-gate	 */
12967c478bdstevel@tonic-gate
12977c478bdstevel@tonic-gate	p = name;
12987c478bdstevel@tonic-gate
12997c478bdstevel@tonic-gate	/*
13007c478bdstevel@tonic-gate	 * While there are characters left,
13017c478bdstevel@tonic-gate	 * set name to start after last
13027c478bdstevel@tonic-gate	 * delimiter.
13037c478bdstevel@tonic-gate	 */
13047c478bdstevel@tonic-gate
13057c478bdstevel@tonic-gate	while (*p)
13067c478bdstevel@tonic-gate		if (*p++ == DELIM && *p)
13077c478bdstevel@tonic-gate			name = p;
13087c478bdstevel@tonic-gate	return (name);
13097c478bdstevel@tonic-gate}
13107c478bdstevel@tonic-gate
13117c478bdstevel@tonic-gatestatic void
13127c478bdstevel@tonic-gateusage(void)
13137c478bdstevel@tonic-gate{
13147c478bdstevel@tonic-gate	/*
13157c478bdstevel@tonic-gate	 * Display usage message.
13167c478bdstevel@tonic-gate	 */
13177c478bdstevel@tonic-gate
13187c478bdstevel@tonic-gate	if (mve) {
13197c478bdstevel@tonic-gate		(void) fprintf(stderr, gettext(
13207c478bdstevel@tonic-gate		    "Usage: mv [-f] [-i] f1 f2\n"
13217c478bdstevel@tonic-gate		    "       mv [-f] [-i] f1 ... fn d1\n"
13227c478bdstevel@tonic-gate		    "       mv [-f] [-i] d1 d2\n"));
13237c478bdstevel@tonic-gate	} else if (lnk) {
13247c478bdstevel@tonic-gate#ifdef XPG4
13253d63ea0as		(void) fprintf(stderr, gettext(
13267c478bdstevel@tonic-gate		    "Usage: ln [-f] [-s] f1 [f2]\n"
13277c478bdstevel@tonic-gate		    "       ln [-f] [-s] f1 ... fn d1\n"
13287c478bdstevel@tonic-gate		    "       ln [-f] -s d1 d2\n"));
13297c478bdstevel@tonic-gate#else
13303d63ea0as		(void) fprintf(stderr, gettext(
13317c478bdstevel@tonic-gate		    "Usage: ln [-f] [-n] [-s] f1 [f2]\n"
13327c478bdstevel@tonic-gate		    "       ln [-f] [-n] [-s] f1 ... fn d1\n"
13337c478bdstevel@tonic-gate		    "       ln [-f] [-n] -s d1 d2\n"));
13347c478bdstevel@tonic-gate#endif
13357c478bdstevel@tonic-gate	} else if (cpy) {
13367c478bdstevel@tonic-gate		(void) fprintf(stderr, gettext(
13379e64776Alexander Eremin		    "Usage: cp [-a] [-f] [-i] [-p] [-@] [-/] f1 f2\n"
13389e64776Alexander Eremin		    "       cp [-a] [-f] [-i] [-p] [-@] [-/] f1 ... fn d1\n"
13399e64776Alexander Eremin		    "       cp [-r|-R [-H|-L|-P]] [-a] [-f] [-i] [-p] [-@] "
13409e64776Alexander Eremin		    "[-/] d1 ... dn-1 dn\n"));
13417c478bdstevel@tonic-gate	}
13427c478bdstevel@tonic-gate	exit(2);
13437c478bdstevel@tonic-gate}
13447c478bdstevel@tonic-gate
13457c478bdstevel@tonic-gate/*
13467c478bdstevel@tonic-gate * chg_time()
13477c478bdstevel@tonic-gate *
13487c478bdstevel@tonic-gate * Try to preserve modification and access time.
13497c478bdstevel@tonic-gate * If 1) pflg is not set, or 2) pflg is set and this is the Solaris version,
135078cca7eRoger A. Faulkner * don't report a utimensat() failure.
135178cca7eRoger A. Faulkner * If this is the XPG4 version and utimensat fails, if 1) pflg is set (cp -p)
13527c478bdstevel@tonic-gate * or 2) we are doing a mv, print a diagnostic message; arrange for a non-zero
13537c478bdstevel@tonic-gate * exit status only if pflg is set.
135478cca7eRoger A. Faulkner * utimensat(2) is being used to achieve granularity in nanoseconds
135578cca7eRoger A. Faulkner * (if supported by the underlying file system) while setting file times.
13567c478bdstevel@tonic-gate */
13577c478bdstevel@tonic-gatestatic int
13587c478bdstevel@tonic-gatechg_time(char *to, struct stat ss)
13597c478bdstevel@tonic-gate{
136078cca7eRoger A. Faulkner	struct timespec times[2];
1361dfe0259Toomas Soome#ifdef XPG4
13627c478bdstevel@tonic-gate	int rc;
1363dfe0259Toomas Soome#endif
13647c478bdstevel@tonic-gate
136578cca7eRoger A. Faulkner	times[0] = ss.st_atim;
136678cca7eRoger A. Faulkner	times[1] = ss.st_mtim;
13677c478bdstevel@tonic-gate
1368dfe0259Toomas Soome#ifdef XPG4
13696cdb722Alexander Eremin	rc = utimensat(AT_FDCWD, to, times,
13706cdb722Alexander Eremin	    ISLNK(s1) ? AT_SYMLINK_NOFOLLOW : 0);
13717c478bdstevel@tonic-gate	if ((pflg || mve) && rc != 0) {
13727c478bdstevel@tonic-gate		(void) fprintf(stderr,
13737c478bdstevel@tonic-gate		    gettext("%s: cannot set times for %s: "), cmd, to);
13747c478bdstevel@tonic-gate		perror("");
13757c478bdstevel@tonic-gate		if (pflg)
13767c478bdstevel@tonic-gate			return (1);
13777c478bdstevel@tonic-gate	}
1378dfe0259Toomas Soome#else
1379dfe0259Toomas Soome	(void) utimensat(AT_FDCWD, to, times,
1380dfe0259Toomas Soome	    ISLNK(s1) ? AT_SYMLINK_NOFOLLOW : 0);
13817c478bdstevel@tonic-gate#endif
13827c478bdstevel@tonic-gate
13837c478bdstevel@tonic-gate	return (0);
13847c478bdstevel@tonic-gate
13857c478bdstevel@tonic-gate}
13867c478bdstevel@tonic-gate
13877c478bdstevel@tonic-gate/*
13887c478bdstevel@tonic-gate * chg_mode()
13897c478bdstevel@tonic-gate *
13907c478bdstevel@tonic-gate * This function is called upon "cp -p" or mv across filesystems.
13917c478bdstevel@tonic-gate *
13927c478bdstevel@tonic-gate * Try to preserve the owner and group id.  If chown() fails,
13937c478bdstevel@tonic-gate * only print a diagnostic message if doing a mv in the XPG4 version;
13947c478bdstevel@tonic-gate * try to clear S_ISUID and S_ISGID bits in the target.  If unable to clear
13957c478bdstevel@tonic-gate * S_ISUID and S_ISGID bits, print a diagnostic message and arrange for a
13967c478bdstevel@tonic-gate * non-zero exit status because this is a security violation.
13977c478bdstevel@tonic-gate * Try to preserve permissions.
13987c478bdstevel@tonic-gate * If this is the XPG4 version and chmod() fails, print a diagnostic message
13997c478bdstevel@tonic-gate * and arrange for a non-zero exit status.
14007c478bdstevel@tonic-gate * If this is the Solaris version and chmod() fails, do not print a
14017c478bdstevel@tonic-gate * diagnostic message or exit with a non-zero value.
14027c478bdstevel@tonic-gate */
14037c478bdstevel@tonic-gatestatic int
14047c478bdstevel@tonic-gatechg_mode(char *target, uid_t uid, gid_t gid, mode_t mode)
14057c478bdstevel@tonic-gate{
14067c478bdstevel@tonic-gate	int clearflg = 0; /* controls message printed upon chown() error */
14076cdb722Alexander Eremin	struct stat st;
14086cdb722Alexander Eremin
14096cdb722Alexander Eremin	/* Don't change mode if target is symlink */
14106cdb722Alexander Eremin	if (lstat(target, &st) == 0 && ISLNK(st))
14116cdb722Alexander Eremin		return (0);
14127c478bdstevel@tonic-gate
14137c478bdstevel@tonic-gate	if (chown(target, uid, gid) != 0) {
14147c478bdstevel@tonic-gate#ifdef XPG4
14157c478bdstevel@tonic-gate		if (mve) {
14167c478bdstevel@tonic-gate			(void) fprintf(stderr, gettext("%s: cannot change"
14177c478bdstevel@tonic-gate			    " owner and group of %s: "), cmd, target);
14187c478bdstevel@tonic-gate			perror("");
14197c478bdstevel@tonic-gate		}
14207c478bdstevel@tonic-gate#endif
14217c478bdstevel@tonic-gate		if (mode & (S_ISUID | S_ISGID)) {
14227c478bdstevel@tonic-gate			/* try to clear S_ISUID and S_ISGID */
14237c478bdstevel@tonic-gate			mode &= ~S_ISUID & ~S_ISGID;
14247c478bdstevel@tonic-gate			++clearflg;
14257c478bdstevel@tonic-gate		}
14267c478bdstevel@tonic-gate	}
14277c478bdstevel@tonic-gate	if (chmod(target, mode) != 0) {
14287c478bdstevel@tonic-gate		if (clearflg) {
14297c478bdstevel@tonic-gate			(void) fprintf(stderr, gettext(
14307c478bdstevel@tonic-gate			    "%s: cannot clear S_ISUID and S_ISGID bits in"
14317c478bdstevel@tonic-gate			    " %s: "), cmd, target);
14327c478bdstevel@tonic-gate			perror("");
14337c478bdstevel@tonic-gate			/* cp -p should get non-zero exit; mv should not */
14347c478bdstevel@tonic-gate			if (pflg)
14357c478bdstevel@tonic-gate				return (1);
14367c478bdstevel@tonic-gate		}
14377c478bdstevel@tonic-gate#ifdef XPG4
14387c478bdstevel@tonic-gate		else {
14397c478bdstevel@tonic-gate			(void) fprintf(stderr, gettext(
14407c478bdstevel@tonic-gate			"%s: cannot set permissions for %s: "), cmd, target);
14417c478bdstevel@tonic-gate			perror("");
14427c478bdstevel@tonic-gate			/* cp -p should get non-zero exit; mv should not */
14437c478bdstevel@tonic-gate			if (pflg)
14447c478bdstevel@tonic-gate				return (1);
14457c478bdstevel@tonic-gate		}
14467c478bdstevel@tonic-gate#endif
14477c478bdstevel@tonic-gate	}
14487c478bdstevel@tonic-gate	return (0);
14497c478bdstevel@tonic-gate
14507c478bdstevel@tonic-gate}
14517c478bdstevel@tonic-gate
14527c478bdstevel@tonic-gatestatic void
14537c478bdstevel@tonic-gatePerror(char *s)
14547c478bdstevel@tonic-gate{
14557c478bdstevel@tonic-gate	char buf[PATH_MAX + 10];
14567c478bdstevel@tonic-gate
14577c478bdstevel@tonic-gate	(void) snprintf(buf, sizeof (buf), "%s: %s", cmd, s);
14587c478bdstevel@tonic-gate	perror(buf);
14597c478bdstevel@tonic-gate}
14607c478bdstevel@tonic-gate
14617c478bdstevel@tonic-gatestatic void
14627c478bdstevel@tonic-gatePerror2(char *s1, char *s2)
14637c478bdstevel@tonic-gate{
14647c478bdstevel@tonic-gate	char buf[PATH_MAX + 20];
14657c478bdstevel@tonic-gate
14667c478bdstevel@tonic-gate	(void) snprintf(buf, sizeof (buf), "%s: %s: %s",
14677c478bdstevel@tonic-gate	    cmd, gettext(s1), gettext(s2));
14687c478bdstevel@tonic-gate	perror(buf);
14697c478bdstevel@tonic-gate}
14707c478bdstevel@tonic-gate
14717c478bdstevel@tonic-gate/*
14727c478bdstevel@tonic-gate * used for cp -R and for mv across file systems
14737c478bdstevel@tonic-gate */
14747c478bdstevel@tonic-gatestatic int
14757c478bdstevel@tonic-gatecopydir(char *source, char *target)
14767c478bdstevel@tonic-gate{
14777c478bdstevel@tonic-gate	int ret, attret = 0;
1478cee1ddabasabi	int sattret = 0;
14797c478bdstevel@tonic-gate	int pret = 0;		/* need separate flag if -p is specified */
14807c478bdstevel@tonic-gate	mode_t	fixmode = (mode_t)0;	/* cleanup mode after copy */
14817c478bdstevel@tonic-gate	struct stat s1save;
1482fa9e406ahrens	acl_t  *s1acl_save;
1483cee1ddabasabi	int error = 0;
1484fa9e406ahrens
1485fa9e406ahrens	s1acl_save = NULL;
14867c478bdstevel@tonic-gate
14877c478bdstevel@tonic-gate	if (cpy && !rflg) {
14887c478bdstevel@tonic-gate		(void) fprintf(stderr,
14897c478bdstevel@tonic-gate		    gettext("%s: %s: is a directory\n"), cmd, source);
14907c478bdstevel@tonic-gate		return (1);
14917c478bdstevel@tonic-gate	}
14927c478bdstevel@tonic-gate
14937c478bdstevel@tonic-gate	if (stat(target, &s2) < 0) {
14947c478bdstevel@tonic-gate		if (mkdir(target, (s1.st_mode & MODEBITS)) < 0) {
14957c478bdstevel@tonic-gate			(void) fprintf(stderr, "%s: ", cmd);
14967c478bdstevel@tonic-gate			perror(target);
14977c478bdstevel@tonic-gate			return (1);
14987c478bdstevel@tonic-gate		}
14997c478bdstevel@tonic-gate		if (stat(target, &s2) == 0) {
15007c478bdstevel@tonic-gate			fixmode = s2.st_mode;
15017c478bdstevel@tonic-gate		} else {
15027c478bdstevel@tonic-gate			fixmode = s1.st_mode;
15037c478bdstevel@tonic-gate		}
15047c478bdstevel@tonic-gate		(void) chmod(target, ((fixmode & MODEBITS) | S_IRWXU));
15057c478bdstevel@tonic-gate	} else if (!(ISDIR(s2))) {
15067c478bdstevel@tonic-gate		(void) fprintf(stderr,
15077c478bdstevel@tonic-gate		    gettext("%s: %s: not a directory.\n"), cmd, target);
15087c478bdstevel@tonic-gate		return (1);
15097c478bdstevel@tonic-gate	}
15107c478bdstevel@tonic-gate	if (pflg || mve) {
15117c478bdstevel@tonic-gate		/*
15127c478bdstevel@tonic-gate		 * Save s1 (stat information for source dir) and acl info,
15137c478bdstevel@tonic-gate		 * if any, so that ownership, modes, times, and acl's can
15147c478bdstevel@tonic-gate		 * be reserved during "cp -p" or mv.
15157c478bdstevel@tonic-gate		 * s1 gets overwritten when doing the recursive copy.
15167c478bdstevel@tonic-gate		 */
15177c478bdstevel@tonic-gate		s1save = s1;
1518fa9e406ahrens		if (s1acl != NULL) {
1519fa9e406ahrens			s1acl_save = acl_dup(s1acl);
1520fa9e406ahrens			if (s1acl_save == NULL) {
1521fa9e406ahrens				(void) fprintf(stderr, gettext("%s: "
1522fa9e406ahrens				    "Insufficient memory to save acl"
1523fa9e406ahrens				    " entry\n"), cmd);
1524fa9e406ahrens				if (pflg)
1525fa9e406ahrens					return (1);
1526fa9e406ahrens
15277c478bdstevel@tonic-gate			}
15283d63ea0as#ifdef XPG4
15293d63ea0as			else {
15303d63ea0as				(void) fprintf(stderr, gettext("%s: "
15313d63ea0as				    "Insufficient memory to save acl"
15323d63ea0as				    " entry\n"), cmd);
15333d63ea0as				if (pflg)
15343d63ea0as					return (1);
15353d63ea0as			}
15367c478bdstevel@tonic-gate#endif
15377c478bdstevel@tonic-gate		}
15387c478bdstevel@tonic-gate	}
15397c478bdstevel@tonic-gate
15407c478bdstevel@tonic-gate	ret = rcopy(source, target);
15417c478bdstevel@tonic-gate
15427c478bdstevel@tonic-gate	/*
15437c478bdstevel@tonic-gate	 * Once we created a directory, go ahead and set
15447c478bdstevel@tonic-gate	 * its attributes, e.g. acls and time. The info
15457c478bdstevel@tonic-gate	 * may get overwritten if we continue traversing
15467c478bdstevel@tonic-gate	 * down the tree.
15477c478bdstevel@tonic-gate	 *
15487c478bdstevel@tonic-gate	 * ACL for directory
15497c478bdstevel@tonic-gate	 */
15507c478bdstevel@tonic-gate	if (pflg || mve) {
1551d2443e7marks		if ((pret = chg_mode(target, UID(s1save), GID(s1save),
1552d2443e7marks		    FMODE(s1save))) == 0)
1553d2443e7marks			pret = chg_time(target, s1save);
1554d2443e7marks		ret += pret;
1555fa9e406ahrens		if (s1acl_save != NULL) {
1556fa9e406ahrens			if (acl_set(target, s1acl_save) < 0) {
1557cee1ddabasabi				error++;
15587c478bdstevel@tonic-gate#ifdef XPG4
15597c478bdstevel@tonic-gate				if (pflg || mve) {
15607c478bdstevel@tonic-gate#else
15617c478bdstevel@tonic-gate				if (pflg) {
15627c478bdstevel@tonic-gate#endif
15637c478bdstevel@tonic-gate					(void) fprintf(stderr, gettext(
15647c478bdstevel@tonic-gate					    "%s: failed to set acl entries "
15657c478bdstevel@tonic-gate					    "on %s\n"), cmd, target);
15667c478bdstevel@tonic-gate					if (pflg) {
1567fa9e406ahrens						acl_free(s1acl_save);
1568fa9e406ahrens						s1acl_save = NULL;
15697c478bdstevel@tonic-gate						ret++;
15707c478bdstevel@tonic-gate					}
15717c478bdstevel@tonic-gate				}
15727c478bdstevel@tonic-gate				/* else: silent and continue */
15737c478bdstevel@tonic-gate			}
1574fa9e406ahrens			acl_free(s1acl_save);
1575fa9e406ahrens			s1acl_save = NULL;
15767c478bdstevel@tonic-gate		}
15777c478bdstevel@tonic-gate	} else if (fixmode != (mode_t)0)
15787c478bdstevel@tonic-gate		(void) chmod(target, fixmode & MODEBITS);
15797c478bdstevel@tonic-gate
1580da6c28aamw	if (pflg || atflg || mve || saflg) {
15817c478bdstevel@tonic-gate		attret = copyattributes(source, target);
15827c478bdstevel@tonic-gate		if (!attrsilent && attret != 0) {
15837c478bdstevel@tonic-gate			(void) fprintf(stderr, gettext("%s: Failed to preserve"
15847c478bdstevel@tonic-gate			    " extended attributes of directory"
15857c478bdstevel@tonic-gate			    " %s\n"), cmd, source);
15867c478bdstevel@tonic-gate		} else {
15877c478bdstevel@tonic-gate			/*
15887c478bdstevel@tonic-gate			 * Otherwise ignore failure.
15897c478bdstevel@tonic-gate			 */
15907c478bdstevel@tonic-gate			attret = 0;
15917c478bdstevel@tonic-gate		}
1592da6c28aamw		/* Copy extended system attributes */
1593da6c28aamw		if (pflg || mve || saflg) {
1594cee1ddabasabi			sattret = copy_sysattr(source, target);
1595cee1ddabasabi			if (sattret != 0) {
1596da6c28aamw				(void) fprintf(stderr, gettext(
1597da6c28aamw				    "%s: Failed to preserve "
1598da6c28aamw				    "extended system attributes "
1599da6c28aamw				    "of directory %s\n"), cmd, source);
1600da6c28aamw			}
1601da6c28aamw		}
16027c478bdstevel@tonic-gate	}
1603cee1ddabasabi	if (attret != 0 || sattret != 0 || error != 0)
1604cee1ddabasabi		return (1);
16057c478bdstevel@tonic-gate	return (ret);
16067c478bdstevel@tonic-gate}
16077c478bdstevel@tonic-gate
16087c478bdstevel@tonic-gatestatic int
16097c478bdstevel@tonic-gatecopyspecial(char *target)
16107c478bdstevel@tonic-gate{
16117c478bdstevel@tonic-gate	int ret = 0;
16127c478bdstevel@tonic-gate
16137c478bdstevel@tonic-gate	if (mknod(target, s1.st_mode, s1.st_rdev) != 0) {
16147c478bdstevel@tonic-gate		(void) fprintf(stderr, gettext(
16157c478bdstevel@tonic-gate		    "cp: cannot create special file %s: "), target);
16167c478bdstevel@tonic-gate		perror("");
16177c478bdstevel@tonic-gate		return (1);
16187c478bdstevel@tonic-gate	}
16197c478bdstevel@tonic-gate
16207c478bdstevel@tonic-gate	if (pflg) {
16217c478bdstevel@tonic-gate		if ((ret = chg_mode(target, UID(s1), GID(s1), FMODE(s1))) == 0)
16227c478bdstevel@tonic-gate			ret = chg_time(target, s1);
16237c478bdstevel@tonic-gate	}
16247c478bdstevel@tonic-gate
16257c478bdstevel@tonic-gate	return (ret);
16267c478bdstevel@tonic-gate}
16277c478bdstevel@tonic-gate
16287c478bdstevel@tonic-gatestatic int
16297c478bdstevel@tonic-gateuse_stdin(void)
16307c478bdstevel@tonic-gate{
16317c478bdstevel@tonic-gate#ifdef XPG4
16327c478bdstevel@tonic-gate	return (1);
16337c478bdstevel@tonic-gate#else
16347c478bdstevel@tonic-gate	return (isatty(fileno(stdin)));
16357c478bdstevel@tonic-gate#endif
16367c478bdstevel@tonic-gate}
16377c478bdstevel@tonic-gate
1638da6c28aamw/* Copy non-system extended attributes */
1639da6c28aamw
16407c478bdstevel@tonic-gatestatic int
16417c478bdstevel@tonic-gatecopyattributes(char *source, char *target)
16427c478bdstevel@tonic-gate{
16437c478bdstevel@tonic-gate	struct dirent *dp;
16447c478bdstevel@tonic-gate	int error = 0;
1645fa9e406ahrens	int aclerror;
16467c478bdstevel@tonic-gate	mode_t mode;
16477c478bdstevel@tonic-gate	int clearflg = 0;
1648fa9e406ahrens	acl_t *xacl = NULL;
1649fa9e406ahrens	acl_t *attrdiracl = NULL;
165078cca7eRoger A. Faulkner	struct timespec times[2];
16517c478bdstevel@tonic-gate
1652da6c28aamw
1653da6c28aamw	if (pathconf(source,  _PC_XATTR_EXISTS) != 1)
16547c478bdstevel@tonic-gate		return (0);
16557c478bdstevel@tonic-gate
16567c478bdstevel@tonic-gate	if (pathconf(target, _PC_XATTR_ENABLED) != 1) {
16577c478bdstevel@tonic-gate		if (!attrsilent) {
16587c478bdstevel@tonic-gate			(void) fprintf(stderr,
16597c478bdstevel@tonic-gate			    gettext(
16607c478bdstevel@tonic-gate			    "%s: cannot preserve extended attributes, "
16617c478bdstevel@tonic-gate			    "operation not supported on file"
16627c478bdstevel@tonic-gate			    " %s\n"), cmd, target);
16637c478bdstevel@tonic-gate		}
16647c478bdstevel@tonic-gate		return (1);
16657c478bdstevel@tonic-gate	}
1666da6c28aamw	if (open_source(source) != 0)
1667da6c28aamw		return (1);
1668da6c28aamw	if (open_target_srctarg_attrdirs(source, target) !=  0)
1669da6c28aamw		return (1);
1670da6c28aamw	if (open_attrdirp(source) != 0)
1671da6c28aamw		return (1);
16727c478bdstevel@tonic-gate
16737c478bdstevel@tonic-gate	if (pflg || mve) {
16747c478bdstevel@tonic-gate		if (fchmod(targetdirfd, attrdir.st_mode) == -1) {
16757c478bdstevel@tonic-gate			if (!attrsilent) {
16767c478bdstevel@tonic-gate				(void) fprintf(stderr,
16773d63ea0as				    gettext("%s: failed to set file mode"
16783d63ea0as				    " correctly on attribute directory of"
16793d63ea0as				    " file %s: "), cmd, target);
16807c478bdstevel@tonic-gate				perror("");
16817c478bdstevel@tonic-gate				++error;
16827c478bdstevel@tonic-gate			}
16837c478bdstevel@tonic-gate		}
16847c478bdstevel@tonic-gate
16857c478bdstevel@tonic-gate		if (fchown(targetdirfd, attrdir.st_uid, attrdir.st_gid) == -1) {
16867c478bdstevel@tonic-gate			if (!attrsilent) {
16877c478bdstevel@tonic-gate				(void) fprintf(stderr,
16887c478bdstevel@tonic-gate				    gettext("%s: failed to set file"
16897c478bdstevel@tonic-gate				    " ownership correctly on attribute"
16907c478bdstevel@tonic-gate				    " directory of file %s: "), cmd, target);
16917c478bdstevel@tonic-gate				perror("");
16927c478bdstevel@tonic-gate				++error;
16937c478bdstevel@tonic-gate			}
16947c478bdstevel@tonic-gate		}
16957c478bdstevel@tonic-gate		/*
16967c478bdstevel@tonic-gate		 * Now that we are the owner we can update st_ctime by calling
169778cca7eRoger A. Faulkner		 * utimensat.
16987c478bdstevel@tonic-gate		 */
169978cca7eRoger A. Faulkner		times[0] = attrdir.st_atim;
170078cca7eRoger A. Faulkner		times[1] = attrdir.st_mtim;
170178cca7eRoger A. Faulkner		if (utimensat(targetdirfd, ".", times, 0) < 0) {
17027c478bdstevel@tonic-gate			if (!attrsilent) {
17037c478bdstevel@tonic-gate				(void) fprintf(stderr,
17043d63ea0as				    gettext("%s: cannot set attribute times"
17053d63ea0as				    " for %s: "), cmd, target);
17067c478bdstevel@tonic-gate				perror("");
17077c478bdstevel@tonic-gate				++error;
17087c478bdstevel@tonic-gate			}
17097c478bdstevel@tonic-gate		}
17107c478bdstevel@tonic-gate
17117c478bdstevel@tonic-gate		/*
17127c478bdstevel@tonic-gate		 * Now set owner and group of attribute directory, implies
17137c478bdstevel@tonic-gate		 * changing the ACL of the hidden attribute directory first.
17147c478bdstevel@tonic-gate		 */
1715fa9e406ahrens		if ((aclerror = facl_get(sourcedirfd,
1716fa9e406ahrens		    ACL_NO_TRIVIAL, &attrdiracl)) != 0) {
17177c478bdstevel@tonic-gate			if (!attrsilent) {
17187c478bdstevel@tonic-gate				(void) fprintf(stderr, gettext(
17197c478bdstevel@tonic-gate				    "%s: failed to get acl entries of"
17207c478bdstevel@tonic-gate				    " attribute directory for"
1721fa9e406ahrens				    " %s : %s\n"), cmd,
1722fa9e406ahrens				    source, acl_strerror(aclerror));
17237c478bdstevel@tonic-gate				++error;
17247c478bdstevel@tonic-gate			}
17257c478bdstevel@tonic-gate		}
1726fa9e406ahrens
1727fa9e406ahrens		if (attrdiracl) {
1728fa9e406ahrens			if (facl_set(targetdirfd, attrdiracl) != 0) {
17297c478bdstevel@tonic-gate				if (!attrsilent) {
17307c478bdstevel@tonic-gate					(void) fprintf(stderr, gettext(
1731fa9e406ahrens					"%s: failed to set acl entries"
1732