4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
27 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
31 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
32 /* All Rights Reserved */
35 * University Copyright- Copyright (c) 1982, 1986, 1988
36 * The Regents of the University of California
39 * University Acknowledgment- Portions of this document are derived from
40 * software developed by the University of California, Berkeley, and its
45 * Combined mv/cp/ln command:
48 * mv file1 ... filen dir1
55 #include <libcmdutils.h>
57 #include "getresponse.h"
59 #define FTYPE(A) (A.st_mode)
60 #define FMODE(A) (A.st_mode)
61 #define UID(A) (A.st_uid)
62 #define GID(A) (A.st_gid)
63 #define IDENTICAL(A, B) (A.st_dev == B.st_dev && A.st_ino == B.st_ino)
64 #define ISDIR(A) ((A.st_mode & S_IFMT) == S_IFDIR)
65 #define ISDOOR(A) ((A.st_mode & S_IFMT) == S_IFDOOR)
66 #define ISLNK(A) ((A.st_mode & S_IFMT) == S_IFLNK)
67 #define ISREG(A) (((A).st_mode & S_IFMT) == S_IFREG)
68 #define ISDEV(A) ((A.st_mode & S_IFMT) == S_IFCHR || \
69 (A.st_mode & S_IFMT) == S_IFBLK || \
70 (A.st_mode & S_IFMT) == S_IFIFO)
71 #define ISSOCK(A) ((A.st_mode & S_IFMT) == S_IFSOCK)
74 #define EQ(x, y) (strcmp(x, y) == 0)
76 #define MODEBITS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
79 static char *dname(char *);
80 static int lnkfil(char *, char *);
81 static int cpymve(char *, char *);
82 static int chkfiles(char *, char **);
83 static int rcopy(char *, char *);
84 static int chk_different(char *, char *);
85 static int chg_time(char *, struct stat
);
86 static int chg_mode(char *, uid_t
, gid_t
, mode_t
);
87 static int copydir(char *, char *);
88 static int copyspecial(char *);
89 static int getrealpath(char *, char *);
90 static void usage(void);
91 static void Perror(char *);
92 static void Perror2(char *, char *);
93 static int use_stdin(void);
94 static int copyattributes(char *, char *);
95 static int copy_sysattr(char *, char *);
96 static tree_node_t
*create_tnode(dev_t
, ino_t
);
98 static struct stat s1
, s2
, s3
, s4
;
99 static int cpy
= FALSE
;
100 static int mve
= FALSE
;
101 static int lnk
= FALSE
;
103 static int silent
= 0;
107 static int Rflg
= 0; /* recursive copy */
108 static int rflg
= 0; /* recursive copy */
110 static int Hflg
= 0; /* follow cmd line arg symlink to dir */
111 static int Lflg
= 0; /* follow symlinks */
112 static int Pflg
= 0; /* do not follow symlinks */
113 static int atflg
= 0;
114 static int attrsilent
= 0;
115 static int targetexists
= 0;
116 static int cmdarg
; /* command line argument */
117 static avl_tree_t
*stree
= NULL
; /* source file inode search tree */
119 static int saflg
= 0; /* 'cp' extended system attr. */
120 static int srcfd
= -1;
121 static int targfd
= -1;
122 static int sourcedirfd
= -1;
123 static int targetdirfd
= -1;
124 static DIR *srcdirp
= NULL
;
125 static int srcattrfd
= -1;
126 static int targattrfd
= -1;
127 static struct stat attrdir
;
129 /* Extended system attributes support */
131 static int open_source(char *);
132 static int open_target_srctarg_attrdirs(char *, char *);
133 static int open_attrdirp(char *);
134 static int traverse_attrfile(struct dirent
*, char *, char *, int);
135 static void rewind_attrdir(DIR *);
136 static void close_all();
140 main(int argc
, char *argv
[])
142 int c
, i
, r
, errflg
= 0;
143 char target
[PATH_MAX
];
144 int (*move
)(char *, char *);
147 * Determine command invoked (mv, cp, or ln)
150 if (cmd
= strrchr(argv
[0], '/'))
156 * Set flags based on command.
159 (void) setlocale(LC_ALL
, "");
160 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
161 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
163 (void) textdomain(TEXT_DOMAIN
);
164 if (init_yes() < 0) {
165 (void) fprintf(stderr
, gettext(ERR_MSG_INIT_YES
),
172 else if (EQ(cmd
, "ln"))
174 else if (EQ(cmd
, "cp"))
177 (void) fprintf(stderr
,
178 gettext("Invalid command name (%s); expecting "
179 "mv, cp, or ln.\n"), cmd
);
185 * cp [ -r|-R [-H|-L|-P]] [-afip@/] file1 [file2 ...] target
186 * cp [-afiprR@/] file1 [file2 ...] target
187 * ln [-f] [-n] [-s] file1 [file2 ...] target
188 * ln [-f] [-n] [-s] file1 [file2 ...]
189 * mv [-f|i] file1 [file2 ...] target
190 * mv [-f|i] dir1 target
194 while ((c
= getopt(argc
, argv
, "afHiLpPrR@/")) != EOF
)
215 * If more than one of -H, -L, or -P are
216 * specified, only the last option specified
217 * determines the behavior.
232 * The default behavior of cp -R|-r
233 * when specified without -H|-L|-P
266 /* -R or -r must be specified with -H, -L, or -P */
267 if ((Hflg
|| Lflg
|| Pflg
) && !(Rflg
|| rflg
)) {
272 while ((c
= getopt(argc
, argv
, "fis")) != EOF
)
290 while ((c
= getopt(argc
, argv
, "fns")) != EOF
)
296 /* silently ignored; this is the default */
307 * For BSD compatibility allow - to delimit the end of
310 if (mve
&& optind
< argc
&& (strcmp(argv
[optind
], "-") == 0))
314 * Check for sufficient arguments
319 argv
= &argv
[optind
];
321 if ((argc
< 2 && lnk
!= TRUE
) || (argc
< 1 && lnk
== TRUE
)) {
322 (void) fprintf(stderr
,
323 gettext("%s: Insufficient arguments (%d)\n"),
332 * If there is more than a source and target,
333 * the last argument (the target) must be a directory
334 * which really exists.
338 if (stat(argv
[argc
-1], &s2
) < 0) {
339 (void) fprintf(stderr
,
340 gettext("%s: %s not found\n"),
346 (void) fprintf(stderr
,
347 gettext("%s: Target %s must be a directory\n"),
353 if (strlen(argv
[argc
-1]) >= PATH_MAX
) {
354 (void) fprintf(stderr
,
355 gettext("%s: Target %s file name length exceeds PATH_MAX"
356 " %d\n"), cmd
, argv
[argc
-1], PATH_MAX
);
363 (void) strcpy(target
, ".");
365 (void) strcpy(target
, argv
[--argc
]);
369 * Perform a multiple argument mv|cp|ln by
370 * multiple invocations of cpymve() or lnkfil().
378 for (i
= 0; i
< argc
; i
++) {
381 r
+= move(argv
[i
], target
);
385 * Show errors by nonzero exit code.
392 lnkfil(char *source
, char *target
)
399 * If target is a directory make complete
400 * name of the new symbolic link within that
404 if ((stat(target
, &s2
) >= 0) && ISDIR(s2
)) {
407 len
= strlen(target
) + strlen(dname(source
)) + 4;
408 if ((buf
= (char *)malloc(len
)) == NULL
) {
409 (void) fprintf(stderr
,
410 gettext("%s: Insufficient memory "
411 "to %s %s\n"), cmd
, cmd
, source
);
414 (void) snprintf(buf
, len
, "%s/%s",
415 target
, dname(source
));
420 * Check to see if the file exists already.
421 * In this case we use lstat() instead of stat():
422 * unlink(2) and symlink(2) will operate on the file
423 * itself, not its reference, if the file is a symlink.
426 if ((lstat(target
, &s2
) == 0)) {
428 * Check if the silent flag is set ie. the -f option
429 * is used. If so, use unlink to remove the current
430 * target to replace with the new target, specified
431 * on the command line. Proceed with symlink.
435 * Don't allow silent (-f) removal of an existing
436 * directory; could leave unreferenced directory
440 (void) fprintf(stderr
,
441 gettext("%s: cannot create link "
442 "over directory %s\n"), cmd
,
446 if (unlink(target
) < 0) {
447 (void) fprintf(stderr
,
448 gettext("%s: cannot unlink %s: "),
458 * Create a symbolic link to the source.
461 if (symlink(source
, target
) < 0) {
462 (void) fprintf(stderr
,
463 gettext("%s: cannot create %s: "),
475 switch (chkfiles(source
, &target
)) {
478 /* default - fall through */
482 * Make sure source file is not a directory,
483 * we cannot link directories...
487 (void) fprintf(stderr
,
488 gettext("%s: %s is a directory\n"), cmd
, source
);
493 * hard link, call link() and return.
496 if (link(source
, target
) < 0) {
498 (void) fprintf(stderr
,
499 gettext("%s: %s is on a different file system\n"),
502 (void) fprintf(stderr
,
503 gettext("%s: cannot create link %s: "),
518 cpymve(char *source
, char *target
)
528 switch (chkfiles(source
, &target
)) {
531 /* default - fall through */
535 * If it's a recursive copy and source
536 * is a directory, then call rcopy (from copydir).
541 avl_index_t where
= 0;
544 dev_t save_dev
= s1
.st_dev
;
545 ino_t save_ino
= s1
.st_ino
;
548 * We will be recursing into the directory so
549 * save the inode information to a search tree
550 * to avoid getting into an endless loop.
552 if ((rc
= add_tnode(&stree
, save_dev
, save_ino
)) != 1) {
555 * We've already visited this directory.
556 * Don't remove the search tree entry
557 * to make sure we don't get into an
558 * endless loop if revisited from a
559 * different part of the hierarchy.
561 (void) fprintf(stderr
, gettext(
562 "%s: cycle detected: %s\n"),
571 rc
= copydir(source
, target
);
574 * Create a tnode to get an index to the matching
575 * node (same dev and inode) in the search tree,
576 * then use the index to remove the matching node
577 * so it we do not wrongly detect a cycle when
578 * revisiting this directory from another part of
581 if ((tnode
= create_tnode(save_dev
,
582 save_ino
)) == NULL
) {
586 if ((tptr
= avl_find(stree
, tnode
, &where
)) != NULL
) {
587 avl_remove(stree
, tptr
);
593 } else if (ISDEV(s1
) && Rflg
) {
594 return (copyspecial(target
));
601 if (rename(source
, target
) >= 0)
603 if (errno
!= EXDEV
) {
604 if (errno
== ENOTDIR
&& ISDIR(s1
)) {
605 (void) fprintf(stderr
,
606 gettext("%s: %s is a directory\n"),
610 (void) fprintf(stderr
,
611 gettext("%s: cannot rename %s to %s: "),
612 cmd
, source
, target
);
618 * cannot move a non-directory (source) onto an existing
622 if (targetexists
&& ISDIR(s2
) && (!ISDIR(s1
))) {
623 (void) fprintf(stderr
,
624 gettext("%s: cannot mv a non directory %s "
625 "over existing directory"
626 " %s \n"), cmd
, source
, target
);
631 if (targetexists
&& ISDIR(s2
)) {
632 /* existing target dir must be empty */
633 if (rmdir(target
) < 0) {
635 (void) fprintf(stderr
,
636 gettext("%s: cannot rmdir %s: "),
644 if ((n
= copydir(source
, target
)) == 0)
645 (void) rmdir(source
);
649 /* doors cannot be moved across filesystems */
651 (void) fprintf(stderr
,
652 gettext("%s: %s: cannot move door "
653 "across file systems\n"), cmd
, source
);
657 /* sockets cannot be moved across filesystems */
659 (void) fprintf(stderr
,
660 gettext("%s: %s: cannot move socket "
661 "across file systems\n"), cmd
, source
);
666 * File cannot be renamed, try to recreate the symbolic
667 * link or special device, or copy the file wholesale
668 * between file systems.
673 char symln
[PATH_MAX
+ 1];
675 if (targetexists
&& unlink(target
) < 0) {
676 (void) fprintf(stderr
,
677 gettext("%s: cannot unlink %s: "),
683 if ((m
= readlink(source
, symln
,
684 sizeof (symln
) - 1)) < 0) {
690 md
= umask(~(s1
.st_mode
& MODEBITS
));
691 if (symlink(symln
, target
) < 0) {
696 m
= lchown(target
, UID(s1
), GID(s1
));
699 (void) fprintf(stderr
, gettext("%s: cannot"
700 " change owner and group of"
701 " %s: "), cmd
, target
);
709 if (targetexists
&& unlink(target
) < 0) {
710 (void) fprintf(stderr
,
711 gettext("%s: cannot unlink %s: "),
717 if (mknod(target
, s1
.st_mode
, s1
.st_rdev
) < 0) {
722 (void) chg_mode(target
, UID(s1
), GID(s1
), FMODE(s1
));
723 (void) chg_time(target
, s1
);
729 if (targetexists
&& rmdir(target
) < 0) {
730 (void) fprintf(stderr
,
731 gettext("%s: cannot rmdir %s: "),
737 if (targetexists
&& unlink(target
) < 0) {
738 (void) fprintf(stderr
,
739 gettext("%s: cannot unlink %s: "),
749 * If the source file is a symlink, and either
750 * -P or -H flag (only if -H is specified and the
751 * source file is not a command line argument)
752 * were specified, then action is taken on the symlink
753 * itself, not the file referenced by the symlink.
754 * Note: this is executed for 'cp' only.
756 if (cpy
&& (Pflg
|| (Hflg
&& !cmdarg
)) && (ISLNK(s1
))) {
759 char symln
[PATH_MAX
+ 1];
761 m
= readlink(source
, symln
, sizeof (symln
) - 1);
770 * Copy the sym link to the target.
771 * Note: If the target exists, write a
772 * diagnostic message, do nothing more
773 * with the source file, and return to
774 * process any remaining files.
776 md
= umask(~(s1
.st_mode
& MODEBITS
));
777 if (symlink(symln
, target
) < 0) {
782 m
= lchown(target
, UID(s1
), GID(s1
));
785 (void) fprintf(stderr
, gettext(
786 "cp: cannot change owner and "
787 "group of %s:"), target
);
792 * Copy the file. If it happens to be a
793 * symlink, copy the file referenced
796 fi
= open(source
, O_RDONLY
);
798 (void) fprintf(stderr
,
799 gettext("%s: cannot open %s: "),
805 fo
= creat(target
, s1
.st_mode
& MODEBITS
);
808 * If -f and creat() failed, unlink
812 (void) unlink(target
);
814 s1
.st_mode
& MODEBITS
);
818 (void) fprintf(stderr
,
819 gettext("%s: cannot create %s: "),
825 /* stat the new file, its used below */
826 (void) stat(target
, &s2
);
830 * Set target's permissions to the source
831 * before any copying so that any partially
832 * copied file will have the source's
833 * permissions (at most) or umask permissions
834 * whichever is the most restrictive.
836 * ACL for regular files
840 (void) chmod(target
, FMODE(s1
));
845 (void) fprintf(stderr
,
861 if (fstat(fi
, &s1
) < 0) {
862 (void) fprintf(stderr
,
863 gettext("%s: cannot access %s\n"),
867 if (IDENTICAL(s1
, s2
)) {
868 (void) fprintf(stderr
,
870 "%s: %s and %s are identical\n"),
871 cmd
, source
, target
);
875 if (writefile(fi
, fo
, source
, target
, NULL
,
876 NULL
, &s1
, &s2
) != 0) {
882 Perror2(target
, "write");
886 /* Copy regular extended attributes */
887 if (pflg
|| atflg
|| mve
|| saflg
) {
888 attret
= copyattributes(source
, target
);
889 if (attret
!= 0 && !attrsilent
) {
890 (void) fprintf(stderr
, gettext(
891 "%s: Failed to preserve"
892 " extended attributes of file"
893 " %s\n"), cmd
, source
);
895 /* Copy extended system attributes */
896 if (pflg
|| mve
|| saflg
)
897 sattret
= copy_sysattr(source
, target
);
898 if (mve
&& attret
!= 0) {
899 (void) unlink(target
);
908 * XPG4: the write system call will clear setgid
909 * and setuid bits, so set them again.
912 if ((ret
= chg_mode(target
, UID(s1
), GID(s1
),
916 * Reapply ACL, since chmod may have
920 if ((acl_set(target
, s1acl
)) < 0) {
922 (void) fprintf(stderr
,
923 gettext("%s: Failed to "
925 "on %s\n"), cmd
, target
);
932 if ((ret
= chg_time(target
, s1
)) > 0)
936 if (error
!= 0 || attret
!= 0 || sattret
!= 0)
942 (void) fprintf(stderr
,
943 gettext("%s: %s: unknown file type 0x%x\n"), cmd
,
944 source
, (s1
.st_mode
& S_IFMT
));
948 if (unlink(source
) < 0) {
949 (void) unlink(target
);
950 (void) fprintf(stderr
,
951 gettext("%s: cannot unlink %s: "),
956 if (error
!= 0 || attret
!= 0 || sattret
!= 0)
967 * Create a node for use with the search tree which contains the
968 * inode information (device id and inode number).
975 * tnode - NULL on error, otherwise returns a tnode structure
976 * which contains the input device id and inode number.
979 create_tnode(dev_t dev
, ino_t ino
)
983 if ((tnode
= (tree_node_t
*)malloc(sizeof (tree_node_t
))) != NULL
) {
984 tnode
->node_dev
= dev
;
985 tnode
->node_ino
= ino
;
992 chkfiles(char *source
, char **to
)
994 char *buf
= (char *)NULL
;
995 int (*statf
)() = (cpy
&&
996 !(Pflg
|| (Hflg
&& !cmdarg
))) ? stat
: lstat
;
1001 * Make sure source file exists.
1003 if ((*statf
)(source
, &s1
) < 0) {
1005 * Keep the old error message except when someone tries to
1006 * mv/cp/ln a symbolic link that has a trailing slash and
1009 if (errno
== ENOTDIR
)
1010 (void) fprintf(stderr
, "%s: %s: %s\n", cmd
, source
,
1013 (void) fprintf(stderr
,
1014 gettext("%s: cannot access %s\n"), cmd
, source
);
1019 * Get ACL info: don't bother with ln or cp/mv'ing symlinks
1021 if (!lnk
&& !ISLNK(s1
)) {
1022 if (s1acl
!= NULL
) {
1026 if ((error
= acl_get(source
, ACL_NO_TRIVIAL
, &s1acl
)) != 0) {
1027 (void) fprintf(stderr
,
1028 "%s: failed to get acl entries: %s\n", source
,
1029 acl_strerror(error
));
1032 /* else: just permission bits */
1036 * If stat fails, then the target doesn't exist,
1037 * we will create a new target with default file type of regular.
1040 FTYPE(s2
) = S_IFREG
;
1042 if ((*statf
)(target
, &s2
) >= 0) {
1044 (void) stat(target
, &s2
);
1046 * If target is a directory,
1047 * make complete name of new file
1048 * within that directory.
1053 len
= strlen(target
) + strlen(dname(source
)) + 4;
1054 if ((buf
= (char *)malloc(len
)) == NULL
) {
1055 (void) fprintf(stderr
,
1056 gettext("%s: Insufficient memory to "
1057 "%s %s\n "), cmd
, cmd
, source
);
1060 (void) snprintf(buf
, len
, "%s/%s",
1061 target
, dname(source
));
1065 if ((*statf
)(target
, &s2
) >= 0) {
1066 int overwrite
= FALSE
;
1067 int override
= FALSE
;
1072 * For cp and mv, it is an error if the
1073 * source and target are the same file.
1074 * Check for the same inode and file
1075 * system, but don't check for the same
1076 * absolute pathname because it is an
1077 * error when the source and target are
1078 * hard links to the same file.
1080 if (IDENTICAL(s1
, s2
)) {
1081 (void) fprintf(stderr
,
1083 "%s: %s and %s are identical\n"),
1084 cmd
, source
, target
);
1092 * For ln, it is an error if the source and
1093 * target are identical files (same inode,
1094 * same file system, and filenames resolve
1095 * to same absolute pathname).
1097 if (!chk_different(source
, target
)) {
1103 if (lnk
&& !silent
) {
1104 (void) fprintf(stderr
,
1105 gettext("%s: %s: File exists\n"),
1114 * If the user does not have access to
1115 * the target, ask ----if it is not
1116 * silent and user invoked command
1120 * If not silent, and stdin is a terminal, and
1121 * there's no write access, and the file isn't a
1122 * symbolic link, ask for permission.
1124 * XPG4: both overwrite and override:
1125 * ask only one question.
1127 * TRANSLATION_NOTE - The following messages will
1128 * contain the first character of the strings for
1129 * "yes" and "no" defined in the file
1130 * "nl_langinfo.po". After substitution, the
1131 * message will appear as follows:
1132 * <cmd>: overwrite <filename> (y/n)?
1133 * where <cmd> is the name of the command
1134 * (cp, mv) and <filename> is the destination file
1138 overwrite
= iflg
&& !silent
&& use_stdin();
1139 override
= !cpy
&& (access(target
, 2) < 0) &&
1140 !silent
&& use_stdin() && !ISLNK(s2
);
1142 if (overwrite
&& override
) {
1143 (void) fprintf(stderr
,
1144 gettext("%s: overwrite %s and override "
1145 "protection %o (%s/%s)? "), cmd
, target
,
1146 FMODE(s2
) & MODEBITS
, yesstr
, nostr
);
1152 } else if (overwrite
&& ISREG(s2
)) {
1153 (void) fprintf(stderr
,
1154 gettext("%s: overwrite %s (%s/%s)? "),
1155 cmd
, target
, yesstr
, nostr
);
1161 } else if (override
) {
1162 (void) fprintf(stderr
,
1163 gettext("%s: %s: override protection "
1167 cmd
, target
, FMODE(s2
) & MODEBITS
,
1176 if (lnk
&& unlink(target
) < 0) {
1177 (void) fprintf(stderr
,
1178 gettext("%s: cannot unlink %s: "),
1189 * check whether source and target are different
1190 * return 1 when they are different
1191 * return 0 when they are identical, or when unable to resolve a pathname
1194 chk_different(char *source
, char *target
)
1196 char rtarget
[PATH_MAX
], rsource
[PATH_MAX
];
1198 if (IDENTICAL(s1
, s2
)) {
1200 * IDENTICAL will be true for hard links, therefore
1201 * check whether the filenames are different
1203 if ((getrealpath(source
, rsource
) == 0) ||
1204 (getrealpath(target
, rtarget
) == 0)) {
1207 if (strncmp(rsource
, rtarget
, PATH_MAX
) == 0) {
1208 (void) fprintf(stderr
, gettext(
1209 "%s: %s and %s are identical\n"),
1210 cmd
, source
, target
);
1218 * get real path (resolved absolute pathname)
1219 * return 1 on success, 0 on failure
1222 getrealpath(char *path
, char *rpath
)
1224 if (realpath(path
, rpath
) == NULL
) {
1225 int errno_save
= errno
;
1226 (void) fprintf(stderr
, gettext(
1227 "%s: cannot resolve path %s: "), cmd
, path
);
1236 rcopy(char *from
, char *to
)
1238 DIR *fold
= opendir(from
);
1240 struct stat statb
, s1save
;
1242 char fromname
[PATH_MAX
];
1244 if (fold
== 0 || ((pflg
|| mve
) && fstat(fold
->dd_fd
, &statb
) < 0)) {
1250 * Save s1 (stat information for source dir) so that
1251 * mod and access times can be reserved during "cp -p"
1252 * or mv, since s1 gets overwritten.
1259 (void) closedir(fold
);
1261 return (chg_time(to
, s1save
) + errs
);
1266 if ((strcmp(dp
->d_name
, ".") == 0) ||
1267 (strcmp(dp
->d_name
, "..") == 0))
1269 if (strlen(from
)+1+strlen(dp
->d_name
) >=
1270 sizeof (fromname
) - 1) {
1271 (void) fprintf(stderr
,
1272 gettext("%s : %s/%s: Name too long\n"),
1273 cmd
, from
, dp
->d_name
);
1277 (void) snprintf(fromname
, sizeof (fromname
),
1278 "%s/%s", from
, dp
->d_name
);
1279 errs
+= cpymve(fromname
, to
);
1289 * Return just the file name given the complete path.
1296 * While there are characters left,
1297 * set name to start after last
1302 if (*p
++ == DELIM
&& *p
)
1311 * Display usage message.
1315 (void) fprintf(stderr
, gettext(
1316 "Usage: mv [-f] [-i] f1 f2\n"
1317 " mv [-f] [-i] f1 ... fn d1\n"
1318 " mv [-f] [-i] d1 d2\n"));
1321 (void) fprintf(stderr
, gettext(
1322 "Usage: ln [-f] [-s] f1 [f2]\n"
1323 " ln [-f] [-s] f1 ... fn d1\n"
1324 " ln [-f] -s d1 d2\n"));
1326 (void) fprintf(stderr
, gettext(
1327 "Usage: ln [-f] [-n] [-s] f1 [f2]\n"
1328 " ln [-f] [-n] [-s] f1 ... fn d1\n"
1329 " ln [-f] [-n] -s d1 d2\n"));
1332 (void) fprintf(stderr
, gettext(
1333 "Usage: cp [-a] [-f] [-i] [-p] [-@] [-/] f1 f2\n"
1334 " cp [-a] [-f] [-i] [-p] [-@] [-/] f1 ... fn d1\n"
1335 " cp [-r|-R [-H|-L|-P]] [-a] [-f] [-i] [-p] [-@] "
1336 "[-/] d1 ... dn-1 dn\n"));
1344 * Try to preserve modification and access time.
1345 * If 1) pflg is not set, or 2) pflg is set and this is the Solaris version,
1346 * don't report a utimensat() failure.
1347 * If this is the XPG4 version and utimensat fails, if 1) pflg is set (cp -p)
1348 * or 2) we are doing a mv, print a diagnostic message; arrange for a non-zero
1349 * exit status only if pflg is set.
1350 * utimensat(2) is being used to achieve granularity in nanoseconds
1351 * (if supported by the underlying file system) while setting file times.
1354 chg_time(char *to
, struct stat ss
)
1356 struct timespec times
[2];
1359 times
[0] = ss
.st_atim
;
1360 times
[1] = ss
.st_mtim
;
1362 rc
= utimensat(AT_FDCWD
, to
, times
,
1363 ISLNK(s1
) ? AT_SYMLINK_NOFOLLOW
: 0);
1365 if ((pflg
|| mve
) && rc
!= 0) {
1366 (void) fprintf(stderr
,
1367 gettext("%s: cannot set times for %s: "), cmd
, to
);
1381 * This function is called upon "cp -p" or mv across filesystems.
1383 * Try to preserve the owner and group id. If chown() fails,
1384 * only print a diagnostic message if doing a mv in the XPG4 version;
1385 * try to clear S_ISUID and S_ISGID bits in the target. If unable to clear
1386 * S_ISUID and S_ISGID bits, print a diagnostic message and arrange for a
1387 * non-zero exit status because this is a security violation.
1388 * Try to preserve permissions.
1389 * If this is the XPG4 version and chmod() fails, print a diagnostic message
1390 * and arrange for a non-zero exit status.
1391 * If this is the Solaris version and chmod() fails, do not print a
1392 * diagnostic message or exit with a non-zero value.
1395 chg_mode(char *target
, uid_t uid
, gid_t gid
, mode_t mode
)
1397 int clearflg
= 0; /* controls message printed upon chown() error */
1400 /* Don't change mode if target is symlink */
1401 if (lstat(target
, &st
) == 0 && ISLNK(st
))
1404 if (chown(target
, uid
, gid
) != 0) {
1407 (void) fprintf(stderr
, gettext("%s: cannot change"
1408 " owner and group of %s: "), cmd
, target
);
1412 if (mode
& (S_ISUID
| S_ISGID
)) {
1413 /* try to clear S_ISUID and S_ISGID */
1414 mode
&= ~S_ISUID
& ~S_ISGID
;
1418 if (chmod(target
, mode
) != 0) {
1420 (void) fprintf(stderr
, gettext(
1421 "%s: cannot clear S_ISUID and S_ISGID bits in"
1422 " %s: "), cmd
, target
);
1424 /* cp -p should get non-zero exit; mv should not */
1430 (void) fprintf(stderr
, gettext(
1431 "%s: cannot set permissions for %s: "), cmd
, target
);
1433 /* cp -p should get non-zero exit; mv should not */
1446 char buf
[PATH_MAX
+ 10];
1448 (void) snprintf(buf
, sizeof (buf
), "%s: %s", cmd
, s
);
1453 Perror2(char *s1
, char *s2
)
1455 char buf
[PATH_MAX
+ 20];
1457 (void) snprintf(buf
, sizeof (buf
), "%s: %s: %s",
1458 cmd
, gettext(s1
), gettext(s2
));
1463 * used for cp -R and for mv across file systems
1466 copydir(char *source
, char *target
)
1468 int ret
, attret
= 0;
1470 int pret
= 0; /* need separate flag if -p is specified */
1471 mode_t fixmode
= (mode_t
)0; /* cleanup mode after copy */
1479 (void) fprintf(stderr
,
1480 gettext("%s: %s: is a directory\n"), cmd
, source
);
1484 if (stat(target
, &s2
) < 0) {
1485 if (mkdir(target
, (s1
.st_mode
& MODEBITS
)) < 0) {
1486 (void) fprintf(stderr
, "%s: ", cmd
);
1490 if (stat(target
, &s2
) == 0) {
1491 fixmode
= s2
.st_mode
;
1493 fixmode
= s1
.st_mode
;
1495 (void) chmod(target
, ((fixmode
& MODEBITS
) | S_IRWXU
));
1496 } else if (!(ISDIR(s2
))) {
1497 (void) fprintf(stderr
,
1498 gettext("%s: %s: not a directory.\n"), cmd
, target
);
1503 * Save s1 (stat information for source dir) and acl info,
1504 * if any, so that ownership, modes, times, and acl's can
1505 * be reserved during "cp -p" or mv.
1506 * s1 gets overwritten when doing the recursive copy.
1509 if (s1acl
!= NULL
) {
1510 s1acl_save
= acl_dup(s1acl
);
1511 if (s1acl_save
== NULL
) {
1512 (void) fprintf(stderr
, gettext("%s: "
1513 "Insufficient memory to save acl"
1521 (void) fprintf(stderr
, gettext("%s: "
1522 "Insufficient memory to save acl"
1531 ret
= rcopy(source
, target
);
1534 * Once we created a directory, go ahead and set
1535 * its attributes, e.g. acls and time. The info
1536 * may get overwritten if we continue traversing
1542 if ((pret
= chg_mode(target
, UID(s1save
), GID(s1save
),
1543 FMODE(s1save
))) == 0)
1544 pret
= chg_time(target
, s1save
);
1546 if (s1acl_save
!= NULL
) {
1547 if (acl_set(target
, s1acl_save
) < 0) {
1554 (void) fprintf(stderr
, gettext(
1555 "%s: failed to set acl entries "
1556 "on %s\n"), cmd
, target
);
1558 acl_free(s1acl_save
);
1563 /* else: silent and continue */
1565 acl_free(s1acl_save
);
1568 } else if (fixmode
!= (mode_t
)0)
1569 (void) chmod(target
, fixmode
& MODEBITS
);
1571 if (pflg
|| atflg
|| mve
|| saflg
) {
1572 attret
= copyattributes(source
, target
);
1573 if (!attrsilent
&& attret
!= 0) {
1574 (void) fprintf(stderr
, gettext("%s: Failed to preserve"
1575 " extended attributes of directory"
1576 " %s\n"), cmd
, source
);
1579 * Otherwise ignore failure.
1583 /* Copy extended system attributes */
1584 if (pflg
|| mve
|| saflg
) {
1585 sattret
= copy_sysattr(source
, target
);
1587 (void) fprintf(stderr
, gettext(
1588 "%s: Failed to preserve "
1589 "extended system attributes "
1590 "of directory %s\n"), cmd
, source
);
1594 if (attret
!= 0 || sattret
!= 0 || error
!= 0)
1600 copyspecial(char *target
)
1604 if (mknod(target
, s1
.st_mode
, s1
.st_rdev
) != 0) {
1605 (void) fprintf(stderr
, gettext(
1606 "cp: cannot create special file %s: "), target
);
1612 if ((ret
= chg_mode(target
, UID(s1
), GID(s1
), FMODE(s1
))) == 0)
1613 ret
= chg_time(target
, s1
);
1625 return (isatty(fileno(stdin
)));
1629 /* Copy non-system extended attributes */
1632 copyattributes(char *source
, char *target
)
1640 acl_t
*attrdiracl
= NULL
;
1641 struct timespec times
[2];
1644 if (pathconf(source
, _PC_XATTR_EXISTS
) != 1)
1647 if (pathconf(target
, _PC_XATTR_ENABLED
) != 1) {
1649 (void) fprintf(stderr
,
1651 "%s: cannot preserve extended attributes, "
1652 "operation not supported on file"
1653 " %s\n"), cmd
, target
);
1657 if (open_source(source
) != 0)
1659 if (open_target_srctarg_attrdirs(source
, target
) != 0)
1661 if (open_attrdirp(source
) != 0)
1665 if (fchmod(targetdirfd
, attrdir
.st_mode
) == -1) {
1667 (void) fprintf(stderr
,
1668 gettext("%s: failed to set file mode"
1669 " correctly on attribute directory of"
1670 " file %s: "), cmd
, target
);
1676 if (fchown(targetdirfd
, attrdir
.st_uid
, attrdir
.st_gid
) == -1) {
1678 (void) fprintf(stderr
,
1679 gettext("%s: failed to set file"
1680 " ownership correctly on attribute"
1681 " directory of file %s: "), cmd
, target
);
1687 * Now that we are the owner we can update st_ctime by calling
1690 times
[0] = attrdir
.st_atim
;
1691 times
[1] = attrdir
.st_mtim
;
1692 if (utimensat(targetdirfd
, ".", times
, 0) < 0) {
1694 (void) fprintf(stderr
,
1695 gettext("%s: cannot set attribute times"
1696 " for %s: "), cmd
, target
);
1703 * Now set owner and group of attribute directory, implies
1704 * changing the ACL of the hidden attribute directory first.
1706 if ((aclerror
= facl_get(sourcedirfd
,
1707 ACL_NO_TRIVIAL
, &attrdiracl
)) != 0) {
1709 (void) fprintf(stderr
, gettext(
1710 "%s: failed to get acl entries of"
1711 " attribute directory for"
1713 source
, acl_strerror(aclerror
));
1719 if (facl_set(targetdirfd
, attrdiracl
) != 0) {
1721 (void) fprintf(stderr
, gettext(
1722 "%s: failed to set acl entries"
1723 " on attribute directory "
1724 "for %s\n"), cmd
, target
);
1727 acl_free(attrdiracl
);
1733 while ((dp
= readdir(srcdirp
)) != NULL
) {
1736 if ((ret
= traverse_attrfile(dp
, source
, target
, 1)) == -1)
1744 if ((aclerror
= facl_get(srcattrfd
,
1745 ACL_NO_TRIVIAL
, &xacl
)) != 0) {
1747 (void) fprintf(stderr
, gettext(
1748 "%s: failed to get acl entries of"
1750 " %s: %s"), cmd
, dp
->d_name
,
1751 source
, acl_strerror(aclerror
));
1760 if ((pflg
|| mve
) && xacl
!= NULL
) {
1761 if ((facl_set(targattrfd
, xacl
)) < 0) {
1763 (void) fprintf(stderr
, gettext(
1764 "%s: failed to set acl entries on"
1766 "%s\n"), cmd
, dp
->d_name
, target
);
1774 if (writefile(srcattrfd
, targattrfd
, source
, target
,
1775 dp
->d_name
, dp
->d_name
, &s3
, &s4
) != 0) {
1785 if (fchown(targattrfd
, UID(s3
), GID(s3
)) != 0) {
1787 (void) fprintf(stderr
,
1788 gettext("%s: cannot change"
1789 " owner and group of"
1790 " attribute %s for" " file"
1791 " %s: "), cmd
, dp
->d_name
, target
);
1795 if (mode
& (S_ISUID
| S_ISGID
)) {
1796 /* try to clear S_ISUID and S_ISGID */
1797 mode
&= ~S_ISUID
& ~S_ISGID
;
1801 times
[0] = s3
.st_atim
;
1802 times
[1] = s3
.st_mtim
;
1803 if (utimensat(targetdirfd
, dp
->d_name
, times
, 0) < 0) {
1805 (void) fprintf(stderr
,
1806 gettext("%s: cannot set attribute"
1807 " times for %s: "), cmd
, target
);
1812 if (fchmod(targattrfd
, mode
) != 0) {
1814 (void) fprintf(stderr
, gettext(
1815 "%s: cannot clear S_ISUID and "
1816 "S_ISGID bits in attribute %s"
1818 " %s: "), cmd
, dp
->d_name
, target
);
1821 (void) fprintf(stderr
,
1823 "%s: cannot set permissions of attribute"
1824 " %s for %s: "), cmd
, dp
->d_name
, target
);
1830 if (xacl
&& ((facl_set(targattrfd
, xacl
)) < 0)) {
1832 (void) fprintf(stderr
, gettext(
1833 "%s: failed to set acl entries on"
1835 "%s\n"), cmd
, dp
->d_name
, target
);
1847 if (srcattrfd
!= -1)
1848 (void) close(srcattrfd
);
1849 if (targattrfd
!= -1)
1850 (void) close(targattrfd
);
1851 srcattrfd
= targattrfd
= -1;
1858 if (attrdiracl
!= NULL
) {
1859 acl_free(attrdiracl
);
1863 if (!saflg
&& !pflg
&& !mve
)
1865 return (error
== 0 ? 0 : 1);
1868 /* Copy extended system attributes from source to target */
1871 copy_sysattr(char *source
, char *target
)
1876 int target_sa_support
= 0;
1878 if (sysattr_support(source
, _PC_SATTR_EXISTS
) != 1)
1881 if (open_source(source
) != 0)
1885 * Gets non default extended system attributes from the
1886 * source file to copy to the target. The target has
1887 * the defaults set when its created and thus no need
1888 * to copy the defaults.
1890 response
= sysattr_list(cmd
, srcfd
, source
);
1892 if (sysattr_support(target
, _PC_SATTR_ENABLED
) != 1) {
1893 if (response
!= NULL
) {
1894 (void) fprintf(stderr
,
1896 "%s: cannot preserve extended system "
1897 "attribute, operation not supported on file"
1898 " %s\n"), cmd
, target
);
1903 target_sa_support
= 1;
1906 if (target_sa_support
) {
1907 if (srcdirp
== NULL
) {
1908 if (open_target_srctarg_attrdirs(source
,
1913 if (open_attrdirp(source
) != 0) {
1918 rewind_attrdir(srcdirp
);
1920 while ((dp
= readdir(srcdirp
)) != NULL
) {
1924 if ((ret
= traverse_attrfile(dp
, source
, target
,
1932 * Gets non default extended system attributes from the
1933 * attribute file to copy to the target. The target has
1934 * the defaults set when its created and thus no need
1935 * to copy the defaults.
1937 if (dp
->d_name
!= NULL
) {
1938 res
= sysattr_list(cmd
, srcattrfd
, dp
->d_name
);
1943 * Copy non default extended system attributes of named
1946 if (fsetattr(targattrfd
,
1947 XATTR_VIEW_READWRITE
, res
) != 0) {
1949 (void) fprintf(stderr
, gettext("%s: "
1950 "Failed to copy extended system "
1951 "attributes from attribute file "
1952 "%s of %s to %s\n"), cmd
,
1953 dp
->d_name
, source
, target
);
1957 if (srcattrfd
!= -1)
1958 (void) close(srcattrfd
);
1959 if (targattrfd
!= -1)
1960 (void) close(targattrfd
);
1961 srcattrfd
= targattrfd
= -1;
1965 /* Copy source file non default extended system attributes to target */
1966 if (target_sa_support
&& (response
!= NULL
) &&
1967 (fsetattr(targfd
, XATTR_VIEW_READWRITE
, response
)) != 0) {
1969 (void) fprintf(stderr
, gettext("%s: Failed to "
1970 "copy extended system attributes from "
1971 "%s to %s\n"), cmd
, source
, target
);
1974 nvlist_free(response
);
1976 return (error
== 0 ? 0 : 1);
1979 /* Open the source file */
1982 open_source(char *src
)
1987 if ((srcfd
= open(src
, O_RDONLY
)) == -1) {
1988 if (pflg
&& attrsilent
) {
1993 (void) fprintf(stderr
,
1994 gettext("%s: cannot open file"
1995 " %s: "), cmd
, src
);
2003 return (error
== 0 ? 0 : 1);
2006 /* Open source attribute dir, target and target attribute dir. */
2009 open_target_srctarg_attrdirs(char *src
, char *targ
)
2013 targfd
= sourcedirfd
= targetdirfd
= -1;
2015 if ((targfd
= open(targ
, O_RDONLY
)) == -1) {
2016 if (pflg
&& attrsilent
) {
2021 (void) fprintf(stderr
,
2022 gettext("%s: cannot open file"
2023 " %s: "), cmd
, targ
);
2030 if ((sourcedirfd
= openat(srcfd
, ".", O_RDONLY
|O_XATTR
)) == -1) {
2031 if (pflg
&& attrsilent
) {
2036 (void) fprintf(stderr
,
2037 gettext("%s: cannot open attribute"
2038 " directory for %s: "), cmd
, src
);
2045 if (fstat(sourcedirfd
, &attrdir
) == -1) {
2046 if (pflg
&& attrsilent
) {
2052 (void) fprintf(stderr
,
2053 gettext("%s: could not retrieve stat"
2054 " information for attribute directory"
2055 "of file %s: "), cmd
, src
);
2061 if ((targetdirfd
= openat(targfd
, ".", O_RDONLY
|O_XATTR
)) == -1) {
2062 if (pflg
&& attrsilent
) {
2067 (void) fprintf(stderr
,
2068 gettext("%s: cannot open attribute"
2069 " directory for %s: "), cmd
, targ
);
2077 return (error
== 0 ? 0 : 1);
2081 open_attrdirp(char *source
)
2087 * dup sourcedirfd for use by fdopendir().
2088 * fdopendir will take ownership of given fd and will close
2089 * it when closedir() is called.
2092 if ((tmpfd
= dup(sourcedirfd
)) == -1) {
2093 if (pflg
&& attrsilent
) {
2098 (void) fprintf(stderr
,
2100 "%s: unable to dup attribute directory"
2101 " file descriptor for %s: "), cmd
, source
);
2107 if ((srcdirp
= fdopendir(tmpfd
)) == NULL
) {
2108 if (pflg
&& attrsilent
) {
2113 (void) fprintf(stderr
,
2114 gettext("%s: failed to open attribute"
2115 " directory for %s: "), cmd
, source
);
2123 return (error
== 0 ? 0 : 1);
2126 /* Skips through ., .., and system attribute 'view' files */
2128 traverse_attrfile(struct dirent
*dp
, char *source
, char *target
, int first
)
2132 srcattrfd
= targattrfd
= -1;
2134 if ((dp
->d_name
[0] == '.' && dp
->d_name
[1] == '\0') ||
2135 (dp
->d_name
[0] == '.' && dp
->d_name
[1] == '.' &&
2136 dp
->d_name
[2] == '\0') ||
2137 (sysattr_type(dp
->d_name
) == _RO_SATTR
) ||
2138 (sysattr_type(dp
->d_name
) == _RW_SATTR
))
2141 if ((srcattrfd
= openat(sourcedirfd
, dp
->d_name
,
2144 (void) fprintf(stderr
,
2145 gettext("%s: cannot open attribute %s on"
2146 " file %s: "), cmd
, dp
->d_name
, source
);
2153 if (fstat(srcattrfd
, &s3
) < 0) {
2155 (void) fprintf(stderr
,
2156 gettext("%s: could not stat attribute"
2158 " %s: "), cmd
, dp
->d_name
, source
);
2166 (void) unlinkat(targetdirfd
, dp
->d_name
, 0);
2167 if ((targattrfd
= openat(targetdirfd
, dp
->d_name
,
2168 O_RDWR
|O_CREAT
|O_TRUNC
, s3
.st_mode
& MODEBITS
)) == -1) {
2170 (void) fprintf(stderr
,
2171 gettext("%s: could not create attribute"
2172 " %s on file %s: "), cmd
, dp
->d_name
,
2180 if ((targattrfd
= openat(targetdirfd
, dp
->d_name
,
2183 (void) fprintf(stderr
,
2184 gettext("%s: could not open attribute"
2185 " %s on file %s: "), cmd
, dp
->d_name
,
2195 if (fstat(targattrfd
, &s4
) < 0) {
2197 (void) fprintf(stderr
,
2198 gettext("%s: could not stat attribute"
2200 " %s: "), cmd
, dp
->d_name
, target
);
2208 if (srcattrfd
!= -1)
2209 (void) close(srcattrfd
);
2210 if (targattrfd
!= -1)
2211 (void) close(targattrfd
);
2212 srcattrfd
= targattrfd
= -1;
2214 return (error
== 0 ? 0 :1);
2218 rewind_attrdir(DIR * sdp
)
2222 pwdfd
= open(".", O_RDONLY
);
2223 if ((pwdfd
!= -1) && (fchdir(sourcedirfd
) == 0)) {
2225 (void) fchdir(pwdfd
);
2226 (void) close(pwdfd
);
2229 (void) fprintf(stderr
, gettext("%s: "
2230 "failed to rewind attribute dir\n"),
2239 if (srcattrfd
!= -1)
2240 (void) close(srcattrfd
);
2241 if (targattrfd
!= -1)
2242 (void) close(targattrfd
);
2243 if (sourcedirfd
!= -1)
2244 (void) close(sourcedirfd
);
2245 if (targetdirfd
!= -1)
2246 (void) close(targetdirfd
);
2247 if (srcdirp
!= NULL
) {
2248 (void) closedir(srcdirp
);
2252 (void) close(srcfd
);
2254 (void) close(targfd
);