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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1996 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include <sys/param.h> 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 #include <sys/file.h> 46 #include <fcntl.h> 47 #include <grp.h> 48 #include <pwd.h> 49 #include <stdio.h> 50 #include <ctype.h> 51 #include <errno.h> 52 #include <locale.h> 53 54 #define DEF_GROUP "staff" /* default group */ 55 #define DEF_OWNER "root" /* default owner */ 56 #define DEF_MODE 0755 /* default mode */ 57 58 char *group = DEF_GROUP; 59 char *owner = DEF_OWNER; 60 int mode = DEF_MODE; 61 int sflag = 0; 62 struct passwd *pp; 63 struct group *gp; 64 extern int errno; 65 int copy(); 66 void usage(); 67 68 int 69 main(int argc, char **argv) 70 { 71 extern char *optarg; 72 extern int optind; 73 struct stat stb; 74 char *dirname; 75 int ch; 76 int i; 77 int rc; 78 int dflag = 0; 79 int gflag = 0; 80 int oflag = 0; 81 int mflag = 0; 82 83 (void) setlocale(LC_ALL, ""); 84 85 #if !defined(TEXT_DOMAIN) 86 #define TEXT_DOMAIN "SYS_TEST" 87 #endif 88 (void) textdomain(TEXT_DOMAIN); 89 90 while ((ch = getopt(argc, argv, "dcg:o:m:s")) != EOF) 91 switch((char)ch) { 92 case 'c': 93 break; /* always do "copy" */ 94 case 'd': 95 dflag++; 96 break; 97 case 'g': 98 gflag++; 99 group = optarg; 100 break; 101 case 'm': 102 mflag++; 103 mode = atoo(optarg); 104 break; 105 case 'o': 106 oflag++; 107 owner = optarg; 108 break; 109 case 's': 110 sflag++; 111 break; 112 case '?': 113 default: 114 usage(); 115 } 116 argc -= optind; 117 argv += optind; 118 119 /* get group and owner id's */ 120 if (!(gp = getgrnam(group))) { 121 fprintf(stderr, gettext("install: unknown group %s.\n"), group); 122 exit(1); 123 } 124 if (!(pp = getpwnam(owner))) { 125 fprintf(stderr, gettext("install: unknown user %s.\n"), owner); 126 exit(1); 127 } 128 129 if (dflag) { /* install a directory */ 130 int exists = 0; 131 132 if (argc != 1) 133 usage(); 134 dirname = argv[0]; 135 if (mkdirp(dirname, 0777) < 0) { 136 exists = errno == EEXIST; 137 if (!exists) { 138 fprintf(stderr, gettext("install: mkdir: %s: %s\n"), dirname, strerror(errno)); 139 exit(1); 140 } 141 } 142 if (stat(dirname, &stb) < 0) { 143 fprintf(stderr, gettext("install: stat: %s: %s\n"), dirname, strerror(errno)); 144 exit(1); 145 } 146 if ((stb.st_mode&S_IFMT) != S_IFDIR) { 147 fprintf(stderr, gettext("install: %s is not a directory\n"), dirname); 148 } 149 /* make sure directory setgid bit is inherited */ 150 mode = (mode & ~S_ISGID) | (stb.st_mode & S_ISGID); 151 if (mflag && chmod(dirname, mode)) { 152 fprintf(stderr, gettext("install: chmod: %s: %s\n"), dirname, strerror(errno)); 153 if (!exists) 154 (void) unlink(dirname); 155 exit(1) ; 156 } 157 if (oflag && chown(dirname, pp->pw_uid, -1) && errno != EPERM) { 158 fprintf(stderr, gettext("install: chown: %s: %s\n"), dirname, strerror(errno)); 159 if (!exists) 160 (void) unlink(dirname); 161 exit(1) ; 162 } 163 if (gflag && chown(dirname, -1, gp->gr_gid) && errno != EPERM) { 164 fprintf(stderr, gettext("install: chgrp: %s: %s\n"), dirname, strerror(errno)); 165 if (!exists) 166 (void) unlink(dirname); 167 exit(1) ; 168 } 169 exit(0); 170 } 171 172 if (argc < 2) 173 usage(); 174 175 if (argc > 2) { /* last arg must be a directory */ 176 if (stat(argv[argc-1], &stb) < 0) 177 usage(); 178 if ((stb.st_mode&S_IFMT) != S_IFDIR) 179 usage(); 180 } 181 rc = 0; 182 for (i = 0; i < argc-1; i++) 183 rc |= install(argv[i], argv[argc-1]); 184 return (rc); 185 } 186 187 int 188 install(from, to) 189 char *from, *to; 190 { 191 int to_fd; 192 int devnull; 193 int status = 0; 194 char *path; 195 struct stat from_sb, to_sb; 196 static char pbuf[MAXPATHLEN]; 197 char buf[MAXPATHLEN + 10]; 198 199 /* check source */ 200 if (stat(from, &from_sb)) { 201 fprintf(stderr, gettext("install: %s: %s\n"), from, strerror(errno)); 202 return (1); 203 } 204 /* special case for removing files */ 205 devnull = !strcmp(from, "/dev/null"); 206 if (!devnull && !((from_sb.st_mode&S_IFMT) == S_IFREG)) { 207 fprintf(stderr, gettext("install: %s isn't a regular file.\n"), from); 208 return (1); 209 } 210 211 /* build target path, find out if target is same as source */ 212 if (!stat(path = to, &to_sb)) { 213 if ((to_sb.st_mode&S_IFMT) == S_IFDIR) { 214 char *C, *strrchr(); 215 216 (void) sprintf(path = pbuf, "%s/%s", to, (C = strrchr(from, '/')) ? ++C : from); 217 if (stat(path, &to_sb)) 218 goto nocompare; 219 } 220 if ((to_sb.st_mode&S_IFMT) != S_IFREG) { 221 fprintf(stderr, gettext("install: %s isn't a regular file.\n"), path); 222 return (1); 223 } 224 if (to_sb.st_dev == from_sb.st_dev && to_sb.st_ino == from_sb.st_ino) { 225 fprintf(stderr, gettext("install: %s and %s are the same file.\n"), from, path); 226 return (1); 227 } 228 /* unlink now... avoid ETXTBSY errors later */ 229 (void) unlink(path); 230 } 231 232 nocompare: 233 /* open target, set mode, owner, group */ 234 if ((to_fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0)) < 0) { 235 fprintf(stderr, gettext("install: %s: %s\n"), path, strerror(errno)); 236 return (1); 237 } 238 if (fchmod(to_fd, mode)) { 239 fprintf(stderr, gettext("install: chmod: %s: %s\n"), path, strerror(errno)); 240 status = 1; 241 close(to_fd); 242 goto inst_done; 243 } 244 if (!devnull) { 245 status = copy(from, to_fd, path); /* copy */ 246 close(to_fd); 247 } 248 if (sflag) { 249 sprintf(buf, "strip %s", path); 250 system(buf); 251 } 252 if (chown(path, pp->pw_uid, gp->gr_gid) && errno != EPERM) { 253 fprintf(stderr, gettext("install: chown: %s: %s\n"), path, strerror(errno)); 254 status = 1; 255 } 256 257 inst_done: 258 if (status) 259 (void) unlink(path); 260 return (status); 261 } 262 263 /* 264 * copy -- 265 * copy from one file to another 266 */ 267 int 268 copy(from_name, to_fd, to_name) 269 int to_fd; 270 char *from_name, *to_name; 271 { 272 int n, from_fd; 273 int status = 0; 274 char buf[MAXBSIZE]; 275 276 if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) { 277 fprintf(stderr, gettext("install: open: %s: %s\n"), from_name, strerror(errno)); 278 return (1); 279 } 280 while ((n = read(from_fd, buf, sizeof(buf))) > 0) 281 if (write(to_fd, buf, n) != n) { 282 fprintf(stderr, gettext("install: write: %s: %s\n"), to_name, strerror(errno)); 283 status = 1; 284 goto copy_done; 285 } 286 if (n == -1) { 287 fprintf(stderr, gettext("install: read: %s: %s\n"), from_name, strerror(errno)); 288 status = 1; 289 goto copy_done; 290 } 291 292 copy_done: 293 (void) close(from_fd); 294 return (status); 295 } 296 297 /* 298 * atoo -- 299 * octal string to int 300 */ 301 int 302 atoo(str) 303 char *str; 304 { 305 int val; 306 307 for (val = 0; isdigit(*str); ++str) 308 val = val * 8 + *str - '0'; 309 return(val); 310 } 311 312 313 /* 314 * usage -- 315 * print a usage message and die 316 */ 317 void 318 usage() 319 { 320 fputs(gettext("usage: install [-cs] [-g group] [-m mode] [-o owner] file ... destination\n"), stderr); 321 fputs(gettext(" install -d [-g group] [-m mode] [-o owner] dir\n"), stderr); 322 exit(1); 323 } 324 325 /* 326 * mkdirp -- 327 * make a directory and parents if needed 328 */ 329 int 330 mkdirp(dir, mode) 331 char *dir; 332 int mode; 333 { 334 int err; 335 char *slash; 336 char *strrchr(); 337 extern int errno; 338 339 if (mkdir(dir, mode) == 0) 340 return (0); 341 if (errno != ENOENT) 342 return (-1); 343 slash = strrchr(dir, '/'); 344 if (slash == NULL) 345 return (-1); 346 *slash = '\0'; 347 err = mkdirp(dir, 0777); 348 *slash = '/'; 349 if (err) 350 return (err); 351 return mkdir(dir, mode); 352 } 353