POSIX.2 compliance: set uid/gid for -p, add -f.
authorKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Sat, 20 May 1989 09:11:48 +0000 (01:11 -0800)
committerKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Sat, 20 May 1989 09:11:48 +0000 (01:11 -0800)
on -r, recreate special files

SCCS-vsn: bin/cp/cp.1 6.4
SCCS-vsn: bin/cp/cp.c 5.5

usr/src/bin/cp/cp.1
usr/src/bin/cp/cp.c

index 4ad6d16..ba6ad30 100644 (file)
@@ -1,74 +1,99 @@
-.\" Copyright (c) 1980 Regents of the University of California.
-.\" All rights reserved.  The Berkeley software License Agreement
-.\" specifies the terms and conditions for redistribution.
+.\" Copyright (c) 1989 The Regents of the University of California.
+.\" All rights reserved.
 .\"
 .\"
-.\"    @(#)cp.1        6.3 (Berkeley) %G%
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley.  The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\"    @(#)cp.1        6.4 (Berkeley) %G%
 .\"
 .TH CP 1 ""
 .UC 4
 .SH NAME
 .\"
 .TH CP 1 ""
 .UC 4
 .SH NAME
-cp \- copy
+cp - copy files
 .SH SYNOPSIS
 .SH SYNOPSIS
-.B cp
-[
-.B \-hip
-] file1 file2
-.PP
-.B cp
-[
-.B \-hipr
-] file ... directory
+\fBcp [ \fI-fhip\fB ] source_file target_file
+.sp
+\fBcp [ \fI-fhipr\fB ] source_file ... target_directory
+.ft R
 .SH DESCRIPTION
 .SH DESCRIPTION
-.I File1
-is copied onto
-.IR file2 .
-By default, the mode and owner of  
-.I file2
-are preserved if it already
-existed; otherwise the mode of the source file modified by the current
-.IR umask (2)
-is used.  The
-.B \-p
-option causes
+The
 .I cp
 .I cp
-to attempt to preserve (duplicate) in its copies the modification
-times and modes of the source files, ignoring the present
-.IR umask .
-.PP
-In the second form, one or more
-.I files
-are copied into the
-.I directory
-with their original file-names.
-.PP
-.I Cp
-refuses to copy a file onto itself.
+utility copies
+.I source_file
+to
+.I target_file
+or, in the second form, one or more
+.IR source_file s
+are copied into the target
+.IR target_directory ,
+retaining their original filenames.
+If
+.I cp
+detects an attempt to copy a file to itself, the copy shall fail.
+For each destination file that already exists, its contents are
+overwritten if permissions allow, but its mode, user ID, and group
+ID are unchanged.
+Otherwise, the mode of the
+.I source_file
+is used as modified by the file mode creation mask.
+Appropriate permissions are required for file creation or overwriting.
 .PP
 .PP
-If the 
-.B \-i
-option is specified, 
+The following options are available:
+.TP
+.I -h
+Forces
 .I cp
 .I cp
-will prompt the user with the name of the file whenever the copy
-will cause an old file to be overwritten.
-An answer of 'y' will cause 
+to follow symbolic links.
+.TP
+.I -f
+Force existing destination pathnames to be removed before copying,
+without prompting for confirmation.
+.TP
+.I -i
+Causes
 .I cp
 .I cp
-to continue.
-Any other answer will prevent it from overwriting the file.
-.PP
-If the
-.B \-r
-option is specified and any of the source files are directories,
+to write a prompt to standard error before copying a file that would
+overwrite an existing file.
+If the response from the standard input begins with the character ``y'',
+the file is copied if permissions allow the copy.
+.TP
+.I -p
+Causes
 .I cp
 .I cp
-copies each subtree rooted at that name; in this case
-the destination must be a directory.
-.I Cp
-does not follow symbolic links if the
-.B -r
-option is specified.
-The
-.B -h
-option forces
+to preserve in the copy as many of the modification time, access time,
+file mode, user ID, and group ID as allowed by permissions.
+.TP
+.I -r
+If
+.I source_file
+designates a directory,
+.I cp
+copies the directory and the entire subtree connected at that point.
+This option also causes symbolic links to be copied, rather than
+indirected through, and for
 .I cp
 .I cp
