The branch main has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=c3efa16dc9bcdcbe128c6b3c4b000867bbaf7991
commit c3efa16dc9bcdcbe128c6b3c4b000867bbaf7991 Author: Dag-Erling Smørgrav <d...@freebsd.org> AuthorDate: 2025-07-09 17:05:54 +0000 Commit: Dag-Erling Smørgrav <d...@freebsd.org> CommitDate: 2025-07-09 17:07:13 +0000 cp: Add GNU-compatible long options. While here, fully switch boolean variables from int to bool, and clean up the manual page a little. Sponsored by: Klara, Inc. Reviewed by: kevans Differential Revision: https://reviews.freebsd.org/D51213 --- bin/cp/cp.1 | 39 +++++++++++-------------- bin/cp/cp.c | 78 +++++++++++++++++++++++++++++++------------------ bin/cp/extern.h | 2 +- bin/cp/tests/cp_test.sh | 16 ++++++++++ bin/cp/utils.c | 4 +-- 5 files changed, 86 insertions(+), 53 deletions(-) diff --git a/bin/cp/cp.1 b/bin/cp/cp.1 index 2856391a029e..6edc8e403acd 100644 --- a/bin/cp/cp.1 +++ b/bin/cp/cp.1 @@ -29,7 +29,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd March 28, 2024 +.Dd July 9, 2025 .Dt CP 1 .Os .Sh NAME @@ -84,16 +84,16 @@ If the .Fl R option is specified, symbolic links on the command line are followed. (Symbolic links encountered in the tree traversal are not followed.) -.It Fl L +.It Fl L , Fl -dereference If the .Fl R option is specified, all symbolic links are followed. -.It Fl P +.It Fl P , Fl -no-dereference No symbolic links are followed. This is the default if the .Fl R option is specified. -.It Fl R +.It Fl R , Fl -recursive If .Ar source_file designates a directory, @@ -121,11 +121,11 @@ If you need to preserve hard links, consider using or .Xr pax 1 instead. -.It Fl a +.It Fl a , Fl -archive Archive mode. Same as .Fl RpP . -.It Fl f +.It Fl f , Fl -force For each existing destination pathname, remove it and create a new file, without prompting for confirmation regardless of its permissions. @@ -136,10 +136,8 @@ option overrides any previous or .Fl n options.) -.It Fl i -Cause -.Nm -to write a prompt to the standard error output before copying a file +.It Fl i , Fl -interactive +Write a prompt to the standard error output before copying a file that would overwrite an existing file. If the response from the standard input begins with the character .Sq Li y @@ -153,13 +151,13 @@ option overrides any previous or .Fl n options.) -.It Fl l +.It Fl l , Fl -link Create hard links to regular files in a hierarchy instead of copying. .It Fl N When used with .Fl p , suppress copying file flags. -.It Fl n +.It Fl n , Fl -no-clobber Do not overwrite an existing file. (The .Fl n @@ -169,9 +167,7 @@ or .Fl i options.) .It Fl p -Cause -.Nm -to preserve the following attributes of each source +Preserve the following attributes of each source file in the copy: modification time, access time, file flags, file mode, ACL, user ID, and group ID, as allowed by permissions. .Pp @@ -188,14 +184,13 @@ 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 +.It Fl s , Fl -symbolic-link Create symbolic links to regular files in a hierarchy instead of copying. -.It Fl v -Cause -.Nm -to be verbose, showing files as they are copied. -.It Fl x -File system mount points are not traversed. +.It Fl v , Fl -verbose +Be verbose, showing both the source and destination path of each file +as is copied. +.It Fl x , Fl -one-file-system +Do not traverse file system mount points. .El .Pp For each destination file that already exists, its contents are diff --git a/bin/cp/cp.c b/bin/cp/cp.c index 7e97715c3ef4..a1b62084a790 100644 --- a/bin/cp/cp.c +++ b/bin/cp/cp.c @@ -55,6 +55,7 @@ #include <errno.h> #include <fcntl.h> #include <fts.h> +#include <getopt.h> #include <limits.h> #include <signal.h> #include <stdbool.h> @@ -69,8 +70,8 @@ static char dot[] = "."; #define END(buf) (buf + sizeof(buf)) PATH_T to = { .dir = -1, .end = to.path }; -int Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag; -static int Hflag, Lflag, Pflag, Rflag, rflag; +bool Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag; +static bool Hflag, Lflag, Pflag, Rflag, rflag; volatile sig_atomic_t info; enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; @@ -78,6 +79,26 @@ enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; static int copy(char *[], enum op, int, struct stat *); static void siginfo(int __unused); +enum { + SORT_OPT = CHAR_MAX, +}; + +static const struct option long_opts[] = +{ + { "archive", no_argument, NULL, 'a' }, + { "force", no_argument, NULL, 'f' }, + { "interactive", no_argument, NULL, 'i' }, + { "dereference", no_argument, NULL, 'L' }, + { "link", no_argument, NULL, 'l' }, + { "no-clobber", no_argument, NULL, 'n' }, + { "no-dereference", no_argument, NULL, 'P' }, + { "recursive", no_argument, NULL, 'R' }, + { "symbolic-link", no_argument, NULL, 's' }, + { "verbose", no_argument, NULL, 'v' }, + { "one-file-system", no_argument, NULL, 'x' }, + { 0 } +}; + int main(int argc, char *argv[]) { @@ -88,59 +109,60 @@ main(int argc, char *argv[]) bool have_trailing_slash = false; fts_options = FTS_NOCHDIR | FTS_PHYSICAL; - while ((ch = getopt(argc, argv, "HLPRafilNnprsvx")) != -1) + while ((ch = getopt_long(argc, argv, "+HLPRafilNnprsvx", long_opts, + NULL)) != -1) switch (ch) { case 'H': - Hflag = 1; - Lflag = Pflag = 0; + Hflag = true; + Lflag = Pflag = false; break; case 'L': - Lflag = 1; - Hflag = Pflag = 0; + Lflag = true; + Hflag = Pflag = false; break; case 'P': - Pflag = 1; - Hflag = Lflag = 0; + Pflag = true; + Hflag = Lflag = false; break; case 'R': - Rflag = 1; + Rflag = true; break; case 'a': - pflag = 1; - Rflag = 1; - Pflag = 1; - Hflag = Lflag = 0; + pflag = true; + Rflag = true; + Pflag = true; + Hflag = Lflag = false; break; case 'f': - fflag = 1; - iflag = nflag = 0; + fflag = true; + iflag = nflag = false; break; case 'i': - iflag = 1; - fflag = nflag = 0; + iflag = true; + fflag = nflag = false; break; case 'l': - lflag = 1; + lflag = true; break; case 'N': - Nflag = 1; + Nflag = true; break; case 'n': - nflag = 1; - fflag = iflag = 0; + nflag = true; + fflag = iflag = false; break; case 'p': - pflag = 1; + pflag = true; break; case 'r': - rflag = Lflag = 1; - Hflag = Pflag = 0; + rflag = Lflag = true; + Hflag = Pflag = false; break; case 's': - sflag = 1; + sflag = true; break; case 'v': - vflag = 1; + vflag = true; break; case 'x': fts_options |= FTS_XDEV; @@ -159,7 +181,7 @@ main(int argc, char *argv[]) if (lflag && sflag) errx(1, "the -l and -s options may not be specified together"); if (rflag) - Rflag = 1; + Rflag = true; if (Rflag) { if (Hflag) fts_options |= FTS_COMFOLLOW; diff --git a/bin/cp/extern.h b/bin/cp/extern.h index c0c524756980..683e6e5f289f 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 Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag; +extern bool Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag; extern volatile sig_atomic_t info; __BEGIN_DECLS diff --git a/bin/cp/tests/cp_test.sh b/bin/cp/tests/cp_test.sh index 1d2cd4292459..6adbc45c5009 100755 --- a/bin/cp/tests/cp_test.sh +++ b/bin/cp/tests/cp_test.sh @@ -688,6 +688,21 @@ unrfile_body() atf_check cmp src/c dst/c } +atf_test_case nopermute +nopermute_head() +{ + atf_set descr "Check that getopt_long does not permute options" +} +nopermute_body() +{ + mkdir src dst + atf_check \ + -s exit:1 \ + -e match:'cp: -p: No such file' \ + cp -R src -p dst + atf_check test -d dst/src +} + atf_init_test_cases() { atf_add_test_case basic @@ -729,4 +744,5 @@ atf_init_test_cases() atf_add_test_case dirloop atf_add_test_case unrdir atf_add_test_case unrfile + atf_add_test_case nopermute } diff --git a/bin/cp/utils.c b/bin/cp/utils.c index cfc0f0f12603..2036056ada68 100644 --- a/bin/cp/utils.c +++ b/bin/cp/utils.c @@ -105,7 +105,7 @@ copy_file(const FTSENT *entp, bool dne, bool beneath) ssize_t wcount; off_t wtotal; int ch, checkch, from_fd, rval, to_fd; - int use_copy_file_range = 1; + bool use_copy_file_range = true; fs = entp->fts_statp; from_fd = to_fd = -1; @@ -210,7 +210,7 @@ copy_file(const FTSENT *entp, bool dne, bool beneath) to_fd, NULL, SSIZE_MAX, 0); if (wcount < 0 && errno == EINVAL) { /* probably a non-seekable descriptor */ - use_copy_file_range = 0; + use_copy_file_range = false; } } if (!use_copy_file_range) {