1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 /*
  26  * Copyright (c) 2018, Joyent, Inc.
  27  */
  28 
  29 #include <stdio.h>
  30 #include <stdlib.h>
  31 #include <strings.h>
  32 #include <sys/param.h>
  33 #include <fcntl.h>
  34 #include <sys/errno.h>
  35 #include <sys/types.h>
  36 #include <sys/uio.h>
  37 #include <unistd.h>
  38 #include <sys/stat.h>
  39 #include <errno.h>
  40 #include <libgen.h>
  41 #include "stdusers.h"
  42 
  43 
  44 #define FILE_BUFF       40960
  45 
  46 static int suppress = 0;
  47 
  48 static void usage(void);
  49 static void file_copy(char *src_file, char *dest_file);
  50 static void chown_file(const char *file, const char *group, const char *owner);
  51 static char *find_basename(const char *str);
  52 static int creatdir(char *fn);
  53 
  54 
  55 void
  56 usage(void)
  57 {
  58         (void) fprintf(stderr,
  59             "usage: install [-sd][-m mode][-g group][-u owner] "
  60             "-f dir file ...\n");
  61 }
  62 
  63 void
  64 file_copy(char *src_file, char *dest_file)
  65 {
  66         int     src_fd;
  67         int     dest_fd;
  68         int     count;
  69         static char file_buff[FILE_BUFF];
  70 
  71         if ((src_fd = open(src_file, O_RDONLY))  == -1) {
  72                 (void) fprintf(stderr, "install:file_copy: %s failed "
  73                     "(%d): %s\n", src_file, errno, strerror(errno));
  74                 exit(1);
  75         }
  76 
  77         if ((dest_fd = open(dest_file, O_CREAT|O_WRONLY|O_TRUNC, 0755)) == -1) {
  78                 (void) fprintf(stderr, "install:file_copy: %s failed "
  79                     "(%d): %s\n", dest_file, errno, strerror(errno));
  80                 exit(1);
  81         }
  82 
  83         while ((count = read(src_fd, file_buff, FILE_BUFF)) > 0) {
  84                 (void) write(dest_fd, file_buff, count);
  85         }
  86 
  87         if (count == -1) {
  88                 (void) fprintf(stderr, "install:file_copy:read failed "
  89                     "(%d): %s\n", errno, strerror(errno));
  90                 exit(1);
  91         }
  92 
  93         if (!suppress)
  94                 (void) printf("%s installed as %s\n", src_file, dest_file);
  95 
  96         (void) close(src_fd);
  97         (void) close(dest_fd);
  98 }
  99 
 100 
 101 void
 102 chown_file(const char *file, const char *group, const char *owner)
 103 {
 104         gid_t   grp = (gid_t)-1;
 105         uid_t   own = (uid_t)-1;
 106 
 107         if (group) {
 108                 grp = stdfind(group, groupnames);
 109                 if (grp == (gid_t)-1)
 110                         (void) fprintf(stderr, "unknown group(%s)\n", group);
 111         }
 112 
 113         if (owner) {
 114                 own = stdfind(owner, usernames);
 115                 if (own == (uid_t)-1) {
 116                         (void) fprintf(stderr, "unknown owner(%s)\n", owner);
 117                         exit(1);
 118                 }
 119 
 120         }
 121 
 122         if (chown(file, own, grp) == -1) {
 123                 (void) fprintf(stderr, "install:chown_file: failed "
 124                     "(%d): %s\n", errno, strerror(errno));
 125                 exit(1);
 126         }
 127 }
 128 
 129 
 130 char *
 131 find_basename(const char *str)
 132 {
 133         int     i;
 134         int     len;
 135 
 136         len = strlen(str);
 137 
 138         for (i = len-1; i >= 0; i--)
 139                 if (str[i] == '/')
 140                         return ((char *)(str + i + 1));
 141         return ((char *)str);
 142 }
 143 
 144 int
 145 creatdir(char *fn) {
 146 
 147         errno = 0;
 148 
 149         if (mkdirp(fn, 0755) == -1) {
 150                 if (errno != EEXIST)
 151                         return (errno);
 152         } else if (!suppress) {
 153                 (void) printf("directory %s created\n", fn);
 154         }
 155         return (0);
 156 }
 157 
 158 
 159 int
 160 main(int argc, char **argv)
 161 {
 162         int     c;
 163         int     errflg = 0;
 164         int     dirflg = 0;
 165         char    *group = NULL;
 166         char    *owner = NULL;
 167         char    *dirb = NULL;
 168         char    *ins_file = NULL;
 169         int     mode = -1;
 170         char    dest_file[MAXPATHLEN];
 171         int     rv = 0;
 172 
 173         while ((c = getopt(argc, argv, "f:sm:du:g:")) != EOF) {
 174                 switch (c) {
 175                 case 'f':
 176                         dirb = optarg;
 177                         break;
 178                 case 'g':
 179                         group = optarg;
 180                         break;
 181                 case 'u':
 182                         owner = optarg;
 183                         break;
 184                 case 'd':
 185                         dirflg = 1;
 186                         break;
 187                 case 'm':
 188                         mode = strtol(optarg, NULL, 8);
 189                         break;
 190                 case 's':
 191                         suppress = 1;
 192                         break;
 193                 case '?':
 194                         errflg++;
 195                         break;
 196                 }
 197         }
 198 
 199         if (errflg) {
 200                 usage();
 201                 return (1);
 202         }
 203 
 204         if (argc == optind) {
 205                 usage();
 206                 return (1);
 207         }
 208 
 209         if (!dirflg && (dirb == NULL)) {
 210                 (void) fprintf(stderr,
 211                     "install: no destination directory specified.\n");
 212                 return (1);
 213         }
 214 
 215         for (c = optind; c < argc; c++) {
 216                 ins_file = argv[c];
 217 
 218                 if (dirflg) {
 219                         rv = creatdir(ins_file);
 220                         if (rv) {
 221                                 (void) fprintf(stderr,
 222                                     "install: creatdir %s (%d): %s\n",
 223                                     ins_file, errno, strerror(errno));
 224                                 return (rv);
 225                         }
 226                         (void) strlcpy(dest_file, ins_file, MAXPATHLEN);
 227 
 228                 } else {
 229                         (void) strcat(strcat(strcpy(dest_file, dirb), "/"),
 230                             find_basename(ins_file));
 231                         file_copy(ins_file, dest_file);
 232                 }
 233 
 234                 if (group || owner)
 235                         chown_file(dest_file, group, owner);
 236 
 237                 if (mode != -1) {
 238                         (void) umask(0);
 239                         if (chmod(dest_file, mode) == -1) {
 240                                 (void) fprintf(stderr,
 241                                     "install: chmod of %s to mode %o failed "
 242                                     "(%d): %s\n",
 243                                     dest_file, mode, errno, strerror(errno));
 244                                 return (1);
 245                         }
 246                 }
 247         }
 248         return (0);
 249 }