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
This commit is contained in:
+17
-22
@@ -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
|
||||
|
||||
+50
-28
@@ -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;
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
+2
-2
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user