-to always follow symbolic links.
+to create special files rather than copying them as normal files.
+.PP
+The
+.I -i
+option is ignored if the
+.I -f
+option is specified.
+.PP
+Symbolic links are followed unless the
+.I -r
+option is specified, in which case the link itself is copied.
+.PP
+.I Cp
+exits 0 on success, >0 if an error occurred.
 .SH "SEE ALSO"
 .SH "SEE ALSO"
-cat(1), mv(1), rcp(1)
+mv(1), rcp(1), umask(2)
index a28451f..73f54b6 100644 (file)
@@ -25,7 +25,7 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)cp.c       5.4 (Berkeley) %G%";
+static char sccsid[] = "@(#)cp.c       5.5 (Berkeley) %G%";
 #endif /* not lint */
 
 /*
 #endif /* not lint */
 
 /*
@@ -63,10 +63,12 @@ static char sccsid[] = "@(#)cp.c    5.4 (Berkeley) %G%";
 #include <strings.h>
 
 typedef struct {
 #include <strings.h>
 
 typedef struct {
-       char    *p_path;        /* Pointer to the start of a path. */
-       char    *p_end;         /* Pointer to NULL at end of path. */
+       char    *p_path;        /* pointer to the start of a path. */
+       char    *p_end;         /* pointer to NULL at end of path. */
 } path_t;
 
 } path_t;
 
+#define        type(st)        ((st).st_mode&S_IFMT)
+
 char *path_append(), *path_basename();
 void path_restore();
 
 char *path_append(), *path_basename();
 void path_restore();
 
@@ -85,10 +87,15 @@ main(argc, argv)
        extern int optind, errno;
        struct stat to_stat;
        register int c, r;
        extern int optind, errno;
        struct stat to_stat;
        register int c, r;
+       int force_flag;
        char *old_to, *malloc();
 
        char *old_to, *malloc();
 
