BSD 4_3_Net_2 release
[unix-history] / usr / src / usr.bin / xinstall / xinstall.c
index 327b65b..2a98730 100644 (file)
@@ -2,17 +2,33 @@
  * Copyright (c) 1987 Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1987 Regents of the University of California.
  * All rights reserved.
  *
- * 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
@@ -22,59 +38,56 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)xinstall.c 5.11 (Berkeley) %G%";
+static char sccsid[] = "@(#)xinstall.c 5.24 (Berkeley) 7/1/90";
 #endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/file.h>
 #endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/file.h>
-#include <a.out.h>
 #include <grp.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <grp.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <ctype.h>
+#include <paths.h>
+#include "pathnames.h"
 
 
-#define        YES     1                       /* yes/true */
-#define        NO      0                       /* no/false */
-
-#define        PERROR(head, msg) { \
-       fputs(head, stderr); \
-       perror(msg); \
-}
-
-static struct passwd   *pp;
-static struct group    *gp;
-static int     docopy, dostrip,
-               mode = 0755;
-static char    *group, *owner,
-               pathbuf[MAXPATHLEN];
+static struct passwd *pp;
+static struct group *gp;
+static int docopy, dostrip, mode = 0755;
+static char *group, *owner, pathbuf[MAXPATHLEN];
 
 main(argc, argv)
 
 main(argc, argv)
-       int     argc;
-       char    **argv;
+       int argc;
+       char **argv;
 {
 {
-       extern char     *optarg;
-       extern int      optind;
-       struct stat     from_sb, to_sb;
-       int     ch, no_target;
-       char    *to_name;
+       extern char *optarg;
+       extern int optind;
+       struct stat from_sb, to_sb;
+       mode_t *set, *setmode();
+       int ch, no_target;
+       char *to_name;
 
        while ((ch = getopt(argc, argv, "cg:m:o:s")) != EOF)
                switch((char)ch) {
                case 'c':
 
        while ((ch = getopt(argc, argv, "cg:m:o:s")) != EOF)
                switch((char)ch) {
                case 'c':
-                       docopy = YES;
+                       docopy = 1;
                        break;
                case 'g':
                        group = optarg;
                        break;
                case 'm':
                        break;
                case 'g':
                        group = optarg;
                        break;
                case 'm':
-                       mode = atoo(optarg);
+                       if (!(set = setmode(optarg))) {
+                               (void)fprintf(stderr,
+                                   "install: invalid file mode.\n");
+                               exit(1);
+                       }
+                       mode = getmode(set, 0);
                        break;
                case 'o':
                        owner = optarg;
                        break;
                case 's':
                        break;
                case 'o':
                        owner = optarg;
                        break;
                case 's':
-                       dostrip = YES;
+                       dostrip = 1;
                        break;
                case '?':
                default:
                        break;
                case '?':
                default:
@@ -98,7 +111,7 @@ main(argc, argv)
        no_target = stat(to_name = argv[argc - 1], &to_sb);
        if (!no_target && (to_sb.st_mode & S_IFMT) == S_IFDIR) {
                for (; *argv != to_name; ++argv)
        no_target = stat(to_name = argv[argc - 1], &to_sb);
        if (!no_target && (to_sb.st_mode & S_IFMT) == S_IFDIR) {
                for (; *argv != to_name; ++argv)
-                       install(*argv, to_name, YES);
+                       install(*argv, to_name, 1);
                exit(0);
        }
 
                exit(0);
        }
 
@@ -122,7 +135,7 @@ main(argc, argv)
                /* unlink now... avoid ETXTBSY errors later */
                (void)unlink(to_name);
        }
                /* unlink now... avoid ETXTBSY errors later */
                (void)unlink(to_name);
        }
-       install(*argv, to_name, NO);
+       install(*argv, to_name, 0);
        exit(0);
 }
 
        exit(0);
 }
 
@@ -130,17 +143,16 @@ main(argc, argv)
  * install --
  *     build a path name and install the file
  */
  * install --
  *     build a path name and install the file
  */
-static
 install(from_name, to_name, isdir)
 install(from_name, to_name, isdir)
