preserve file flags across install; general ANSI C and style cleanup
authorKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Mon, 29 Jun 1992 05:51:53 +0000 (21:51 -0800)
committerKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Mon, 29 Jun 1992 05:51:53 +0000 (21:51 -0800)
SCCS-vsn: usr.bin/xinstall/xinstall.c 5.25
SCCS-vsn: usr.bin/xinstall/install.1 6.12

usr/src/usr.bin/xinstall/install.1
usr/src/usr.bin/xinstall/xinstall.c

index 1358f4e..a7ffedb 100644 (file)
@@ -3,7 +3,7 @@
 .\"
 .\" %sccs.include.redist.roff%
 .\"
 .\"
 .\" %sccs.include.redist.roff%
 .\"
-.\"     @(#)install.1  6.11 (Berkeley) %G%
+.\"     @(#)install.1  6.12 (Berkeley) %G%
 .\"
 .Dd 
 .Dt INSTALL 1
 .\"
 .Dd 
 .Dt INSTALL 1
@@ -41,7 +41,7 @@ allow.
 .Bl -tag -width Ds
 .It Fl m
 Specify an alternate mode.
 .Bl -tag -width Ds
 .It Fl m
 Specify an alternate mode.
-The default mode is set to 755.
+The default mode is set to 755 (rwxr-xr-x).
 The specified mode may be either an octal or symbolic value; see
 .Xr chmod  1
 for a description of possible mode values.
 The specified mode may be either an octal or symbolic value; see
 .Xr chmod  1
 for a description of possible mode values.
@@ -57,8 +57,13 @@ to strip binaries so that install can be portable over a large
 number of systems and binary types.
 .El
 .Pp
 number of systems and binary types.
 .El
 .Pp
-.Nm Install
-refuses to move a file onto itself.
+The
+.Nm install
+utility attempts to prevent moving a file onto itself.
+.Pp
+The
+.Nm install
+utility always attempts to preserve the file flags.
 .Pp
 Installing
 .Pa /dev/null
 .Pp
 Installing
 .Pa /dev/null
@@ -67,12 +72,12 @@ creates an empty file.
 Upon successful completion a value of 0 is returned.
 Otherwise, a value of 1 is returned.
 .Sh SEE ALSO
 Upon successful completion a value of 0 is returned.
 Otherwise, a value of 1 is returned.
 .Sh SEE ALSO
+.Xr chflags 1 ,
 .Xr chgrp 1 ,
 .Xr chmod 1 ,
 .Xr cp 1 ,
 .Xr mv 1 ,
 .Xr strip 1 ,
 .Xr chgrp 1 ,
 .Xr chmod 1 ,
 .Xr cp 1 ,
 .Xr mv 1 ,
 .Xr strip 1 ,
-.Xr a.out 5 ,
 .Xr chown 8
 .Sh HISTORY
 The
 .Xr chown 8
 .Sh HISTORY
 The
index 26069a5..613d83b 100644 (file)
@@ -12,32 +12,44 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)xinstall.c 5.24 (Berkeley) %G%";
+static char sccsid[] = "@(#)xinstall.c 5.25 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/param.h>
 #endif /* not lint */
 
 #include <sys/param.h>
+#include <sys/wait.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
-#include <sys/file.h>
+
+#include <fcntl.h>
 #include <grp.h>
 #include <pwd.h>
 #include <grp.h>
 #include <pwd.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <ctype.h>
+#include <string.h>
 #include <paths.h>
 #include "pathnames.h"
 
 #include <paths.h>
 #include "pathnames.h"
 
-static struct passwd *pp;
-static struct group *gp;
-static int docopy, dostrip, mode = 0755;
-static char *group, *owner, pathbuf[MAXPATHLEN];
+struct passwd *pp;
+struct group *gp;
+int docopy, dostrip;
+int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
+char *group, *owner, pathbuf[MAXPATHLEN];
+
+void   copy __P((int, char *, int, char *));
+void   err __P((const char *, ...));
+void   install __P((char *, char *, int));
+void   strip __P((char *));
+void   usage __P((void));
 
 
+int
 main(argc, argv)
        int argc;
 main(argc, argv)
        int argc;
