From nobody Wed Jul 9 17:09:54 2025 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4bckxG5dTcz60hYD; Wed, 09 Jul 2025 17:09:54 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4bckxG4xvmz4H3t; Wed, 09 Jul 2025 17:09:54 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1752080994; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=dB84tqXdgKpwFNZRiRVVWW5thylgmAi5EmhBnQPZnQI=; b=icjhlkctQDOdInwkGUOqXyR6hRDfe3Wtg93rQqjcbQ7KAWNpO4lTe5DlODbQH5udAAdsWV dRHsrmQOvzpnG8EW6sDUyp76gSZh8qalI2x+s/4o+RYiX3JRESEYAfFlY6fUmONzNpgzYY t7sW6KbV1KcuM2JDcgdbIjxjuif5cCOvfNxt6m2PqeschG6w57toYpTOt1AU06/U9Kt4xb 6WrQIIjVKf/CU4TeVId7UGmIzgwFjAnd5zgWRjnwayqNIpU/4zp/sBopVUB0ofaaM4cEJ/ NFl+BesnC8FMx5izKHmg0Fz9K4u9Ktj42UHi6iUuNNweVKaswOONbA/Cvt7HHg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1752080994; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=dB84tqXdgKpwFNZRiRVVWW5thylgmAi5EmhBnQPZnQI=; b=GPtujN8+t547LC1XVNcioAwcG6jKoUgp7NnQ0w8tk4LFUfaxbUfhIVCt/jrhEQ/8Ifusae /OW44qfaUldYz3e8cItB3m9/FvvtNVYY4Gv8BhWv+khOj2qo2MToXLTcJ4ZGAsgqE9Rc94 SBSGR8l7vAEVJOuWHGrdO5exRc39TWoqF9ipMUjy8bp5JfB1yF+ICVJAZnpbu5SLoWLE2h uFfJeUCB6qcTC4KuSGnUYslUsWCXVpsEsBGB4QE8AKqlQyB2feM/AfR142RPcwFoHwETDh Li2zCrwljbfKaoODl71HFNoCVCFgW2wjR09kL5bI1d7gJ4gGVP6E9EC1kksgsg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1752080994; a=rsa-sha256; cv=none; b=i/DJEXHRfmSv2A7LsCWnw1NGED2XskzBptRDYJ6VR42svE9NaJ2yQopsuUQV7s9NH0RiWH BRrOrSOXA43dQr4cuf/Y+wGZcoLb0/Lsjce3I8Jv1JKceyiOE10N2y5s6GoO+8CxZU3SIL Rivn2lUqxF5gr0i4AUbAX2e4vyqhXhQeDPxyWbBLfF0fb5qdPI5+aUcNVFNFSV/ztlJpgM 3Awsw4RAciStnSmPmcrBJc/YPN/ah7IN+idDmwFc0AzejfY45Xup0c8yiYFrIMwCdmDOzN 0w8257h3xObyPxzkuwshz4uc+g3zxgIh8w2MHTqwTDGexjWh1R7vwT2ayp0P7A== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4bckxG4L04zWHp; Wed, 09 Jul 2025 17:09:54 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 569H9sow072737; Wed, 9 Jul 2025 17:09:54 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 569H9sqA072735; Wed, 9 Jul 2025 17:09:54 GMT (envelope-from git) Date: Wed, 9 Jul 2025 17:09:54 GMT Message-Id: <202507091709.569H9sqA072735@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Dag-Erling =?utf-8?Q?Sm=C3=B8rgrav?= Subject: git: c3efa16dc9bc - main - cp: Add GNU-compatible long options. List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: des X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: c3efa16dc9bcdcbe128c6b3c4b000867bbaf7991 Auto-Submitted: auto-generated The branch main has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=c3efa16dc9bcdcbe128c6b3c4b000867bbaf7991 commit c3efa16dc9bcdcbe128c6b3c4b000867bbaf7991 Author: Dag-Erling Smørgrav AuthorDate: 2025-07-09 17:05:54 +0000 Commit: Dag-Erling Smørgrav 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 #include #include +#include #include #include #include @@ -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) {