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 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <strings.h>
  29 #include <sys/param.h>
  30 #include <fcntl.h>
  31 #include <sys/errno.h>
  32 #include <sys/types.h>
  33 #include <sys/uio.h>
  34 #include <unistd.h>
  35 #include <sys/stat.h>
  36 #include <errno.h>
  37 #include <libgen.h>
  38 #include "stdusers.h"
  39 
  40 
  41 #define FILE_BUFF       40960
  42 
  43 static int suppress = 0;
  44 
  45 static void usage(void);
  46 static void file_copy(char *src_file, char *dest_file);
  47 static void chown_file(const char *file, const char *group, const char *owner);
  48 static void formclosed(char *root, char *closedroot);
  49 static char *find_basename(const char *str);
  50 static int creatdir(char *fn);
  51 
  52 
  53 void
  54 usage(void)
  55 {
  56         (void) fprintf(stderr,
  57             "usage: install [-sdO][-m mode][-g group][-u owner] "
  58             "-f dir file ...\n");
  59 }
  60 
  61 void
  62 file_copy(char *src_file, char *dest_file)
  63 {
  64         int     src_fd;
  65         int     dest_fd;
  66         int     count;
  67         static char file_buff[FILE_BUFF];
  68 
  69         if ((src_fd = open(src_file, O_RDONLY))  == -1) {
  70                 (void) fprintf(stderr, "install:file_copy: %s failed "
  71                     "(%d): %s\n", src_file, errno, strerror(errno));
  72                 exit(1);
  73         }
  74 
  75         if ((dest_fd = open(dest_file, O_CREAT|O_WRONLY|O_TRUNC, 0755)) == -1) {
  76                 (void) fprintf(stderr, "install:file_copy: %s failed "
  77                     "(%d): %s\n", dest_file, errno, strerror(errno));
  78                 exit(1);
  79         }
  80 
  81         while ((count = read(src_fd, file_buff, FILE_BUFF)) > 0) {
  82                 (void) write(dest_fd, file_buff, count);
  83         }
  84 
  85         if (count == -1) {
  86                 (void) fprintf(stderr, "install:file_copy:read failed "
  87                     "(%d): %s\n", errno, strerror(errno));
  88                 exit(1);
  89         }
  90 
  91         if (!suppress)
  92                 (void) printf("%s installed as %s\n", src_file, dest_file);
  93 
  94         (void) close(src_fd);
  95         (void) close(dest_fd);
  96 }
  97 
  98 
  99 void
 100 chown_file(const char *file, const char *group, const char *owner)
 101 {
 102         gid_t   grp = (gid_t)-1;
 103         uid_t   own = (uid_t)-1;
 104 
 105         if (group) {
 106                 grp = stdfind(group, groupnames);
 107                 if (grp < 0)
 108                         (void) fprintf(stderr, "unknown group(%s)\n", group);
 109         }
 110 
 111         if (owner) {
 112                 own = stdfind(owner, usernames);
 113                 if (own < 0) {
 114                         (void) fprintf(stderr, "unknown owner(%s)\n", owner);
 115                         exit(1);
 116                 }
 117 
 118         }
 119 
 120         if (chown(file, own, grp) == -1) {
 121                 (void) fprintf(stderr, "install:chown_file: failed "
 122                     "(%d): %s\n", errno, strerror(errno));
 123                 exit(1);
 124         }
 125 }
 126 
 127 
 128 void
 129 formclosed(char *root, char *closedroot)
 130 {
 131         int wholelen, residlen;
 132         char *temp;
 133 
 134         wholelen = strlen(root);
 135         temp = strstr(strstr(root, "proto/root_"), "/");
 136         temp++;
 137         temp = strstr(temp, "/");
 138         residlen = strlen(temp);
 139         (void) strlcpy(closedroot, root, wholelen - residlen + 1);
 140         (void) strlcat(closedroot, "-closed", MAXPATHLEN);
 141         (void) strlcat(closedroot, temp, MAXPATHLEN);
 142 }
 143 
 144 
 145 char *
 146 find_basename(const char *str)
 147 {
 148         int     i;
 149         int     len;
 150 
 151         len = strlen(str);
 152 
 153         for (i = len-1; i >= 0; i--)
 154                 if (str[i] == '/')
 155                         return ((char *)(str + i + 1));
 156         return ((char *)str);
 157 }
 158 
 159 int
 160 creatdir(char *fn) {
 161 
 162         errno = 0;
 163 
 164         if (mkdirp(fn, 0755) == -1) {
 165                 if (errno != EEXIST)
 166                         return (errno);
 167         } else if (!suppress) {
 168                 (void) printf("directory %s created\n", fn);
 169         }
 170         return (0);
 171 }
 172 
 173 
 174 int
 175 main(int argc, char **argv)
 176 {
 177         int     c;
 178         int     errflg = 0;
 179         int     dirflg = 0;
 180         char    *group = NULL;
 181         char    *owner = NULL;
 182         char    *dirb = NULL;
 183         char    *ins_file = NULL;
 184         int     mode = -1;
 185         char    dest_file[MAXPATHLEN];
 186         char    shadow_dest[MAXPATHLEN];
 187         char    shadow_dirb[MAXPATHLEN];
 188         int     tonic = 0;
 189         int     rv = 0;
 190 
 191         while ((c = getopt(argc, argv, "f:sm:du:g:O")) != EOF) {
 192                 switch (c) {
 193                 case 'f':
 194                         dirb = optarg;
 195                         break;
 196                 case 'g':
 197                         group = optarg;
 198                         break;
 199                 case 'u':
 200                         owner = optarg;
 201                         break;
 202                 case 'd':
 203                         dirflg = 1;
 204                         break;
 205                 case 'm':
 206                         mode = strtol(optarg, NULL, 8);
 207                         break;
 208                 case 's':
 209                         suppress = 1;
 210                         break;
 211                 case 'O':
 212                         tonic = 1;
 213                         break;
 214                 case '?':
 215                         errflg++;
 216                         break;
 217                 }
 218         }
 219 
 220         if (errflg) {
 221                 usage();
 222                 return (1);
 223         }
 224 
 225         if (argc == optind) {
 226                 usage();
 227                 return (1);
 228         }
 229 
 230         if (!dirflg && (dirb == NULL)) {
 231                 (void) fprintf(stderr,
 232                     "install: no destination directory specified.\n");
 233                 return (1);
 234         }
 235 
 236         for (c = optind; c < argc; c++) {
 237                 ins_file = argv[c];
 238 
 239                 if (dirflg) {
 240                         if (tonic) {
 241                                 formclosed(ins_file, shadow_dest);
 242                                 rv = creatdir(shadow_dest);
 243                                 if (rv) {
 244                                         (void) fprintf(stderr,
 245                                             "install: tonic creatdir "
 246                                             "%s (%d): (%s)\n",
 247                                             shadow_dest, errno,
 248                                             strerror(errno));
 249                                         return (rv);
 250                                 }
 251                         }
 252                         rv = creatdir(ins_file);
 253                         if (rv) {
 254                                 (void) fprintf(stderr,
 255                                     "install: creatdir %s (%d): %s\n",
 256                                     ins_file, errno, strerror(errno));
 257                                 return (rv);
 258                         }
 259                         (void) strlcpy(dest_file, ins_file, MAXPATHLEN);
 260 
 261                 } else {
 262                         (void) strcat(strcat(strcpy(dest_file, dirb), "/"),
 263                             find_basename(ins_file));
 264                         file_copy(ins_file, dest_file);
 265 
 266                         if (tonic) {
 267                                 formclosed(dirb, shadow_dirb);
 268                                 /*
 269                                  * The standard directories in the proto
 270                                  * area are created as part of "make setup",
 271                                  * but that doesn't create them in the
 272                                  * closed proto area. So if the target
 273                                  * directory doesn't exist, we need to
 274                                  * create it now.
 275                                  */
 276                                 rv = creatdir(shadow_dirb);
 277                                 if (rv) {
 278                                         (void) fprintf(stderr,
 279                                             "install: tonic creatdir(f) "
 280                                             "%s (%d): %s\n",
 281                                             shadow_dirb, errno,
 282                                             strerror(errno));
 283                                         return (rv);
 284                                 }
 285                                 (void) strcat(strcat(strcpy(shadow_dest,
 286                                     shadow_dirb), "/"),
 287                                     find_basename(ins_file));
 288                                 file_copy(ins_file, shadow_dest);
 289                         }
 290                 }
 291 
 292                 if (group || owner) {
 293                         chown_file(dest_file, group, owner);
 294                         if (tonic)
 295                                 chown_file(shadow_dest, group, owner);
 296                 }
 297                 if (mode != -1) {
 298                         (void) umask(0);
 299                         if (chmod(dest_file, mode) == -1) {
 300                                 (void) fprintf(stderr,
 301                                     "install: chmod of %s to mode %o failed "
 302                                     "(%d): %s\n",
 303                                     dest_file, mode, errno, strerror(errno));
 304                                 return (1);
 305                         }
 306                         if (tonic) {
 307                                 if (chmod(shadow_dest, mode) == -1) {
 308                                         (void) fprintf(stderr,
 309                                             "install: tonic chmod of %s "
 310                                             "to mode %o failed (%d): %s\n",
 311                                             shadow_dest, mode,
 312                                             errno, strerror(errno));
 313                                         return (1);
 314                                 }
 315                         }
 316                 }
 317         }
 318         return (0);
 319 }