112657Skvn/*- 212657Skvn * Copyright (c) 1988, 1993, 1994 312657Skvn * The Regents of the University of California. All rights reserved. 412657Skvn * 512657Skvn * This code is derived from software contributed to Berkeley by 612657Skvn * David Hitz of Auspex Systems Inc. 712657Skvn * 812657Skvn * Redistribution and use in source and binary forms, with or without 912657Skvn * modification, are permitted provided that the following conditions 1012657Skvn * are met: 1112657Skvn * 1. Redistributions of source code must retain the above copyright 1212657Skvn * notice, this list of conditions and the following disclaimer. 1312657Skvn * 2. Redistributions in binary form must reproduce the above copyright 1412657Skvn * notice, this list of conditions and the following disclaimer in the 1512657Skvn * documentation and/or other materials provided with the distribution. 1612657Skvn * 4. Neither the name of the University nor the names of its contributors 1712657Skvn * may be used to endorse or promote products derived from this software 1812657Skvn * without specific prior written permission. 1912657Skvn * 2012657Skvn * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2112657Skvn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2212657Skvn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2312657Skvn * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2412657Skvn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2512968Siveresov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2612968Siveresov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2712657Skvn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2812657Skvn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2912657Skvn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3012657Skvn * SUCH DAMAGE. 3112657Skvn */ 3212657Skvn 3312657Skvn#if 0 3412657Skvn#ifndef lint 3512657Skvnstatic char const copyright[] = 3612657Skvn"@(#) Copyright (c) 1988, 1993, 1994\n\ 3712657Skvn The Regents of the University of California. All rights reserved.\n"; 3812657Skvn#endif /* not lint */ 3912657Skvn 4012657Skvn#ifndef lint 4112657Skvnstatic char sccsid[] = "@(#)cp.c 8.2 (Berkeley) 4/1/94"; 4212657Skvn#endif /* not lint */ 4312657Skvn#endif 4412657Skvn#include <sys/cdefs.h> 4512657Skvn__FBSDID("$FreeBSD$"); 4612657Skvn 4712657Skvn/* 4812657Skvn * Cp copies source files to target files. 4912657Skvn * 5012657Skvn * The global PATH_T structure "to" always contains the path to the 5112657Skvn * current target file. Since fts(3) does not change directories, 5212657Skvn * this path can be either absolute or dot-relative. 5312657Skvn * 5412657Skvn * The basic algorithm is to initialize "to" and use fts(3) to traverse 5512657Skvn * the file hierarchy rooted in the argument list. A trivial case is the 5612657Skvn * case of 'cp file1 file2'. The more interesting case is the case of 5712968Siveresov * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the 5812968Siveresov * path (relative to the root of the traversal) is appended to dir (stored 5912995Siveresov * in "to") to form the final target path. 6012968Siveresov */ 6112657Skvn 6212657Skvn#include <sys/types.h> 6312657Skvn#include <sys/stat.h> 6412657Skvn 6512657Skvn#include <err.h> 6612657Skvn#include <errno.h> 6712657Skvn#include <fts.h> 6812657Skvn#include <limits.h> 6912657Skvn#include <signal.h> 7012657Skvn#include <stdio.h> 7112657Skvn#include <stdlib.h> 7212657Skvn#include <string.h> 7312657Skvn#include <unistd.h> 7412657Skvn 7512657Skvn#include "extern.h" 7612657Skvn 7713264Siveresov#define STRIP_TRAILING_SLASH(p) { \ 7812657Skvn while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \ 7912657Skvn *--(p).p_end = 0; \ 8012657Skvn} 8112657Skvn 8212657Skvnstatic char emptystring[] = ""; 8312657Skvn 8412657SkvnPATH_T to = { to.p_path, emptystring, "" }; 8512657Skvn 8612657Skvnint fflag, iflag, lflag, nflag, pflag, vflag; 8712657Skvnstatic int Rflag, rflag; 8812657Skvnvolatile sig_atomic_t info; 8912657Skvn 9012657Skvnenum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; 9112657Skvn 9212968Siveresovstatic int copy(char *[], enum op, int); 9312657Skvnstatic int mastercmp(const FTSENT * const *, const FTSENT * const *); 9412968Siveresovstatic void siginfo(int __unused); 9512657Skvn 9612657Skvnint 9712657Skvnmain(int argc, char *argv[]) 9812657Skvn{ 9912657Skvn struct stat to_stat, tmp_stat; 10012657Skvn enum op type; 10112657Skvn int Hflag, Lflag, ch, fts_options, r, have_trailing_slash; 10212657Skvn char *target; 10312657Skvn 10412657Skvn fts_options = FTS_NOCHDIR | FTS_PHYSICAL; 10512657Skvn Hflag = Lflag = 0; 10612657Skvn while ((ch = getopt(argc, argv, "HLPRafilnprvx")) != -1) 10712657Skvn switch (ch) { 10812657Skvn case 'H': 10912968Siveresov Hflag = 1; 11012657Skvn Lflag = 0; 11112657Skvn break; 11212968Siveresov case 'L': 11312657Skvn Lflag = 1; 11412657Skvn Hflag = 0; 11512657Skvn break; 11612657Skvn case 'P': 11712657Skvn Hflag = Lflag = 0; 11812657Skvn break; 11912657Skvn case 'R': 12013175Siveresov Rflag = 1; 12113175Siveresov break; 12212657Skvn case 'a': 12312657Skvn pflag = 1; 12412657Skvn Rflag = 1; 12512657Skvn Hflag = Lflag = 0; 12612657Skvn break; 12712657Skvn case 'f': 12812657Skvn fflag = 1; 12912657Skvn iflag = nflag = 0; 13012657Skvn break; 13112657Skvn case 'i': 13212657Skvn iflag = 1; 13312657Skvn fflag = nflag = 0; 13412657Skvn break; 13512657Skvn case 'l': 13612657Skvn lflag = 1; 13712657Skvn break; 13812657Skvn case 'n': 13912657Skvn nflag = 1; 14012657Skvn fflag = iflag = 0; 14112657Skvn break; 14212657Skvn case 'p': 14312657Skvn pflag = 1; 14412657Skvn break; 14512657Skvn case 'r': 14612657Skvn rflag = Lflag = 1; 14712657Skvn Hflag = 0; 14812968Siveresov break; 14912968Siveresov case 'v': 15012657Skvn vflag = 1; 15112657Skvn break; 15212657Skvn case 'x': 15312657Skvn fts_options |= FTS_XDEV; 15412657Skvn break; 15512657Skvn default: 15612657Skvn usage(); 15712657Skvn break; 15812657Skvn } 15912657Skvn argc -= optind; 16012657Skvn argv += optind; 16112657Skvn 16212657Skvn if (argc < 2) 16312657Skvn usage(); 16412657Skvn 16512968Siveresov if (Rflag && rflag) 16612968Siveresov errx(1, "the -R and -r options may not be specified together"); 16712657Skvn if (rflag) 16812657Skvn Rflag = 1; 16912657Skvn if (Rflag) { 17012968Siveresov if (Hflag) 17112968Siveresov fts_options |= FTS_COMFOLLOW; 17212657Skvn if (Lflag) { 17312657Skvn fts_options &= ~FTS_PHYSICAL; 17412657Skvn fts_options |= FTS_LOGICAL; 17512968Siveresov } 17612968Siveresov } else { 17712968Siveresov fts_options &= ~FTS_PHYSICAL; 17812657Skvn fts_options |= FTS_LOGICAL | FTS_COMFOLLOW; 17912968Siveresov } 18012657Skvn (void)signal(SIGINFO, siginfo); 18112657Skvn 18212657Skvn /* Save the target base in "to". */ 18312657Skvn target = argv[--argc]; 18412657Skvn if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path)) 18512657Skvn errx(1, "%s: name too long", target); 18612657Skvn to.p_end = to.p_path + strlen(to.p_path); 18712657Skvn if (to.p_path == to.p_end) { 18812657Skvn *to.p_end++ = '.'; 18912657Skvn *to.p_end = 0; 19012657Skvn } 19112657Skvn have_trailing_slash = (to.p_end[-1] == '/'); 19212657Skvn if (have_trailing_slash) 19312657Skvn STRIP_TRAILING_SLASH(to); 19412657Skvn to.target_end = to.p_end; 19512657Skvn 19612657Skvn /* Set end of argument list for fts(3). */ 19712657Skvn argv[argc] = NULL; 19812657Skvn 19912657Skvn /* 20012657Skvn * Cp has two distinct cases: 20112657Skvn * 20212968Siveresov * cp [-R] source target 20312968Siveresov * cp [-R] source1 ... sourceN directory 20412968Siveresov * 20512968Siveresov * In both cases, source can be either a file or a directory. 20612968Siveresov * 20712968Siveresov * In (1), the target becomes a copy of the source. That is, if the 20812968Siveresov * source is a file, the target will be a file, and likewise for 20912968Siveresov * directories. 21012657Skvn * 21112657Skvn * In (2), the real target is not directory, but "directory/source". 21212657Skvn */ 21312657Skvn r = stat(to.p_path, &to_stat); 21412657Skvn if (r == -1 && errno != ENOENT) 21512657Skvn err(1, "%s", to.p_path); 21612657Skvn if (r == -1 || !S_ISDIR(to_stat.st_mode)) { 21712657Skvn /* 21812968Siveresov * Case (1). Target is not a directory. 21912657Skvn */ 22012968Siveresov if (argc > 1) 22112968Siveresov errx(1, "%s is not a directory", to.p_path); 22212968Siveresov 22312657Skvn /* 22412657Skvn * Need to detect the case: 22512968Siveresov * cp -R dir foo 22612968Siveresov * Where dir is a directory and foo does not exist, where 22712657Skvn * we want pathname concatenations turned on but not for 22812657Skvn * the initial mkdir(). 22912995Siveresov */ 23012657Skvn if (r == -1) { 23112657Skvn if (Rflag && (Lflag || Hflag)) 23212657Skvn stat(*argv, &tmp_stat); 23312657Skvn else 23412968Siveresov lstat(*argv, &tmp_stat); 23512968Siveresov 23612657Skvn if (S_ISDIR(tmp_stat.st_mode) && Rflag) 23712657Skvn type = DIR_TO_DNE; 23812657Skvn else 23912657Skvn type = FILE_TO_FILE; 24012968Siveresov } else 24112657Skvn type = FILE_TO_FILE; 24212657Skvn 24312657Skvn if (have_trailing_slash && type == FILE_TO_FILE) { 24412968Siveresov if (r == -1) 24512968Siveresov errx(1, "directory %s does not exist", 24612968Siveresov to.p_path); 24712968Siveresov else 24812968Siveresov errx(1, "%s is not a directory", to.p_path); 24912968Siveresov } 25012968Siveresov } else 25112968Siveresov /* 25212657Skvn * Case (2). Target is a directory. 25312657Skvn */ 25412657Skvn type = FILE_TO_DIR; 25512968Siveresov 25612968Siveresov exit (copy(argv, type, fts_options)); 25712968Siveresov} 25812968Siveresov 25912968Siveresovstatic int 26012657Skvncopy(char *argv[], enum op type, int fts_options) 26112968Siveresov{ 26212968Siveresov struct stat to_stat; 26312968Siveresov FTS *ftsp; 26412968Siveresov FTSENT *curr; 26512657Skvn int base = 0, dne, badcp, rval; 26612657Skvn size_t nlen; 26712657Skvn char *p, *target_mid; 26812657Skvn mode_t mask, mode; 26912657Skvn 27012657Skvn /* 27112657Skvn * Keep an inverted copy of the umask, for use in correcting 27212968Siveresov * permissions on created directories when not using -p. 27312657Skvn */ 27412657Skvn mask = ~umask(0777); 27512657Skvn umask(~mask); 27612657Skvn 27712968Siveresov if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL) 27812657Skvn err(1, "fts_open"); 27912657Skvn for (badcp = rval = 0; (curr = fts_read(ftsp)) != NULL; badcp = 0) { 28012657Skvn switch (curr->fts_info) { 28112657Skvn case FTS_NS: 28212657Skvn case FTS_DNR: 28312657Skvn case FTS_ERR: 28412657Skvn warnx("%s: %s", 28512657Skvn curr->fts_path, strerror(curr->fts_errno)); 28612657Skvn badcp = rval = 1; 28712657Skvn continue; 28812657Skvn case FTS_DC: /* Warn, continue. */ 28912657Skvn warnx("%s: directory causes a cycle", curr->fts_path); 29012657Skvn badcp = rval = 1; 29112968Siveresov continue; 29212968Siveresov default: 29313175Siveresov ; 29412657Skvn } 29512968Siveresov 29612657Skvn /* 29712657Skvn * If we are in case (2) or (3) above, we need to append the 29812657Skvn * source name to the target name. 29912657Skvn */ 30012968Siveresov if (type != FILE_TO_FILE) { 30112968Siveresov /* 30213190Siveresov * Need to remember the roots of traversals to create 30313190Siveresov * correct pathnames. If there's a directory being 30412968Siveresov * copied to a non-existent directory, e.g. 30512657Skvn * cp -R a/dir noexist 30612657Skvn * the resulting path name should be noexist/foo, not 30712657Skvn * noexist/dir/foo (where foo is a file in dir), which 30812657Skvn * is the case where the target exists. 30912968Siveresov * 31012968Siveresov * Also, check for "..". This is for correct path 31112968Siveresov * concatenation for paths ending in "..", e.g. 31212995Siveresov * cp -R .. /tmp 31312657Skvn * Paths ending in ".." are changed to ".". This is 31412657Skvn * tricky, but seems the easiest way to fix the problem. 31512968Siveresov * 31612968Siveresov * XXX 31712657Skvn * Since the first level MUST be FTS_ROOTLEVEL, base 31812657Skvn * is always initialized. 31912657Skvn */ 32012657Skvn if (curr->fts_level == FTS_ROOTLEVEL) { 32112657Skvn if (type != DIR_TO_DNE) { 32212657Skvn p = strrchr(curr->fts_path, '/'); 32312657Skvn base = (p == NULL) ? 0 : 32412657Skvn (int)(p - curr->fts_path + 1); 32512657Skvn 32612657Skvn if (!strcmp(&curr->fts_path[base], 32712657Skvn "..")) 32812968Siveresov base += 1; 32912968Siveresov } else 33012968Siveresov base = curr->fts_pathlen; 33112968Siveresov } 33212657Skvn 33312657Skvn p = &curr->fts_path[base]; 33412657Skvn nlen = curr->fts_pathlen - base; 33512968Siveresov target_mid = to.target_end; 33612657Skvn if (*p != '/' && target_mid[-1] != '/') 33712657Skvn *target_mid++ = '/'; 33812657Skvn *target_mid = 0; 33912995Siveresov if (target_mid - to.p_path + nlen >= PATH_MAX) { 34012657Skvn warnx("%s%s: name too long (not copied)", 34112657Skvn to.p_path, p); 34212657Skvn badcp = rval = 1; 34312657Skvn continue; 34412657Skvn } 34512995Siveresov (void)strncat(target_mid, p, nlen); 34612657Skvn to.p_end = target_mid + nlen; 34712657Skvn *to.p_end = 0; 34812657Skvn STRIP_TRAILING_SLASH(to); 34912657Skvn } 35012657Skvn 35112657Skvn if (curr->fts_info == FTS_DP) { 35212995Siveresov /* 35312657Skvn * We are nearly finished with this directory. If we 35412657Skvn * didn't actually copy it, or otherwise don't need to 35512657Skvn * change its attributes, then we are done. 35612657Skvn */ 35712968Siveresov if (!curr->fts_number) 35812968Siveresov continue; 35912968Siveresov /* 36012657Skvn * If -p is in effect, set all the attributes. 36112657Skvn * Otherwise, set the correct permissions, limited 36212657Skvn * by the umask. Optimise by avoiding a chmod() 36312657Skvn * if possible (which is usually the case if we 36412968Siveresov * made the directory). Note that mkdir() does not 36512657Skvn * honour setuid, setgid and sticky bits, but we 36612657Skvn * normally want to preserve them on directories. 36712657Skvn */ 36812657Skvn if (pflag) { 36912657Skvn if (setfile(curr->fts_statp, -1)) 37012657Skvn rval = 1; 37112657Skvn if (preserve_dir_acls(curr->fts_statp, 37212657Skvn curr->fts_accpath, to.p_path) != 0) 37312657Skvn rval = 1; 37412657Skvn } else { 37512968Siveresov mode = curr->fts_statp->st_mode; 37612657Skvn if ((mode & (S_ISUID | S_ISGID | S_ISTXT)) || 37712657Skvn ((mode | S_IRWXU) & mask) != (mode & mask)) 37812968Siveresov if (chmod(to.p_path, mode & mask) != 0){ 37912968Siveresov warn("chmod: %s", to.p_path); 38012968Siveresov rval = 1; 38112968Siveresov } 38212968Siveresov } 38312968Siveresov continue; 38412657Skvn } 38512657Skvn 38612657Skvn /* Not an error but need to remember it happened */ 38712657Skvn if (stat(to.p_path, &to_stat) == -1) 38812657Skvn dne = 1; 38912657Skvn else { 39012657Skvn if (to_stat.st_dev == curr->fts_statp->st_dev && 39112657Skvn to_stat.st_ino == curr->fts_statp->st_ino) { 39212657Skvn warnx("%s and %s are identical (not copied).", 39312657Skvn to.p_path, curr->fts_path); 39412657Skvn badcp = rval = 1; 39512657Skvn if (S_ISDIR(curr->fts_statp->st_mode)) 39612657Skvn (void)fts_set(ftsp, curr, FTS_SKIP); 39712657Skvn continue; 39812657Skvn } 39912657Skvn if (!S_ISDIR(curr->fts_statp->st_mode) && 40012968Siveresov S_ISDIR(to_stat.st_mode)) { 40112995Siveresov warnx("cannot overwrite directory %s with " 40212657Skvn "non-directory %s", 40312657Skvn to.p_path, curr->fts_path); 40412657Skvn badcp = rval = 1; 40512657Skvn continue; 40612657Skvn } 40712657Skvn dne = 0; 40812657Skvn } 40912657Skvn 41012657Skvn switch (curr->fts_statp->st_mode & S_IFMT) { 41112657Skvn case S_IFLNK: 41212968Siveresov /* Catch special case of a non-dangling symlink */ 41312657Skvn if ((fts_options & FTS_LOGICAL) || 41412657Skvn ((fts_options & FTS_COMFOLLOW) && 41512657Skvn curr->fts_level == 0)) { 41612657Skvn if (copy_file(curr, dne)) 41712657Skvn badcp = rval = 1; 41812657Skvn } else { 41913190Siveresov if (copy_link(curr, !dne)) 42013133Siveresov badcp = rval = 1; 42113133Siveresov } 42212657Skvn break; 42312657Skvn case S_IFDIR: 42412995Siveresov if (!Rflag) { 42512657Skvn warnx("%s is a directory (not copied).", 42612657Skvn curr->fts_path); 42712657Skvn (void)fts_set(ftsp, curr, FTS_SKIP); 42812657Skvn badcp = rval = 1; 42912657Skvn break; 43012657Skvn } 43112657Skvn /* 43212657Skvn * If the directory doesn't exist, create the new 43312657Skvn * one with the from file mode plus owner RWX bits, 43412657Skvn * modified by the umask. Trade-off between being 43512657Skvn * able to write the directory (if from directory is 43612657Skvn * 555) and not causing a permissions race. If the 43712657Skvn * umask blocks owner writes, we fail.. 43812657Skvn */ 43912657Skvn if (dne) { 44012657Skvn if (mkdir(to.p_path, 44112657Skvn curr->fts_statp->st_mode | S_IRWXU) < 0) 44212657Skvn err(1, "%s", to.p_path); 44312968Siveresov } else if (!S_ISDIR(to_stat.st_mode)) { 44412968Siveresov errno = ENOTDIR; 44512657Skvn err(1, "%s", to.p_path); 44612657Skvn } 44712968Siveresov /* 44812657Skvn * Arrange to correct directory attributes later 44912657Skvn * (in the post-order phase) if this is a new 45012657Skvn * directory, or if the -p flag is in effect. 45112968Siveresov */ 45212657Skvn curr->fts_number = pflag || dne; 45312657Skvn break; 45412657Skvn case S_IFBLK: 45512657Skvn case S_IFCHR: 45612657Skvn if (Rflag) { 45712657Skvn if (copy_special(curr->fts_statp, !dne)) 45812657Skvn badcp = rval = 1; 45912657Skvn } else { 46012968Siveresov if (copy_file(curr, dne)) 46112968Siveresov badcp = rval = 1; 46212657Skvn } 46312968Siveresov break; 46412657Skvn case S_IFSOCK: 46512657Skvn warnx("%s is a socket (not copied).", 46612657Skvn curr->fts_path); 46712657Skvn break; 46812657Skvn case S_IFIFO: 46912968Siveresov if (Rflag) { 47012657Skvn if (copy_fifo(curr->fts_statp, !dne)) 47112657Skvn badcp = rval = 1; 47212657Skvn } else { 47313083Skvn if (copy_file(curr, dne)) 47412657Skvn badcp = rval = 1; 47512968Siveresov } 47612968Siveresov break; 47712657Skvn default: 47812657Skvn if (copy_file(curr, dne)) 47912657Skvn badcp = rval = 1; 48012968Siveresov break; 48112968Siveresov } 48212657Skvn if (vflag && !badcp) 48312657Skvn (void)printf("%s -> %s\n", curr->fts_path, to.p_path); 48412657Skvn } 48512968Siveresov if (errno) 48612657Skvn err(1, "fts_read"); 48712657Skvn fts_close(ftsp); 48812657Skvn return (rval); 48912657Skvn} 49012657Skvn 49112657Skvn/* 49212657Skvn * mastercmp -- 49312657Skvn * The comparison function for the copy order. The order is to copy 49412657Skvn * non-directory files before directory files. The reason for this 49512657Skvn * is because files tend to be in the same cylinder group as their 49612657Skvn * parent directory, whereas directories tend not to be. Copying the 49712657Skvn * files first reduces seeking. 49812657Skvn */ 49912657Skvnstatic int 50012968Siveresovmastercmp(const FTSENT * const *a, const FTSENT * const *b) 50112968Siveresov{ 50212657Skvn int a_info, b_info; 50312657Skvn 50412657Skvn a_info = (*a)->fts_info; 50512657Skvn if (a_info == FTS_ERR || a_info == FTS_NS || a_info == FTS_DNR) 50612657Skvn return (0); 50712657Skvn b_info = (*b)->fts_info; 50812657Skvn if (b_info == FTS_ERR || b_info == FTS_NS || b_info == FTS_DNR) 50912968Siveresov return (0); 51012657Skvn if (a_info == FTS_D) 51112657Skvn return (-1); 51212657Skvn if (b_info == FTS_D) 51312657Skvn return (1); 51412657Skvn return (0); 51512968Siveresov} 51612657Skvn 51712657Skvnstatic void 51812657Skvnsiginfo(int sig __unused) 51912968Siveresov{ 52012657Skvn 52112968Siveresov info = 1; 52212657Skvn} 52312968Siveresov