-       while ((c = getopt(argc, argv, "Rhipr")) != EOF) {
-       switch ((char) c) {
+       force_flag = 0;
+       while ((c = getopt(argc, argv, "Rfhipr")) != EOF) {
+       switch ((char)c) {
+               case 'f':
+                       force_flag = 1;
+                       break;
                case 'h':
                        symfollow = 1;
                        break;
                case 'h':
                        symfollow = 1;
                        break;
@@ -115,6 +122,9 @@ main(argc, argv)
        if (argc < 2)
                usage();
 
        if (argc < 2)
                usage();
 
+       if (force_flag)
+               interactive_flag = 0;
+
        my_umask = umask(0);
        (void)umask(my_umask);
 
        my_umask = umask(0);
        (void)umask(my_umask);
 
@@ -146,10 +156,10 @@ main(argc, argv)
 
        r = stat(to.p_path, &to_stat);
        if (r == -1 && errno != ENOENT) {
 
        r = stat(to.p_path, &to_stat);
        if (r == -1 && errno != ENOENT) {
-               error(to.p_path);
+               error(to.p_path, "stat");
                exit(1);
        }
                exit(1);
        }
-       if (r == -1 || (to_stat.st_mode & S_IFMT) != S_IFDIR) {
+       if (r == -1 || type(to_stat) != S_IFDIR) {
                /*
                 * Case (1).  Target is not a directory.
                 */
                /*
                 * Case (1).  Target is not a directory.
                 */
@@ -178,18 +188,16 @@ main(argc, argv)
        exit(exit_val);
 }
 
        exit(exit_val);
 }
 
-/*
- * Copy file or directory at "from" to "to".
- */
+/* copy file or directory at "from" to "to". */
 copy()
 {
        struct stat from_stat, to_stat;
 copy()
 {
        struct stat from_stat, to_stat;
-       int new_target_dir, statval;
+       int statval;
 
        statval = symfollow || !recursive_flag ?
            stat(from.p_path, &from_stat) : lstat(from.p_path, &from_stat);
        if (statval == -1) {
 
        statval = symfollow || !recursive_flag ?
            stat(from.p_path, &from_stat) : lstat(from.p_path, &from_stat);
        if (statval == -1) {
-               error(from.p_path);
+               error(from.p_path, "stat");
                return;
        }
 
                return;
        }
 
@@ -205,62 +213,57 @@ copy()
                return;
        }
 
                return;
        }
 
-       if ((from_stat.st_mode & S_IFMT) == S_IFLNK) {
+       switch(type(from_stat)) {
+       case S_IFLNK:
                copy_link(to_stat.st_ino != -1);
                return;
                copy_link(to_stat.st_ino != -1);
                return;
-       }
-
-       new_target_dir = 0;
-       if ((from_stat.st_mode & S_IFMT) != S_IFDIR) {
-               if (!copy_file(from_stat.st_mode))
-                       return;
-       }
-       else {
+       case S_IFDIR:
                if (!recursive_flag) {
                        (void)fprintf(stderr,
                if (!recursive_flag) {
                        (void)fprintf(stderr,
-                          "cp: \"%s\" is a directory (not copied).\n",
-                          from.p_path);
+                           "cp: %s is a directory (not copied).\n",
+                           from.p_path);
                        exit_val = 1;
                        return;
                }
                if (to_stat.st_ino == -1) {
                        if (mkdir(to.p_path, 0777) < 0) {
                        exit_val = 1;
                        return;
                }
                if (to_stat.st_ino == -1) {
                        if (mkdir(to.p_path, 0777) < 0) {
-                               error(to.p_path);
+                               error(to.p_path, "mkdir");
                                return;
                        }
                                return;
                        }
-                       new_target_dir = 1;
+                       from_stat.st_mode &= ~my_umask;
                }
                }
-               else if ((to_stat.st_mode & S_IFMT) != S_IFDIR) {
-                       (void)fprintf(stderr,
-                          "cp: %s: not a directory.\n",
-                          to.p_path);
+               else if (type(to_stat) != S_IFDIR) {
+                       (void)fprintf(stderr, "cp: %s: not a directory.\n",
+                           to.p_path);
                        return;
                }
                copy_dir();
                        return;
                }
                copy_dir();
+               break;
+       case S_IFCHR:
+       case S_IFBLK:
+               if (recursive_flag) {
+                       copy_special(&from_stat, &to_stat);
+                       if (preserve_flag)
+                               setfile(&from_stat);
+                       return;
+               }
+               /* FALLTHROUGH */
+       default:
+               if (!copy_file(from_stat.st_mode))
+                       return;
        }
        }
-       /* Preserve old times/modes if necessary. */
        if (preserve_flag)
        if (preserve_flag)
-               (void)chmod(to.p_path, (int) from_stat.st_mode);
-       else if (new_target_dir)
-               (void)chmod(to.p_path, (int) from_stat.st_mode & ~my_umask);
-       if (preserve_flag || new_target_dir) {
-               static struct timeval tv[2];
-
-               tv[0].tv_sec = from_stat.st_atime;
-               tv[1].tv_sec = from_stat.st_mtime;
-               if (utimes(to.p_path, tv))
-                       error(to.p_path);
-       }
+               setfile(&from_stat);
 }
 
 copy_file(mode)
 }
 
 copy_file(mode)
-       u_short mode;                   /* Permissions for new file. */
+       u_short mode;                   /* permissions for new file. */
 {
 {
-       int from_fd, to_fd, rcount, wcount;
+       register int from_fd, to_fd, rcount, wcount;
 
        from_fd = open(from.p_path, O_RDONLY, 0);
        if (from_fd == -1) {
 
        from_fd = open(from.p_path, O_RDONLY, 0);
        if (from_fd == -1) {
-               error(from.p_path);
+               error(from.p_path, "open");
                (void)close(from_fd);
                return(0);
        }
                (void)close(from_fd);
                return(0);
        }
@@ -287,7 +290,7 @@ copy_file(mode)
        }
 
        if (to_fd == -1) {
        }
 
        if (to_fd == -1) {
-               error(to.p_path);
+               error(to.p_path, "open");
                (void)close(from_fd);
                return(0);
        }
                (void)close(from_fd);
                return(0);
        }
@@ -295,7 +298,7 @@ copy_file(mode)
        while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
                wcount = write(to_fd, buf, rcount);
                if (rcount != wcount || wcount == -1) {
        while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
                wcount = write(to_fd, buf, rcount);
                if (rcount != wcount || wcount == -1) {
-                       error(from.p_path);
+                       error(from.p_path, "write");
                        break;
                }
        }
                        break;
                }
        }
