diff --git a/bin/cp/cp.1 b/bin/cp/cp.1 index 169f350cc0bc..9bbd9d614b6c 100644 --- a/bin/cp/cp.1 +++ b/bin/cp/cp.1 @@ -32,7 +32,7 @@ .\" @(#)cp.1 8.3 (Berkeley) 4/18/94 .\" $FreeBSD$ .\" -.Dd March 15, 2013 +.Dd June 6, 2015 .Dt CP 1 .Os .Sh NAME @@ -45,7 +45,7 @@ .Op Fl H | Fl L | Fl P .Oc .Op Fl f | i | n -.Op Fl alpvx +.Op Fl alpsvx .Ar source_file target_file .Nm .Oo @@ -53,7 +53,7 @@ .Op Fl H | Fl L | Fl P .Oc .Op Fl f | i | n -.Op Fl alpvx +.Op Fl alpsvx .Ar source_file ... target_directory .Sh DESCRIPTION In the first synopsis form, the @@ -179,6 +179,8 @@ If the source file has both its set-user-ID and set-group-ID bits on, and either the user ID or group ID cannot be preserved, neither the set-user-ID nor set-group-ID bits are preserved in the copy's permissions. +.It Fl s +Create symbolic links to regular files in a hierarchy instead of copying. .It Fl v Cause .Nm @@ -298,7 +300,10 @@ differ as they copy special files as normal files while recreating a hierarchy. .Pp The -.Fl v +.Fl l, +.Fl s, +.Fl v, +.Fl x and .Fl n options are non-standard and their use in scripts is not recommended. diff --git a/bin/cp/cp.c b/bin/cp/cp.c index 2ad5f4a43414..18eb52e035f2 100644 --- a/bin/cp/cp.c +++ b/bin/cp/cp.c @@ -83,7 +83,7 @@ static char emptystring[] = ""; PATH_T to = { to.p_path, emptystring, "" }; -int fflag, iflag, lflag, nflag, pflag, vflag; +int fflag, iflag, lflag, nflag, pflag, sflag, vflag; static int Rflag, rflag; volatile sig_atomic_t info; @@ -102,7 +102,7 @@ main(int argc, char *argv[]) fts_options = FTS_NOCHDIR | FTS_PHYSICAL; Hflag = Lflag = 0; - while ((ch = getopt(argc, argv, "HLPRafilnprvx")) != -1) + while ((ch = getopt(argc, argv, "HLPRafilnprsvx")) != -1) switch (ch) { case 'H': Hflag = 1; @@ -145,6 +145,9 @@ main(int argc, char *argv[]) rflag = Lflag = 1; Hflag = 0; break; + case 's': + sflag = 1; + break; case 'v': vflag = 1; break; @@ -163,6 +166,8 @@ main(int argc, char *argv[]) if (Rflag && rflag) errx(1, "the -R and -r options may not be specified together"); + if (lflag && sflag) + errx(1, "the -l and -s options may not be specified together"); if (rflag) Rflag = 1; if (Rflag) { @@ -452,7 +457,7 @@ copy(char *argv[], enum op type, int fts_options) break; case S_IFBLK: case S_IFCHR: - if (Rflag) { + if (Rflag && !sflag) { if (copy_special(curr->fts_statp, !dne)) badcp = rval = 1; } else { @@ -465,7 +470,7 @@ copy(char *argv[], enum op type, int fts_options) curr->fts_path); break; case S_IFIFO: - if (Rflag) { + if (Rflag && !sflag) { if (copy_fifo(curr->fts_statp, !dne)) badcp = rval = 1; } else { diff --git a/bin/cp/extern.h b/bin/cp/extern.h index 94c416b048ec..f8c20daa893e 100644 --- a/bin/cp/extern.h +++ b/bin/cp/extern.h @@ -37,7 +37,7 @@ typedef struct { } PATH_T; extern PATH_T to; -extern int fflag, iflag, lflag, nflag, pflag, vflag; +extern int fflag, iflag, lflag, nflag, pflag, sflag, vflag; extern volatile sig_atomic_t info; __BEGIN_DECLS diff --git a/bin/cp/utils.c b/bin/cp/utils.c index f8cf6f4f908e..a383713c7565 100644 --- a/bin/cp/utils.c +++ b/bin/cp/utils.c @@ -77,13 +77,15 @@ copy_file(const FTSENT *entp, int dne) ssize_t wcount; size_t wresid; off_t wtotal; - int ch, checkch, from_fd = 0, rcount, rval, to_fd = 0; + int ch, checkch, from_fd, rcount, rval, to_fd; char *bufp; #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED char *p; #endif - if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) { + from_fd = to_fd = -1; + if (!lflag && !sflag && + (from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) { warn("%s", entp->fts_path); return (1); } @@ -103,8 +105,8 @@ copy_file(const FTSENT *entp, int dne) if (nflag) { if (vflag) printf("%s not overwritten\n", to.p_path); - (void)close(from_fd); - return (1); + rval = 1; + goto done; } else if (iflag) { (void)fprintf(stderr, "overwrite %s? %s", to.p_path, YESNO); @@ -112,9 +114,9 @@ copy_file(const FTSENT *entp, int dne) while (ch != '\n' && ch != EOF) ch = getchar(); if (checkch != 'y' && checkch != 'Y') { - (void)close(from_fd); (void)fprintf(stderr, "not overwritten\n"); - return (1); + rval = 1; + goto done; } } @@ -122,28 +124,28 @@ copy_file(const FTSENT *entp, int dne) /* remove existing destination file name, * create a new file */ (void)unlink(to.p_path); - if (!lflag) { + if (!lflag && !sflag) { to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, fs->st_mode & ~(S_ISUID | S_ISGID)); } - } else if (!lflag) { + } else if (!lflag && !sflag) { /* overwrite existing destination file name */ to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0); } - } else if (!lflag) { + } else if (!lflag && !sflag) { to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, fs->st_mode & ~(S_ISUID | S_ISGID)); } - if (to_fd == -1) { + if (!lflag && !sflag && to_fd == -1) { warn("%s", to.p_path); - (void)close(from_fd); - return (1); + rval = 1; + goto done; } rval = 0; - if (!lflag) { + if (!lflag && !sflag) { /* * Mmap and write if less than 8M (the limit is so we don't totally * trash memory on big files. This is really a minor hack, but it @@ -229,11 +231,16 @@ copy_file(const FTSENT *entp, int dne) rval = 1; } } - } else { + } else if (lflag) { if (link(entp->fts_path, to.p_path)) { warn("%s", to.p_path); rval = 1; } + } else if (sflag) { + if (symlink(entp->fts_path, to.p_path)) { + warn("%s", to.p_path); + rval = 1; + } } /* @@ -243,7 +250,7 @@ copy_file(const FTSENT *entp, int dne) * to remove it if we created it and its length is 0. */ - if (!lflag) { + if (!lflag && !sflag) { if (pflag && setfile(fs, to_fd)) rval = 1; if (pflag && preserve_fd_acls(from_fd, to_fd) != 0) @@ -254,8 +261,9 @@ copy_file(const FTSENT *entp, int dne) } } - (void)close(from_fd); - +done: + if (from_fd != -1) + (void)close(from_fd); return (rval); } @@ -535,8 +543,8 @@ usage(void) { (void)fprintf(stderr, "%s\n%s\n", -"usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpvx] source_file target_file", -" cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpvx] source_file ... " +"usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpsvx] source_file target_file", +" cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpsvx] source_file ... " "target_directory"); exit(EX_USAGE); }