home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / xinstall / xinstall.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-16  |  6.7 KB  |  288 lines

  1. /*
  2.  * Copyright (c) 1987 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1987 Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)xinstall.c    5.24 (Berkeley) 7/1/90";
  42. #endif /* not lint */
  43.  
  44. #include <sys/param.h>
  45. #include <sys/stat.h>
  46. #include <sys/file.h>
  47. #include <grp.h>
  48. #include <pwd.h>
  49. #include <stdio.h>
  50. #include <ctype.h>
  51. #include <paths.h>
  52. #include "pathnames.h"
  53.  
  54. static struct passwd *pp;
  55. static struct group *gp;
  56. static int docopy, dostrip, mode = 0755;
  57. static char *group, *owner, pathbuf[MAXPATHLEN];
  58.  
  59. main(argc, argv)
  60.     int argc;
  61.     char **argv;
  62. {
  63.     extern char *optarg;
  64.     extern int optind;
  65.     struct stat from_sb, to_sb;
  66.     mode_t *set, *setmode();
  67.     int ch, no_target;
  68.     char *to_name;
  69.  
  70.     while ((ch = getopt(argc, argv, "cg:m:o:s")) != EOF)
  71.         switch((char)ch) {
  72.         case 'c':
  73.             docopy = 1;
  74.             break;
  75.         case 'g':
  76.             group = optarg;
  77.             break;
  78.         case 'm':
  79.             if (!(set = setmode(optarg))) {
  80.                 (void)fprintf(stderr,
  81.                     "install: invalid file mode.\n");
  82.                 exit(1);
  83.             }
  84.             mode = getmode(set, 0);
  85.             break;
  86.         case 'o':
  87.             owner = optarg;
  88.             break;
  89.         case 's':
  90.             dostrip = 1;
  91.             break;
  92.         case '?':
  93.         default:
  94.             usage();
  95.         }
  96.     argc -= optind;
  97.     argv += optind;
  98.     if (argc < 2)
  99.         usage();
  100.  
  101.     /* get group and owner id's */
  102.     if (group && !(gp = getgrnam(group))) {
  103.         fprintf(stderr, "install: unknown group %s.\n", group);
  104.         exit(1);
  105.     }
  106.     if (owner && !(pp = getpwnam(owner))) {
  107.         fprintf(stderr, "install: unknown user %s.\n", owner);
  108.         exit(1);
  109.     }
  110.  
  111.     no_target = stat(to_name = argv[argc - 1], &to_sb);
  112.     if (!no_target && (to_sb.st_mode & S_IFMT) == S_IFDIR) {
  113.         for (; *argv != to_name; ++argv)
  114.             install(*argv, to_name, 1);
  115.         exit(0);
  116.     }
  117.  
  118.     /* can't do file1 file2 directory/file */
  119.     if (argc != 2)
  120.         usage();
  121.  
  122.     if (!no_target) {
  123.         if (stat(*argv, &from_sb)) {
  124.             fprintf(stderr, "install: can't find %s.\n", *argv);
  125.             exit(1);
  126.         }
  127.         if ((to_sb.st_mode & S_IFMT) != S_IFREG) {
  128.             fprintf(stderr, "install: %s isn't a regular file.\n", to_name);
  129.             exit(1);
  130.         }
  131.         if (to_sb.st_dev == from_sb.st_dev && to_sb.st_ino == from_sb.st_ino) {
  132.             fprintf(stderr, "install: %s and %s are the same file.\n", *argv, to_name);
  133.             exit(1);
  134.         }
  135.         /* unlink now... avoid ETXTBSY errors later */
  136.         (void)unlink(to_name);
  137.     }
  138.     install(*argv, to_name, 0);
  139.     exit(0);
  140. }
  141.  
  142. /*
  143.  * install --
  144.  *    build a path name and install the file
  145.  */
  146. install(from_name, to_name, isdir)
  147.     char *from_name, *to_name;
  148.     int isdir;
  149. {
  150.     struct stat from_sb;
  151.     int devnull, from_fd, to_fd;
  152.     char *C, *rindex();
  153.  
  154.     /* if try to install NULL file to a directory, fails */
  155.     if (isdir || strcmp(from_name, _PATH_DEVNULL)) {
  156.         if (stat(from_name, &from_sb)) {
  157.             fprintf(stderr, "install: can't find %s.\n", from_name);
  158.             exit(1);
  159.         }
  160.         if ((from_sb.st_mode & S_IFMT) != S_IFREG) {
  161.             fprintf(stderr, "install: %s isn't a regular file.\n", from_name);
  162.             exit(1);
  163.         }
  164.         /* build the target path */
  165.         if (isdir) {
  166.             (void)sprintf(pathbuf, "%s/%s", to_name, (C = rindex(from_name, '/')) ? ++C : from_name);
  167.             to_name = pathbuf;
  168.         }
  169.         devnull = 0;
  170.     } else
  171.         devnull = 1;
  172.  
  173.     /* unlink now... avoid ETXTBSY errors later */
  174.     (void)unlink(to_name);
  175.  
  176.     /* create target */
  177.     if ((to_fd = open(to_name, O_CREAT|O_WRONLY|O_TRUNC, 0600)) < 0) {
  178.         error(to_name);
  179.         exit(1);
  180.     }
  181.     if (!devnull) {
  182.         if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
  183.             (void)unlink(to_name);
  184.             error(from_name);
  185.             exit(1);
  186.         }
  187.         copy(from_fd, from_name, to_fd, to_name);
  188.         (void)close(from_fd);
  189.     }
  190.     if (dostrip)
  191.         strip(to_name);
  192.     /*
  193.      * set owner, group, mode for target; do the chown first,
  194.      * chown may lose the setuid bits.
  195.      */
  196.     if ((group || owner) &&
  197.         fchown(to_fd, owner ? pp->pw_uid : -1, group ? gp->gr_gid : -1) ||
  198.         fchmod(to_fd, mode)) {
  199.         error(to_name);
  200.         bad(to_name);
  201.     }
  202.     (void)close(to_fd);
  203.     if (!docopy && !devnull && unlink(from_name)) {
  204.         error(from_name);
  205.         exit(1);
  206.     }
  207. }
  208.  
  209. /*
  210.  * copy --
  211.  *    copy from one file to another
  212.  */
  213. copy(from_fd, from_name, to_fd, to_name)
  214.     register int from_fd, to_fd;
  215.     char *from_name, *to_name;
  216. {
  217.     register int n;
  218.     char buf[MAXBSIZE];
  219.  
  220.     while ((n = read(from_fd, buf, sizeof(buf))) > 0)
  221.         if (write(to_fd, buf, n) != n) {
  222.             error(to_name);
  223.             bad(to_name);
  224.         }
  225.     if (n == -1) {
  226.         error(from_name);
  227.         bad(to_name);
  228.     }
  229. }
  230.  
  231. /*
  232.  * strip --
  233.  *    use strip(1) to strip the target file
  234.  */
  235. strip(to_name)
  236.     char *to_name;
  237. {
  238.     int status;
  239.  
  240.     switch (vfork()) {
  241.     case -1:
  242.         error("fork");
  243.         bad(to_name);
  244.     case 0:
  245.         execl(_PATH_STRIP, "strip", to_name, (char *)NULL);
  246.         error(_PATH_STRIP);
  247.         _exit(1);
  248.     default:
  249.         if (wait(&status) == -1 || status)
  250.             bad(to_name);
  251.     }
  252. }
  253.  
  254. /*
  255.  * error --
  256.  *    print out an error message
  257.  */
  258. error(s)
  259.     char *s;
  260. {
  261.     extern int errno;
  262.     char *strerror();
  263.  
  264.     (void)fprintf(stderr, "install: %s: %s\n", s, strerror(errno));
  265. }
  266.  
  267. /*
  268.  * bad --
  269.  *    remove created target and die
  270.  */
  271. bad(fname)
  272.     char *fname;
  273. {
  274.     (void)unlink(fname);
  275.     exit(1);
  276. }
  277.  
  278. /*
  279.  * usage --
  280.  *    print a usage message and die
  281.  */
  282. usage()
  283. {
  284.     (void)fprintf(stderr,
  285. "usage: install [-cs] [-g group] [-m mode] [-o owner] file1 file2;\n\tor file1 ... fileN directory\n");
  286.     exit(1);
  287. }
  288.