-       char    *from_name, *to_name;
-       int     isdir;
+       char *from_name, *to_name;
+       int isdir;
 {
 {
-       struct stat     from_sb;
-       int     devnull, from_fd, to_fd;
-       char    *C, *rindex();
+       struct stat from_sb;
+       int devnull, from_fd, to_fd;
+       char *C, *rindex();
 
 
-       /* if try to install "/dev/null" to a directory, fails */
-       if (isdir || strcmp(from_name, "/dev/null")) {
+       /* if try to install NULL file to a directory, fails */
+       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 (stat(from_name, &from_sb)) {
                        fprintf(stderr, "install: can't find %s.\n", from_name);
                        exit(1);
@@ -154,95 +166,43 @@ install(from_name, to_name, isdir)
                        (void)sprintf(pathbuf, "%s/%s", to_name, (C = rindex(from_name, '/')) ? ++C : from_name);
                        to_name = pathbuf;
                }
                        (void)sprintf(pathbuf, "%s/%s", to_name, (C = rindex(from_name, '/')) ? ++C : from_name);
                        to_name = pathbuf;
                }
-               devnull = NO;
-       }
-       else
-               devnull = YES;
+               devnull = 0;
+       } else
+               devnull = 1;
 
        /* unlink now... avoid ETXTBSY errors later */
        (void)unlink(to_name);
 
        /* create target */
 
        /* unlink now... avoid ETXTBSY errors later */
        (void)unlink(to_name);
 
        /* create target */
-       if ((to_fd = open(to_name, O_CREAT|O_WRONLY|O_TRUNC, 0)) < 0) {
-               PERROR("install: ", to_name);
+       if ((to_fd = open(to_name, O_CREAT|O_WRONLY|O_TRUNC, 0600)) < 0) {
+               error(to_name);
                exit(1);
        }
        if (!devnull) {
                if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
                        (void)unlink(to_name);
                exit(1);
        }
        if (!devnull) {
                if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
                        (void)unlink(to_name);
-                       PERROR("install: open: ", from_name);
+                       error(from_name);
                        exit(1);
                }
                        exit(1);
                }
-               if (dostrip)
-                       strip(from_fd, from_name, to_fd, to_name);
-               else
-                       copy(from_fd, from_name, to_fd, to_name);
+               copy(from_fd, from_name, to_fd, to_name);
                (void)close(from_fd);
                (void)close(from_fd);
-               if (!docopy)
-                       (void)unlink(from_name);
-       }
-       /* set owner, group, mode for target */
-       if (fchmod(to_fd, mode)) {
-               PERROR("install: fchmod: ", to_name);
-               bad();
        }
        }
-       if ((group || owner) && fchown(to_fd, owner ? pp->pw_uid : -1,
-           group ? gp->gr_gid : -1)) {
-               PERROR("install: fchown: ", to_name);
-               bad();
+       if (dostrip)
+               strip(to_name);
+       /*
+        * 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)) {
+               error(to_name);
+               bad(to_name);
        }
        (void)close(to_fd);
        }
        (void)close(to_fd);
-}
-
-/*
- * strip --
- *     copy file, strip(1)'ing it at the same time
- */
-static
-strip(from_fd, from_name, to_fd, to_name)
-       register int    from_fd, to_fd;
-       char    *from_name, *to_name;
-{
-       typedef struct exec     EXEC;
-       register long   size;
-       register int    n;
-       EXEC    head;
-       char    buf[MAXBSIZE];
-       off_t   lseek();
-
-       if (read(from_fd, (char *)&head, sizeof(head)) < 0 || N_BADMAG(head)) {
-               fprintf(stderr, "install: %s not in a.out format.\n", from_name);
-               bad();
-       }
-       if (head.a_syms || head.a_trsize || head.a_drsize) {
-               size = (long)head.a_text + head.a_data;
-               head.a_syms = head.a_trsize = head.a_drsize = 0;
-               if (head.a_magic == ZMAGIC)
-                       size += getpagesize() - sizeof(EXEC);
-               if (write(to_fd, (char *)&head, sizeof(EXEC)) != sizeof(EXEC)) {
-                       PERROR("install: write: ", to_name);
-                       bad();
-               }
-               for (; size; size -= n)
-                       /* sizeof(buf) guaranteed to fit in an int */
-                       if ((n = read(from_fd, buf, (int)MIN(size, sizeof(buf)))) <= 0)
-                               break;
-                       else if (write(to_fd, buf, n) != n) {
-                               PERROR("install: write: ", to_name);
-                               bad();
-                       }
-               if (size) {
-                       fprintf(stderr, "install: read: %s: premature EOF.\n", from_name);
-                       bad();
-               }
-               if (n == -1) {
-                       PERROR("install: read: ", from_name);
-                       bad();
-               }
-       }
-       else {
-               (void)lseek(from_fd, 0L, L_SET);
-               copy(from_fd, from_name, to_fd, to_name);
+       if (!docopy && !devnull && unlink(from_name)) {
+               error(from_name);
+               exit(1);
        }
 }
 
        }
 }
 
