Subject: bin/5283: cp -f does not work as expected
To: None <gnats-bugs@gnats.netbsd.org>
From: Jochen Pohl <jpo@EasternGraphics.com>
List: netbsd-bugs
Date: 04/12/1998 00:10:05
>Number:         5283
>Category:       bin
>Synopsis:       cp -f does not work as expected
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Apr 11 15:20:00 1998
>Last-Modified:
>Originator:     Jochen Pohl
>Organization:
EasternGraphics GmbH
>Release:        1.3.1
>Environment:
System: NetBSD ariadne.EasternGraphics.com 1.3.1 NetBSD 1.3.1 (ARIADNE_DISKLESS) #0: Thu Apr 2 23:06:37 MEST 1998 root@ariadne.EasternGraphics.com:/usr/src/sys/arch/i386/compile/ARIADNE_DISKLESS i386


>Description:

The manual page for cp(1) in 1.3.1 claims that with the -f option:

1) each existing destination pathname is removed and a new file is
   created, without prompting for confirmation
2) the -i option is ignored

2) is done, 1) not.

The right behaviour for -f would be to try to remove the destination
file if it cannot be opened for writing and to proceed as would be
done without -f. The -i option should not be ignored if -f is
specified.

>How-To-Repeat:

(not as root):
bash$ touch foo
bash$ chmod 444 foo
bash$ touch bar
bash$ cp -f bar foo
cp: foo: Permission denied

>Fix:

--- ./.%%cp.c%%	Tue Mar 31 22:47:58 1998
+++ ./cp.c	Tue Mar 31 22:59:27 1998
@@ -91,7 +91,7 @@
 PATH_T to = { to.p_path, "" };
 
 uid_t myuid;
-int Rflag, iflag, pflag, rflag;
+int Rflag, fflag, iflag, pflag, rflag;
 int myumask;
 
 enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
@@ -129,7 +129,7 @@
 			Rflag = 1;
 			break;
 		case 'f':
-			iflag = 0;
+			fflag = 1;
 			break;
 		case 'i':
 			iflag = isatty(fileno(stdin));
--- ./.%%utils.c%%	Tue Mar 31 22:52:14 1998
+++ ./utils.c	Tue Mar 31 22:58:31 1998
@@ -97,7 +97,11 @@
 			}
 		}
 		to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
-	} else
+		if (to_fd == -1 && fflag)
+			if (unlink(to.p_path) == 0)
+				dne = 1;
+	}
+	if (dne)
 		to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
 		    fs->st_mode & ~(S_ISUID | S_ISGID));
 
--- ./.%%extern.h%%	Tue Mar 31 22:56:54 1998
+++ ./extern.h	Tue Mar 31 22:57:02 1998
@@ -43,7 +43,7 @@
 
 extern PATH_T to;
 extern uid_t myuid;
-extern int iflag, pflag, myumask;
+extern int fflag, iflag, pflag, myumask;
 
 #include <sys/cdefs.h>
 
--- ./.%%cp.1%%	Tue Mar 31 23:01:01 1998
+++ ./cp.1	Sat Apr 11 23:53:22 1998
@@ -102,14 +102,8 @@
 Created directories have the same mode as the corresponding source
 directory, unmodified by the process' umask.
 .It Fl f
-For each existing destination pathname, remove it and
-create a new file, without prompting for confirmation
-regardless of its permissions.
-(The
-.Fl i
-option is ignored if the
-.Fl f
-option is specified.)
+If a destination file cannot be opened for writing,
+attempt to unlink the destination file and proceed.
 .It Fl i
 Causes
 .Nm
>Audit-Trail:
>Unformatted: