1139969Simp/*- 21556Srgrimes * Copyright (c) 1988, 1993, 1994 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * David Hitz of Auspex Systems Inc. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 4. Neither the name of the University nor the names of its contributors 171556Srgrimes * may be used to endorse or promote products derived from this software 181556Srgrimes * without specific prior written permission. 191556Srgrimes * 201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301556Srgrimes * SUCH DAMAGE. 311556Srgrimes */ 321556Srgrimes 33114433Sobrien#if 0 341556Srgrimes#ifndef lint 3520412Sstevestatic char const copyright[] = 361556Srgrimes"@(#) Copyright (c) 1988, 1993, 1994\n\ 371556Srgrimes The Regents of the University of California. All rights reserved.\n"; 381556Srgrimes#endif /* not lint */ 391556Srgrimes 401556Srgrimes#ifndef lint 4136003Scharnierstatic char sccsid[] = "@(#)cp.c 8.2 (Berkeley) 4/1/94"; 42114433Sobrien#endif /* not lint */ 4335773Scharnier#endif 4499109Sobrien#include <sys/cdefs.h> 4599109Sobrien__FBSDID("$FreeBSD$"); 461556Srgrimes 471556Srgrimes/* 481556Srgrimes * Cp copies source files to target files. 498855Srgrimes * 501556Srgrimes * The global PATH_T structure "to" always contains the path to the 511556Srgrimes * current target file. Since fts(3) does not change directories, 5220412Ssteve * this path can be either absolute or dot-relative. 538855Srgrimes * 541556Srgrimes * The basic algorithm is to initialize "to" and use fts(3) to traverse 551556Srgrimes * the file hierarchy rooted in the argument list. A trivial case is the 561556Srgrimes * case of 'cp file1 file2'. The more interesting case is the case of 571556Srgrimes * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the 581556Srgrimes * path (relative to the root of the traversal) is appended to dir (stored 591556Srgrimes * in "to") to form the final target path. 601556Srgrimes */ 611556Srgrimes 62113431Sbde#include <sys/types.h> 631556Srgrimes#include <sys/stat.h> 641556Srgrimes 651556Srgrimes#include <err.h> 661556Srgrimes#include <errno.h> 671556Srgrimes#include <fts.h> 6876693Simp#include <limits.h> 69113431Sbde#include <signal.h> 7050381Smharo#include <stdio.h> 7178469Sdes#include <stdlib.h> 721556Srgrimes#include <string.h> 731556Srgrimes#include <unistd.h> 741556Srgrimes 751556Srgrimes#include "extern.h" 761556Srgrimes 771556Srgrimes#define STRIP_TRAILING_SLASH(p) { \ 78291774Sbdrewery while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \ 79291774Sbdrewery *--(p).p_end = 0; \ 801556Srgrimes} 811556Srgrimes 8291087Smarkmstatic char emptystring[] = ""; 831556Srgrimes 8491087SmarkmPATH_T to = { to.p_path, emptystring, "" }; 851556Srgrimes 86291774Sbdreweryint fflag, iflag, lflag, nflag, pflag, sflag, vflag; 87100538Sjohanstatic int Rflag, rflag; 88113218Smdoddvolatile sig_atomic_t info; 89113209Smdodd 901556Srgrimesenum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; 911556Srgrimes 9299363Smarkmstatic int copy(char *[], enum op, int); 93113430Sbdestatic void siginfo(int __unused); 941556Srgrimes 951556Srgrimesint 9690107Simpmain(int argc, char *argv[]) 971556Srgrimes{ 981556Srgrimes struct stat to_stat, tmp_stat; 991556Srgrimes enum op type; 100245535Seadler int Hflag, Lflag, ch, fts_options, r, have_trailing_slash; 10196809Sache char *target; 1021556Srgrimes 103202461Sgavin fts_options = FTS_NOCHDIR | FTS_PHYSICAL; 104245535Seadler Hflag = Lflag = 0; 105291774Sbdrewery while ((ch = getopt(argc, argv, "HLPRafilnprsvx")) != -1) 1061556Srgrimes switch (ch) { 1071556Srgrimes case 'H': 1081556Srgrimes Hflag = 1; 109245535Seadler Lflag = 0; 1101556Srgrimes break; 1111556Srgrimes case 'L': 1121556Srgrimes Lflag = 1; 113245535Seadler Hflag = 0; 1141556Srgrimes break; 1151556Srgrimes case 'P': 1161556Srgrimes Hflag = Lflag = 0; 1171556Srgrimes break; 1181556Srgrimes case 'R': 1191556Srgrimes Rflag = 1; 1201556Srgrimes break; 121177036Sjhb case 'a': 122177036Sjhb pflag = 1; 123177036Sjhb Rflag = 1; 124177036Sjhb Hflag = Lflag = 0; 125177036Sjhb break; 1261556Srgrimes case 'f': 12714416Swosch fflag = 1; 128100538Sjohan iflag = nflag = 0; 1291556Srgrimes break; 1301556Srgrimes case 'i': 13114416Swosch iflag = 1; 132100538Sjohan fflag = nflag = 0; 1331556Srgrimes break; 134162763Sru case 'l': 135162763Sru lflag = 1; 136162763Sru break; 137100538Sjohan case 'n': 138100538Sjohan nflag = 1; 139100538Sjohan fflag = iflag = 0; 140100538Sjohan break; 1411556Srgrimes case 'p': 1421556Srgrimes pflag = 1; 1431556Srgrimes break; 1441556Srgrimes case 'r': 145163109Strhodes rflag = Lflag = 1; 146245535Seadler Hflag = 0; 1471556Srgrimes break; 148291774Sbdrewery case 's': 149291774Sbdrewery sflag = 1; 150291774Sbdrewery break; 15150381Smharo case 'v': 15250381Smharo vflag = 1; 15350381Smharo break; 154202461Sgavin case 'x': 155202461Sgavin fts_options |= FTS_XDEV; 156202461Sgavin break; 1571556Srgrimes default: 1581556Srgrimes usage(); 1591556Srgrimes break; 1601556Srgrimes } 1611556Srgrimes argc -= optind; 1621556Srgrimes argv += optind; 1631556Srgrimes 1641556Srgrimes if (argc < 2) 1651556Srgrimes usage(); 1661556Srgrimes 167163233Strhodes if (Rflag && rflag) 168163233Strhodes errx(1, "the -R and -r options may not be specified together"); 169291774Sbdrewery if (lflag && sflag) 170291774Sbdrewery errx(1, "the -l and -s options may not be specified together"); 171163233Strhodes if (rflag) 172163109Strhodes Rflag = 1; 1731556Srgrimes if (Rflag) { 1741556Srgrimes if (Hflag) 1751556Srgrimes fts_options |= FTS_COMFOLLOW; 1761556Srgrimes if (Lflag) { 1771556Srgrimes fts_options &= ~FTS_PHYSICAL; 1781556Srgrimes fts_options |= FTS_LOGICAL; 1791556Srgrimes } 1801556Srgrimes } else { 1811556Srgrimes fts_options &= ~FTS_PHYSICAL; 18298171Stjr fts_options |= FTS_LOGICAL | FTS_COMFOLLOW; 1831556Srgrimes } 184113209Smdodd (void)signal(SIGINFO, siginfo); 1851556Srgrimes 1861556Srgrimes /* Save the target base in "to". */ 1871556Srgrimes target = argv[--argc]; 18876693Simp if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path)) 1891556Srgrimes errx(1, "%s: name too long", target); 1901556Srgrimes to.p_end = to.p_path + strlen(to.p_path); 191291774Sbdrewery if (to.p_path == to.p_end) { 1921556Srgrimes *to.p_end++ = '.'; 1931556Srgrimes *to.p_end = 0; 1941556Srgrimes } 19596809Sache have_trailing_slash = (to.p_end[-1] == '/'); 19696809Sache if (have_trailing_slash) 19796809Sache STRIP_TRAILING_SLASH(to); 1981556Srgrimes to.target_end = to.p_end; 1991556Srgrimes 2001556Srgrimes /* Set end of argument list for fts(3). */ 2018855Srgrimes argv[argc] = NULL; 2028855Srgrimes 2031556Srgrimes /* 2041556Srgrimes * Cp has two distinct cases: 2051556Srgrimes * 2061556Srgrimes * cp [-R] source target 2071556Srgrimes * cp [-R] source1 ... sourceN directory 2081556Srgrimes * 2091556Srgrimes * In both cases, source can be either a file or a directory. 2101556Srgrimes * 2111556Srgrimes * In (1), the target becomes a copy of the source. That is, if the 2121556Srgrimes * source is a file, the target will be a file, and likewise for 2131556Srgrimes * directories. 2141556Srgrimes * 2151556Srgrimes * In (2), the real target is not directory, but "directory/source". 2161556Srgrimes */ 2171556Srgrimes r = stat(to.p_path, &to_stat); 2181556Srgrimes if (r == -1 && errno != ENOENT) 2191556Srgrimes err(1, "%s", to.p_path); 2201556Srgrimes if (r == -1 || !S_ISDIR(to_stat.st_mode)) { 2211556Srgrimes /* 2221556Srgrimes * Case (1). Target is not a directory. 2238855Srgrimes */ 224174912Sedwin if (argc > 1) 225174912Sedwin errx(1, "%s is not a directory", to.p_path); 226174912Sedwin 2271556Srgrimes /* 2281556Srgrimes * Need to detect the case: 2291556Srgrimes * cp -R dir foo 2301556Srgrimes * Where dir is a directory and foo does not exist, where 2311556Srgrimes * we want pathname concatenations turned on but not for 2321556Srgrimes * the initial mkdir(). 2331556Srgrimes */ 2341556Srgrimes if (r == -1) { 235163109Strhodes if (Rflag && (Lflag || Hflag)) 2361556Srgrimes stat(*argv, &tmp_stat); 2371556Srgrimes else 2381556Srgrimes lstat(*argv, &tmp_stat); 2398855Srgrimes 240163233Strhodes if (S_ISDIR(tmp_stat.st_mode) && Rflag) 2411556Srgrimes type = DIR_TO_DNE; 2421556Srgrimes else 2431556Srgrimes type = FILE_TO_FILE; 2441556Srgrimes } else 2451556Srgrimes type = FILE_TO_FILE; 24696808Sache 24796808Sache if (have_trailing_slash && type == FILE_TO_FILE) { 248291774Sbdrewery if (r == -1) { 24996808Sache errx(1, "directory %s does not exist", 250291774Sbdrewery to.p_path); 251291774Sbdrewery } else 25296808Sache errx(1, "%s is not a directory", to.p_path); 25396808Sache } 2541556Srgrimes } else 2551556Srgrimes /* 2561556Srgrimes * Case (2). Target is a directory. 2571556Srgrimes */ 2581556Srgrimes type = FILE_TO_DIR; 2591556Srgrimes 2601556Srgrimes exit (copy(argv, type, fts_options)); 2611556Srgrimes} 2621556Srgrimes 263105395Smarkmstatic int 26490107Simpcopy(char *argv[], enum op type, int fts_options) 2651556Srgrimes{ 2661556Srgrimes struct stat to_stat; 2671556Srgrimes FTS *ftsp; 2681556Srgrimes FTSENT *curr; 26991087Smarkm int base = 0, dne, badcp, rval; 27091087Smarkm size_t nlen; 2715292Sbde char *p, *target_mid; 27288439Smckay mode_t mask, mode; 2731556Srgrimes 27487655Smckay /* 27587655Smckay * Keep an inverted copy of the umask, for use in correcting 27687655Smckay * permissions on created directories when not using -p. 27787655Smckay */ 27887655Smckay mask = ~umask(0777); 27987655Smckay umask(~mask); 28087655Smckay 281282890Sjilles if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL) 28299744Sdillon err(1, "fts_open"); 28353819Smharo for (badcp = rval = 0; (curr = fts_read(ftsp)) != NULL; badcp = 0) { 2841556Srgrimes switch (curr->fts_info) { 2851556Srgrimes case FTS_NS: 28636812Sdt case FTS_DNR: 2871556Srgrimes case FTS_ERR: 2881556Srgrimes warnx("%s: %s", 2891556Srgrimes curr->fts_path, strerror(curr->fts_errno)); 29053819Smharo badcp = rval = 1; 2911556Srgrimes continue; 2921556Srgrimes case FTS_DC: /* Warn, continue. */ 2931556Srgrimes warnx("%s: directory causes a cycle", curr->fts_path); 29453819Smharo badcp = rval = 1; 2951556Srgrimes continue; 29691087Smarkm default: 29796371Salfred ; 2981556Srgrimes } 2991556Srgrimes 3001556Srgrimes /* 3018855Srgrimes * If we are in case (2) or (3) above, we need to append the 302291774Sbdrewery * source name to the target name. 303291774Sbdrewery */ 3041556Srgrimes if (type != FILE_TO_FILE) { 3051556Srgrimes /* 3061556Srgrimes * Need to remember the roots of traversals to create 3071556Srgrimes * correct pathnames. If there's a directory being 3081556Srgrimes * copied to a non-existent directory, e.g. 3091556Srgrimes * cp -R a/dir noexist 3101556Srgrimes * the resulting path name should be noexist/foo, not 3111556Srgrimes * noexist/dir/foo (where foo is a file in dir), which 3121556Srgrimes * is the case where the target exists. 3131556Srgrimes * 3141556Srgrimes * Also, check for "..". This is for correct path 31546684Skris * concatenation for paths ending in "..", e.g. 3161556Srgrimes * cp -R .. /tmp 3171556Srgrimes * Paths ending in ".." are changed to ".". This is 3181556Srgrimes * tricky, but seems the easiest way to fix the problem. 3191556Srgrimes * 3201556Srgrimes * XXX 3211556Srgrimes * Since the first level MUST be FTS_ROOTLEVEL, base 3221556Srgrimes * is always initialized. 3231556Srgrimes */ 32446073Simp if (curr->fts_level == FTS_ROOTLEVEL) { 3251556Srgrimes if (type != DIR_TO_DNE) { 3261556Srgrimes p = strrchr(curr->fts_path, '/'); 3278855Srgrimes base = (p == NULL) ? 0 : 3281556Srgrimes (int)(p - curr->fts_path + 1); 3291556Srgrimes 3308855Srgrimes if (!strcmp(&curr->fts_path[base], 3311556Srgrimes "..")) 3321556Srgrimes base += 1; 3331556Srgrimes } else 3341556Srgrimes base = curr->fts_pathlen; 33546073Simp } 3361556Srgrimes 3371556Srgrimes p = &curr->fts_path[base]; 3381556Srgrimes nlen = curr->fts_pathlen - base; 3395292Sbde target_mid = to.target_end; 3405292Sbde if (*p != '/' && target_mid[-1] != '/') 3415292Sbde *target_mid++ = '/'; 3425292Sbde *target_mid = 0; 34376693Simp if (target_mid - to.p_path + nlen >= PATH_MAX) { 3448855Srgrimes warnx("%s%s: name too long (not copied)", 3455292Sbde to.p_path, p); 34653819Smharo badcp = rval = 1; 3475292Sbde continue; 3485292Sbde } 3495292Sbde (void)strncat(target_mid, p, nlen); 3505292Sbde to.p_end = target_mid + nlen; 3511556Srgrimes *to.p_end = 0; 3521556Srgrimes STRIP_TRAILING_SLASH(to); 3531556Srgrimes } 3541556Srgrimes 35587655Smckay if (curr->fts_info == FTS_DP) { 35687655Smckay /* 35788755Smckay * We are nearly finished with this directory. If we 35888755Smckay * didn't actually copy it, or otherwise don't need to 35988755Smckay * change its attributes, then we are done. 36087655Smckay */ 36188439Smckay if (!curr->fts_number) 36288439Smckay continue; 36388439Smckay /* 36488439Smckay * If -p is in effect, set all the attributes. 36588439Smckay * Otherwise, set the correct permissions, limited 36688755Smckay * by the umask. Optimise by avoiding a chmod() 36788755Smckay * if possible (which is usually the case if we 36888755Smckay * made the directory). Note that mkdir() does not 36988755Smckay * honour setuid, setgid and sticky bits, but we 37088755Smckay * normally want to preserve them on directories. 37188439Smckay */ 372103801Smckay if (pflag) { 373117065Sjmg if (setfile(curr->fts_statp, -1)) 374149790Scsjp rval = 1; 375149790Scsjp if (preserve_dir_acls(curr->fts_statp, 376149790Scsjp curr->fts_accpath, to.p_path) != 0) 377149790Scsjp rval = 1; 378103801Smckay } else { 37988439Smckay mode = curr->fts_statp->st_mode; 38088439Smckay if ((mode & (S_ISUID | S_ISGID | S_ISTXT)) || 38188439Smckay ((mode | S_IRWXU) & mask) != (mode & mask)) 382291774Sbdrewery if (chmod(to.p_path, mode & mask) != 383291774Sbdrewery 0) { 38488439Smckay warn("chmod: %s", to.p_path); 38588439Smckay rval = 1; 38688439Smckay } 38787655Smckay } 38887655Smckay continue; 38987655Smckay } 39087655Smckay 391291774Sbdrewery /* Not an error but need to remember it happened. */ 3921556Srgrimes if (stat(to.p_path, &to_stat) == -1) 3931556Srgrimes dne = 1; 3941556Srgrimes else { 3951556Srgrimes if (to_stat.st_dev == curr->fts_statp->st_dev && 3961556Srgrimes to_stat.st_ino == curr->fts_statp->st_ino) { 3971556Srgrimes warnx("%s and %s are identical (not copied).", 3981556Srgrimes to.p_path, curr->fts_path); 39953819Smharo badcp = rval = 1; 4001556Srgrimes if (S_ISDIR(curr->fts_statp->st_mode)) 4011556Srgrimes (void)fts_set(ftsp, curr, FTS_SKIP); 4021556Srgrimes continue; 4031556Srgrimes } 40420412Ssteve if (!S_ISDIR(curr->fts_statp->st_mode) && 40520412Ssteve S_ISDIR(to_stat.st_mode)) { 40691087Smarkm warnx("cannot overwrite directory %s with " 40791087Smarkm "non-directory %s", 40820412Ssteve to.p_path, curr->fts_path); 40953819Smharo badcp = rval = 1; 41020412Ssteve continue; 41120412Ssteve } 4121556Srgrimes dne = 0; 4131556Srgrimes } 4141556Srgrimes 4151556Srgrimes switch (curr->fts_statp->st_mode & S_IFMT) { 4161556Srgrimes case S_IFLNK: 417291774Sbdrewery /* Catch special case of a non-dangling symlink. */ 41898171Stjr if ((fts_options & FTS_LOGICAL) || 41998171Stjr ((fts_options & FTS_COMFOLLOW) && 42098171Stjr curr->fts_level == 0)) { 42198171Stjr if (copy_file(curr, dne)) 42298171Stjr badcp = rval = 1; 42398171Stjr } else { 42498171Stjr if (copy_link(curr, !dne)) 42598171Stjr badcp = rval = 1; 42698171Stjr } 4271556Srgrimes break; 4281556Srgrimes case S_IFDIR: 429163109Strhodes if (!Rflag) { 4301556Srgrimes warnx("%s is a directory (not copied).", 4311556Srgrimes curr->fts_path); 4321556Srgrimes (void)fts_set(ftsp, curr, FTS_SKIP); 43353819Smharo badcp = rval = 1; 4341556Srgrimes break; 4351556Srgrimes } 4361556Srgrimes /* 4371556Srgrimes * If the directory doesn't exist, create the new 4381556Srgrimes * one with the from file mode plus owner RWX bits, 4391556Srgrimes * modified by the umask. Trade-off between being 4401556Srgrimes * able to write the directory (if from directory is 4411556Srgrimes * 555) and not causing a permissions race. If the 442291774Sbdrewery * umask blocks owner writes, we fail. 4431556Srgrimes */ 4441556Srgrimes if (dne) { 4458855Srgrimes if (mkdir(to.p_path, 4461556Srgrimes curr->fts_statp->st_mode | S_IRWXU) < 0) 4471556Srgrimes err(1, "%s", to.p_path); 4481556Srgrimes } else if (!S_ISDIR(to_stat.st_mode)) { 4491556Srgrimes errno = ENOTDIR; 4505879Sdg err(1, "%s", to.p_path); 4511556Srgrimes } 4521556Srgrimes /* 45388439Smckay * Arrange to correct directory attributes later 45487655Smckay * (in the post-order phase) if this is a new 45588439Smckay * directory, or if the -p flag is in effect. 4561556Srgrimes */ 45788439Smckay curr->fts_number = pflag || dne; 4581556Srgrimes break; 4591556Srgrimes case S_IFBLK: 4601556Srgrimes case S_IFCHR: 461291774Sbdrewery if (Rflag && !sflag) { 4621556Srgrimes if (copy_special(curr->fts_statp, !dne)) 46353819Smharo badcp = rval = 1; 4647572Sbde } else { 4651556Srgrimes if (copy_file(curr, dne)) 46653819Smharo badcp = rval = 1; 4677572Sbde } 4681556Srgrimes break; 469161586Sjulian case S_IFSOCK: 470161586Sjulian warnx("%s is a socket (not copied).", 471291774Sbdrewery curr->fts_path); 472208821Strasz break; 4731556Srgrimes case S_IFIFO: 474291774Sbdrewery if (Rflag && !sflag) { 4751556Srgrimes if (copy_fifo(curr->fts_statp, !dne)) 47653819Smharo badcp = rval = 1; 4777572Sbde } else { 4781556Srgrimes if (copy_file(curr, dne)) 47953819Smharo badcp = rval = 1; 4807572Sbde } 4811556Srgrimes break; 4821556Srgrimes default: 4831556Srgrimes if (copy_file(curr, dne)) 48453819Smharo badcp = rval = 1; 4851556Srgrimes break; 4861556Srgrimes } 48753819Smharo if (vflag && !badcp) 48850543Smharo (void)printf("%s -> %s\n", curr->fts_path, to.p_path); 4891556Srgrimes } 4901556Srgrimes if (errno) 4911556Srgrimes err(1, "fts_read"); 492160098Smaxim fts_close(ftsp); 4931556Srgrimes return (rval); 4941556Srgrimes} 4951556Srgrimes 496113209Smdoddstatic void 497113430Sbdesiginfo(int sig __unused) 498113209Smdodd{ 499113209Smdodd 500113209Smdodd info = 1; 501113209Smdodd} 502