@@ -250,48 +210,68 @@ strip(from_fd, from_name, to_fd, to_name)
  * copy --
  *     copy from one file to another
  */
  * copy --
  *     copy from one file to another
  */
-static
 copy(from_fd, from_name, to_fd, to_name)
 copy(from_fd, from_name, to_fd, to_name)
-       register int    from_fd, to_fd;
-       char    *from_name, *to_name;
+       register int from_fd, to_fd;
+       char *from_name, *to_name;
 {
 {
-       register int    n;
-       char    buf[MAXBSIZE];
+       register int n;
+       char buf[MAXBSIZE];
 
        while ((n = read(from_fd, buf, sizeof(buf))) > 0)
                if (write(to_fd, buf, n) != n) {
 
        while ((n = read(from_fd, buf, sizeof(buf))) > 0)
                if (write(to_fd, buf, n) != n) {
-                       PERROR("install: write: ", to_name);
-                       bad();
+                       error(to_name);
+                       bad(to_name);
                }
        if (n == -1) {
                }
        if (n == -1) {
-               PERROR("install: read: ", from_name);
-               bad();
+               error(from_name);
+               bad(to_name);
+       }
+}
+
+/*
+ * strip --
+ *     use strip(1) to strip the target file
+ */
+strip(to_name)
+       char *to_name;
+{
+       int status;
+
+       switch (vfork()) {
+       case -1:
+               error("fork");
+               bad(to_name);
+       case 0:
+               execl(_PATH_STRIP, "strip", to_name, (char *)NULL);
+               error(_PATH_STRIP);
+               _exit(1);
+       default:
+               if (wait(&status) == -1 || status)
+                       bad(to_name);
        }
 }
 
 /*
        }
 }
 
 /*
- * atoo --
- *     octal string to int
+ * error --
+ *     print out an error message
  */
  */
-static
-atoo(str)
-       register char   *str;
+error(s)
+       char *s;
 {
 {
-       register int    val;
+       extern int errno;
+       char *strerror();
 
 
-       for (val = 0; isdigit(*str); ++str)
-               val = val * 8 + *str - '0';
-       return(val);
+       (void)fprintf(stderr, "install: %s: %s\n", s, strerror(errno));
 }
 
 /*
  * bad --
  *     remove created target and die
  */
 }
 
 /*
  * bad --
  *     remove created target and die
  */
-static
-bad()
+bad(fname)
+       char *fname;
 {
 {
-       (void)unlink(pathbuf);
+       (void)unlink(fname);
        exit(1);
 }
 
        exit(1);
 }
 
@@ -299,9 +279,9 @@ bad()
  * usage --
  *     print a usage message and die
  */
  * usage --
  *     print a usage message and die
  */
-static
 usage()
 {
 usage()
 {
-       fputs("usage: install [-cs] [-g group] [-m mode] [-o owner] file1 file2;\n\tor file1 ... fileN directory\n", stderr);
+       (void)fprintf(stderr,
+"usage: install [-cs] [-g group] [-m mode] [-o owner] file1 file2;\n\tor file1 ... fileN directory\n");
        exit(1);
 }
        exit(1);
 }