@@ -335,12 +338,12 @@ copy_dir()
                }
 
                if (stat(from.p_path, &from_stat) < 0) {
                }
 
                if (stat(from.p_path, &from_stat) < 0) {
-                       error(dp->d_name);
+                       error(dp->d_name, "stat");
                        path_restore(&from, old_from);
                        continue;
                }
 
                        path_restore(&from, old_from);
                        continue;
                }
 
-               if ((from_stat.st_mode & S_IFMT) != S_IFDIR) {
+               if (type(from_stat) != S_IFDIR) {
                        old_to = path_append(&to, dp->d_name,
                            (int)dp->d_namlen);
                        if (!old_to) {
                        old_to = path_append(&to, dp->d_name,
                            (int)dp->d_namlen);
                        if (!old_to) {
@@ -356,7 +359,7 @@ copy_dir()
                path_restore(&from, old_from);
        }
 
                path_restore(&from, old_from);
        }
 
-       /* Then copy directories. */
+       /* then copy directories. */
        for (i = 0; i < dir_cnt; ++i) {
                dp = dir_list[i];
                if (!dp)
        for (i = 0; i < dir_cnt; ++i) {
                dp = dir_list[i];
                if (!dp)
@@ -386,26 +389,54 @@ copy_link(exists)
        char link[MAXPATHLEN];
 
        if (readlink(from.p_path, link, sizeof(link)) == -1) {
        char link[MAXPATHLEN];
 
        if (readlink(from.p_path, link, sizeof(link)) == -1) {
-               error(from.p_path);
+               error(from.p_path, "readlink");
                return;
        }
        if (exists && unlink(to.p_path)) {
                return;
        }
        if (exists && unlink(to.p_path)) {
-               error(to.p_path);
+               error(to.p_path, "unlink");
                return;
        }
        if (symlink(link, to.p_path)) {
                return;
        }
        if (symlink(link, to.p_path)) {
-               error(link);
+               error(link, "symlink");
                return;
        }
 }
 
                return;
        }
 }
 
-error(s)
-       char *s;
+copy_special(from_stat, to_stat)
+       struct stat *from_stat, *to_stat;
+{
+       if (to_stat->st_ino != -1 && unlink(to.p_path)) {
+               error(to.p_path, "unlink");
+               return;
+       }
+       if (mknod(to.p_path, from_stat->st_mode,  from_stat->st_rdev)) {
+               error(to.p_path, "mknod");
+               return;
+       }
+}
+
+setfile(fs)
+       struct stat *fs;
+{
+       static struct timeval tv[2];
+
+       if (chown(to.p_path, fs->st_uid, fs->st_gid))
+               error(to.p_path, "chown");
+       if (chmod(to.p_path, fs->st_mode))
+               error(to.p_path, "chmod");
+       tv[0].tv_sec = fs->st_atime;
+       tv[1].tv_sec = fs->st_mtime;
+       if (utimes(to.p_path, tv))
+               error(to.p_path, "utimes");
+}
+
+error(s, call)
+       char *s, *call;
 {
        extern int errno;
 
        exit_val = 1;
 {
        extern int errno;
 
        exit_val = 1;
-       (void)fprintf(stderr, "cp: %s: %s\n", s, strerror(errno));
+       (void)fprintf(stderr, "cp: %s: %s: %s\n", call, s, strerror(errno));
 }
 
 /********************************************************************
 }
 
 /********************************************************************