Patch for cp(1)

Bruce Evans bde at zeta.org.au
Wed Mar 30 21:31:00 PST 2005


On Wed, 30 Mar 2005, Tom Rhodes wrote:

> Hi -standards.
>
> What do people think of the following patch to cp.c:

It seems to be wrong.  From cp(1):

%%%
COMPATIBILITY
      Historic versions of the cp utility had a -r option.  This implementation
      supports that option, however, its use is strongly discouraged, as it
      does not correctly copy special files, symbolic links or fifo's.
%%%

Any change to the semantics of -r would break applications that depend on
its historical behaviour.  Any change that doesn't change the man page would
be more broken.

This conforms to at least POSIX.1-200x-draft7:

%%%
10284 OB         cp -r [-H | -L | -P][-fip] source_file ... target
10326                  * If the -r option was specified, the behavior is implementation-defined.
10430 OB              -r             Copy file hierarchies. The treatment of special files is implementation-defined.
%%%

The correct fix is to remove the -r option.  Unfortunately, POSIX broke
this.

> Index: cp.c
> ===================================================================
> RCS file: /home/ncvs/src/bin/cp/cp.c,v
> retrieving revision 1.51
> diff -u -r1.51 cp.c
> --- cp.c        10 Jan 2005 08:39:21 -0000      1.51
> +++ cp.c        30 Mar 2005 15:42:43 -0000
> @@ -84,7 +84,7 @@
> PATH_T to = { to.p_path, emptystring, "" };
>
> int fflag, iflag, nflag, pflag, vflag;
> -static int Rflag, rflag;
> +static int Rflag;
> volatile sig_atomic_t info;
>
> enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
> @@ -135,7 +135,7 @@
>                        pflag = 1;
>                        break;
>                case 'r':
> -                       rflag = 1;
> +                       Rflag = 1;
>                        break;
>                case 'v':
>                        vflag = 1;

The patch has lots of tab lossage and collateral indentation lossage...

> @@ -151,16 +151,7 @@
>                usage();
>
>        fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
> -       if (rflag) {
> -               if (Rflag)
> -                       errx(1,
> -                   "the -R and -r options may not be specified together.");
> -               if (Hflag || Lflag || Pflag)
> -                       errx(1,
> -       "the -H, -L, and -P options may not be specified with the -r option.");
> -               fts_options &= ~FTS_PHYSICAL;
> -               fts_options |= FTS_LOGICAL;
> -       }

POSIX.1-200x-draft7 only requires -{HLP} to work with -R.  Their behaviour
with -r is not explicitly mentioned.  It is strange to show them in
the synopsis with -r when they are errors when actually used with -r.
However, I think they should cause an error when used with -r, since
their use with -r is not supported.  -r could be made to work the same
as -R iff it is used together with at least one pf -{HLP}, but that
would be wrong since it would undeprecate -r.

> +

... and wrong whitespace gainage.

>        if (Rflag) {
>                if (Hflag)
>                        fts_options |= FTS_COMFOLLOW;
> @@ -224,12 +215,12 @@
>                 * the initial mkdir().
>                 */
>                if (r == -1) {
> -                       if (rflag || (Rflag && (Lflag || Hflag)))
> +                       if ((Rflag && (Lflag || Hflag))
>                                stat(*argv, &tmp_stat);
>                        else
>                                lstat(*argv, &tmp_stat);

This is the main (only?) place where -r gives useful behaviour that is
significantly different from -R.  With a bare -r, cp always follows
symlinks, but with a bare -R, cp never follows symlinks.  (The behaviour
of cp -r on non-regular files is not useful.)

> ...

> So, why/what am I doing:
>
> My copy of SuSv3 states that -r is about to become obsolete;

My copy of cp.1 says that it became obsolete in BSD before 4.4BSDLite1 :-).
It was obsolete long before that too, since it was obolete in FreeBSD-1.
cp.1 in FreeBSD-1 is dated July 30, 1991.  The deprecation apparently
rotted a bit between Net/2 and 4.4BSD -- cp.1 in FreeBSD doesn't mention
-r at all.

> The -r option fails (actually hangs) when trying to copy a fifo
> file within a directory.  It does this on both CURRENT,
> STABLE and SunOS 5.9.

This is the documented behaviour.

> The idea was to make -r a synonym for -R, which works in all of
> these cases.
>
> I plan to fix the manual page as -r is not historical, it was
> implemenation dependent.  Comments/suggestions?  Yes, manual
> page commit would done together of course.

-r is historical.  POSIX permits it to be implementation-defined
to prevent breaking it.

Bruce


More information about the freebsd-standards mailing list