-       char **argv;
+       char *argv[];
 {
 {
-       extern char *optarg;
-       extern int optind;
        struct stat from_sb, to_sb;
        struct stat from_sb, to_sb;
-       mode_t *set, *setmode();
+       mode_t *set;
        int ch, no_target;
        char *to_name;
 
        int ch, no_target;
        char *to_name;
 
@@ -50,11 +62,8 @@ main(argc, argv)
                        group = optarg;
                        break;
                case 'm':
                        group = optarg;
                        break;
                case 'm':
-                       if (!(set = setmode(optarg))) {
-                               (void)fprintf(stderr,
-                                   "install: invalid file mode.\n");
-                               exit(1);
-                       }
+                       if (!(set = setmode(optarg)))
+                               err("%s: invalid file mode\n", optarg);
                        mode = getmode(set, 0);
                        break;
                case 'o':
                        mode = getmode(set, 0);
                        break;
                case 'o':
@@ -73,14 +82,10 @@ main(argc, argv)
                usage();
 
        /* get group and owner id's */
                usage();
 
        /* get group and owner id's */
-       if (group && !(gp = getgrnam(group))) {
-               fprintf(stderr, "install: unknown group %s.\n", group);
-               exit(1);
-       }
-       if (owner && !(pp = getpwnam(owner))) {
-               fprintf(stderr, "install: unknown user %s.\n", owner);
-               exit(1);
-       }
+       if (group && !(gp = getgrnam(group)))
+               err("unknown group %s\n", group);
+       if (owner && !(pp = getpwnam(owner)))
+               err("unknown user %s\n", owner);
 
        no_target = stat(to_name = argv[argc - 1], &to_sb);
        if (!no_target && (to_sb.st_mode & S_IFMT) == S_IFDIR) {
 
        no_target = stat(to_name = argv[argc - 1], &to_sb);
        if (!no_target && (to_sb.st_mode & S_IFMT) == S_IFDIR) {
@@ -94,18 +99,13 @@ main(argc, argv)
                usage();
 
        if (!no_target) {
                usage();
 
        if (!no_target) {
-               if (stat(*argv, &from_sb)) {
-                       fprintf(stderr, "install: can't find %s.\n", *argv);
-                       exit(1);
-               }
-               if ((to_sb.st_mode & S_IFMT) != S_IFREG) {
-                       fprintf(stderr, "install: %s isn't a regular file.\n", to_name);
-                       exit(1);
-               }
-               if (to_sb.st_dev == from_sb.st_dev && to_sb.st_ino == from_sb.st_ino) {
-                       fprintf(stderr, "install: %s and %s are the same file.\n", *argv, to_name);
-                       exit(1);
-               }
+               if (stat(*argv, &from_sb))
+                       err("%s: %s\n", *argv, strerror(errno));
+               if (!S_ISREG(to_sb.st_mode))
+                       err("%s: %s\n", to_name, strerror(EFTYPE));
+               if (to_sb.st_dev == from_sb.st_dev &&
+                   to_sb.st_ino == from_sb.st_ino)
+                       err("%s and %s are the same file\n", *argv, to_name);
                /* unlink now... avoid ETXTBSY errors later */
                (void)unlink(to_name);
        }
                /* unlink now... avoid ETXTBSY errors later */
                (void)unlink(to_name);
        }
@@ -117,46 +117,42 @@ main(argc, argv)
  * install --
  *     build a path name and install the file
  */
  * install --
  *     build a path name and install the file
  */
+void
 install(from_name, to_name, isdir)
        char *from_name, *to_name;
        int isdir;
 {
        struct stat from_sb;
 install(from_name, to_name, isdir)
        char *from_name, *to_name;
        int isdir;
 {
        struct stat from_sb;
-       int devnull, from_fd, to_fd;
-       char *C, *rindex();
+       int devnull, from_fd, to_fd, serrno;
+       char *p;
 
 
-       /* if try to install NULL file to a directory, fails */
+       /* If try to install NULL file to a directory, fails. */
        if (isdir || strcmp(from_name, _PATH_DEVNULL)) {
        if (isdir || strcmp(from_name, _PATH_DEVNULL)) {
-               if (stat(from_name, &from_sb)) {
-                       fprintf(stderr, "install: can't find %s.\n", from_name);
-                       exit(1);
-               }
-               if ((from_sb.st_mode & S_IFMT) != S_IFREG) {
-                       fprintf(stderr, "install: %s isn't a regular file.\n", from_name);
-                       exit(1);
-               }
-               /* build the target path */
+               if (stat(from_name, &from_sb))
+                       err("%s: %s\n", from_name, strerror(errno));
+               if (!S_ISREG(from_sb.st_mode))
+                       err("%s: %s\n", from_name, strerror(EFTYPE));
+               /* Build the target path. */
                if (isdir) {
                if (isdir) {
-                       (void)sprintf(pathbuf, "%s/%s", to_name, (C = rindex(from_name, '/')) ? ++C : from_name);
+                       (void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
+                           to_name,
+                           (p = rindex(from_name, '/')) ? ++p : from_name);
                        to_name = pathbuf;
                }
                devnull = 0;
        } else
                devnull = 1;
 
                        to_name = pathbuf;
                }
                devnull = 0;
        } else
                devnull = 1;
 
-       /* unlink now... avoid ETXTBSY errors later */
+       /* Unlink now... avoid ETXTBSY errors later. */
        (void)unlink(to_name);
 
        (void)unlink(to_name);
 
-       /* create target */
-       if ((to_fd = open(to_name, O_CREAT|O_WRONLY|O_TRUNC, 0600)) < 0) {
-               error(to_name);
-               exit(1);
-       }
+       /* Create target. */
+       if ((to_fd = open(to_name, O_CREAT|O_WRONLY|O_TRUNC, 0600)) < 0)
+               err("%s: %s", to_name, strerror(errno));
        if (!devnull) {
                if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
                        (void)unlink(to_name);
        if (!devnull) {
                if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
                        (void)unlink(to_name);
-                       error(from_name);
-                       exit(1);
+                       err("%s: %s", from_name, strerror(errno));
                }
                copy(from_fd, from_name, to_fd, to_name);
                (void)close(from_fd);
                }
                copy(from_fd, from_name, to_fd, to_name);
                (void)close(from_fd);
@@ -164,41 +160,52 @@ install(from_name, to_name, isdir)
        if (dostrip)
                strip(to_name);
        /*
        if (dostrip)
                strip(to_name);
        /*
-        * set owner, group, mode for target; do the chown first,
+        * Set owner, group, mode for target; do the chown first,
         * chown may lose the setuid bits.
         */
        if ((group || owner) &&
            fchown(to_fd, owner ? pp->pw_uid : -1, group ? gp->gr_gid : -1) ||
            fchmod(to_fd, mode)) {
         * chown may lose the setuid bits.
         */
        if ((group || owner) &&
            fchown(to_fd, owner ? pp->pw_uid : -1, group ? gp->gr_gid : -1) ||
            fchmod(to_fd, mode)) {
-               error(to_name);
-               bad(to_name);
+               serrno = errno;
+               (void)unlink(to_name);
+               err("%s: %s", to_name, strerror(serrno));
        }
        }
-       (void)close(to_fd);
-       if (!docopy && !devnull && unlink(from_name)) {
-               error(from_name);
-               exit(1);
+
+       /* Always preserve the flags. */
+       if (fchflags(to_fd, from_sb.st_flags)) {
+               serrno = errno;
+               (void)unlink(to_name);
+               err("%s: %s", to_name, strerror(serrno));
        }
        }
+
+       (void)close(to_fd);
+       if (!docopy && !devnull && unlink(from_name))
+               err("%s: %s", from_name, strerror(errno));
 }
 
 /*
  * copy --
  *     copy from one file to another
  */
 }
 
 /*
  * copy --
  *     copy from one file to another
  */
+void
 copy(from_fd, from_name, to_fd, to_name)
        register int from_fd, to_fd;
        char *from_name, *to_name;
 {
 copy(from_fd, from_name, to_fd, to_name)
        register int from_fd, to_fd;
        char *from_name, *to_name;
 {
-       register int n;
+       register int nr, nw;
+       int serrno;
        char buf[MAXBSIZE];
 
        char buf[MAXBSIZE];
 
-       while ((n = read(from_fd, buf, sizeof(buf))) > 0)
-               if (write(to_fd, buf, n) != n) {
-                       error(to_name);
-                       bad(to_name);
+       while ((nr = read(from_fd, buf, sizeof(buf))) > 0)
+               if ((nw = write(to_fd, buf, nr)) != nr) {
+                       serrno = errno;
+                       (void)unlink(to_name);
+                       err("%s: %s", to_name, strerror(nw > 0 ? EIO : serrno));
                }
                }
-       if (n == -1) {
-               error(from_name);
-               bad(to_name);
+       if (nr != 0) {
+               serrno = errno;
+               (void)unlink(to_name);
+               err("%s: %s", from_name, strerror(serrno));
        }
 }
 
        }
 }
 
@@ -206,56 +213,63 @@ copy(from_fd, from_name, to_fd, to_name)
  * strip --
  *     use strip(1) to strip the target file
  */
  * strip --
  *     use strip(1) to strip the target file
  */
+void
 strip(to_name)
        char *to_name;
 {
 strip(to_name)
        char *to_name;
 {
-       int status;
+       int serrno, status;
 
        switch (vfork()) {
        case -1:
 
        switch (vfork()) {
        case -1:
-               error("fork");
-               bad(to_name);
+               serrno = errno;
+               (void)unlink(to_name);
+               err("forks: %s", strerror(errno));
        case 0:
        case 0:
-               execl(_PATH_STRIP, "strip", to_name, (char *)NULL);
-               error(_PATH_STRIP);
-               _exit(1);
+               execl(_PATH_STRIP, "strip", to_name, NULL);
+               err("%s: %s", _PATH_STRIP, strerror(errno));
        default:
                if (wait(&status) == -1 || status)
        default:
                if (wait(&status) == -1 || status)
-                       bad(to_name);
+                       (void)unlink(to_name);
        }
 }
 
        }
 }
 
-/*
- * error --
- *     print out an error message
- */
-error(s)
-       char *s;
-{
-       extern int errno;
-       char *strerror();
-
-       (void)fprintf(stderr, "install: %s: %s\n", s, strerror(errno));
-}
-
-/*
- * bad --
- *     remove created target and die
- */
-bad(fname)
-       char *fname;
-{
-       (void)unlink(fname);
-       exit(1);
-}
-
 /*
  * usage --
  *     print a usage message and die
  */
 /*
  * usage --
  *     print a usage message and die
  */
+void
 usage()
 {
        (void)fprintf(stderr,
 "usage: install [-cs] [-g group] [-m mode] [-o owner] file1 file2;\n\tor file1 ... fileN directory\n");
        exit(1);
 }
 usage()
 {
        (void)fprintf(stderr,
 "usage: install [-cs] [-g group] [-m mode] [-o owner] file1 file2;\n\tor file1 ... fileN directory\n");
        exit(1);
 }
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+err(const char *fmt, ...)
+#else
+err(fmt, va_alist)
+       char *fmt;
+        va_dcl
+#endif
+{
+       va_list ap;
+#if __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       (void)fprintf(stderr, "install: ");
+       (void)vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       (void)fprintf(stderr, "\n");
+       exit(1);
+       /* NOTREACHED */
+}