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 main(argc, argv) 69 int argc; 70 char **argv; 71 { 72 extern char *optarg; 73 extern int optind; 74 struct stat stb; 75 char *dirname; 76 int ch; 77 int i; 78 int rc; 79 int dflag = 0; 80 int gflag = 0; 81 int oflag = 0; 82 int mflag = 0; 83 84 (void) setlocale(LC_ALL, ""); 85 86 #if !defined(TEXT_DOMAIN) 87 #define TEXT_DOMAIN "SYS_TEST" 88 #endif 89 (void) textdomain(TEXT_DOMAIN); 90 91 while ((ch = getopt(argc, argv, "dcg:o:m:s")) != EOF) 92 switch((char)ch) { 93 case 'c': 94 break; /* always do "copy" */ 95 case 'd': 96 dflag++; 97 break; 98 case 'g': 99 gflag++; 100 group = optarg; 101 break; 102 case 'm': 103 mflag++; 104 mode = atoo(optarg); 105 break; 106 case 'o': 107 oflag++; 108 owner = optarg; 109 break; 110 case 's': 111 sflag++; 112 break; 113 case '?': 114 default: 115 usage(); 116 } 117 argc -= optind; 118 argv += optind; 119 120 /* get group and owner id's */ 121 if (!(gp = getgrnam(group))) { 122 fprintf(stderr, gettext("install: unknown group %s.\n"), group); 123 exit(1); 124 } 125 if (!(pp = getpwnam(owner))) { 126 fprintf(stderr, gettext("install: unknown user %s.\n"), owner); 127 exit(1); 128 } 129 130 if (dflag) { /* install a directory */ 131 int exists = 0; 132 133 if (argc != 1) 134 usage(); 135 dirname = argv[0]; 136 if (mkdirp(dirname, 0777) < 0) { 137 exists = errno == EEXIST; 138 if (!exists) { 139 fprintf(stderr, gettext("install: mkdir: %s: %s\n"), dirname, strerror(errno)); 140 exit(1); 141 } 142 } 143 if (stat(dirname, &stb) < 0) { 144 fprintf(stderr, gettext("install: stat: %s: %s\n"), dirname, strerror(errno)); 145 exit(1); 146 } 147 if ((stb.st_mode&S_IFMT) != S_IFDIR) { 148 fprintf(stderr, gettext("install: %s is not a directory\n"), dirname); 149 } 150 /* make sure directory setgid bit is inherited */ 151 mode = (mode & ~S_ISGID) | (stb.st_mode & S_ISGID); 152 if (mflag && chmod(dirname, mode)) { 153 fprintf(stderr, gettext("install: chmod: %s: %s\n"), dirname, strerror(errno)); 154 if (!exists) 155 (void) unlink(dirname); 156 exit(1) ; 157 } 158 if (oflag && chown(dirname, pp->pw_uid, -1) && errno != EPERM) { 159 fprintf(stderr, gettext("install: chown: %s: %s\n"), dirname, strerror(errno)); 160 if (!exists) 161 (void) unlink(dirname); 162 exit(1) ; 163 } 164 if (gflag && chown(dirname, -1, gp->gr_gid) && errno != EPERM) { 165 fprintf(stderr, gettext("install: chgrp: %s: %s\n"), dirname, strerror(errno)); 166 if (!exists) 167 (void) unlink(dirname); 168 exit(1) ; 169 } 170 exit(0); 171 } 172 173 if (argc < 2) 174 usage(); 175 176 if (argc > 2) { /* last arg must be a directory */ 177 if (stat(argv[argc-1], &stb) < 0) 178 usage(); 179 if ((stb.st_mode&S_IFMT) != S_IFDIR) 180 usage(); 181 } 182 rc = 0; 183 for (i = 0; i < argc-1; i++) 184 rc |= install(argv[i], argv[argc-1]); 185 exit(rc); 186 /* NOTREACHED */ 187 } 188 189 int 190 install(from, to) 191 char *from, *to; 192 { 193 int to_fd; 194 int devnull; 195 int status = 0; 196 char *path; 197 struct stat from_sb, to_sb; 198 static char pbuf[MAXPATHLEN]; 199 char buf[MAXPATHLEN + 10]; 200 201 /* check source */ 202 if (stat(from, &from_sb)) { 203 fprintf(stderr, gettext("install: %s: %s\n"), from, strerror(errno)); 204 return (1); 205 } 206 /* special case for removing files */ 207 devnull = !strcmp(from, "/dev/null"); 208 if (!devnull && !((from_sb.st_mode&S_IFMT) == S_IFREG)) { 209 fprintf(stderr, gettext("install: %s isn't a regular file.\n"), from); 210 return (1); 211 } 212 213 /* build target path, find out if target is same as source */ 214 if (!stat(path = to, &to_sb)) { 215 if ((to_sb.st_mode&S_IFMT) == S_IFDIR) { 216 char *C, *strrchr(); 217 218 (void) sprintf(path = pbuf, "%s/%s", to, (C = strrchr(from, '/')) ? ++C : from); 219 if (stat(path, &to_sb)) 220 goto nocompare; 221 } 222 if ((to_sb.st_mode&S_IFMT) != S_IFREG) { 223 fprintf(stderr, gettext("install: %s isn't a regular file.\n"), path); 224 return (1); 225 } 226 if (to_sb.st_dev == from_sb.st_dev && to_sb.st_ino == from_sb.st_ino) { 227 fprintf(stderr, gettext("install: %s and %s are the same file.\n"), from, path); 228 return (1); 229 } 230 /* unlink now... avoid ETXTBSY errors later */ 231 (void) unlink(path); 232 } 233 234 nocompare: 235 /* open target, set mode, owner, group */ 236 if ((to_fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0)) < 0) { 237 fprintf(stderr, gettext("install: %s: %s\n"), path, strerror(errno)); 238 return (1); 239 } 240 if (fchmod(to_fd, mode)) { 241 fprintf(stderr, gettext("install: chmod: %s: %s\n"), path, strerror(errno)); 242 status = 1; 243 close(to_fd); 244 goto inst_done; 245 } 246 if (!devnull) { 247 status = copy(from, to_fd, path); /* copy */ 248 close(to_fd); 249 } 250 if (sflag) { 251 sprintf(buf, "strip %s", path); 252 system(buf); 253 } 254 if (chown(path, pp->pw_uid, gp->gr_gid) && errno != EPERM) { 255 fprintf(stderr, gettext("install: chown: %s: %s\n"), path, strerror(errno)); 256 status = 1; 257 } 258 259 inst_done: 260 if (status) 261 (void) unlink(path); 262 return (status); 263 } 264 265 /* 266 * copy -- 267 * copy from one file to another 268 */ 269 int 270 copy(from_name, to_fd, to_name) 271 int to_fd; 272 char *from_name, *to_name; 273 { 274 int n, from_fd; 275 int status = 0; 276 char buf[MAXBSIZE]; 277 278 if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) { 279 fprintf(stderr, gettext("install: open: %s: %s\n"), from_name, strerror(errno)); 280 return (1); 281 } 282 while ((n = read(from_fd, buf, sizeof(buf))) > 0) 283 if (write(to_fd, buf, n) != n) { 284 fprintf(stderr, gettext("install: write: %s: %s\n"), to_name, strerror(errno)); 285 status = 1; 286 goto copy_done; 287 } 288 if (n == -1) { 289 fprintf(stderr, gettext("install: read: %s: %s\n"), from_name, strerror(errno)); 290 status = 1; 291 goto copy_done; 292 } 293 294 copy_done: 295 (void) close(from_fd); 296 return (status); 297 } 298 299 /* 300 * atoo -- 301 * octal string to int 302 */ 303 int 304 atoo(str) 305 register char *str; 306 { 307 register int val; 308 309 for (val = 0; isdigit(*str); ++str) 310 val = val * 8 + *str - '0'; 311 return(val); 312 } 313 314 315 /* 316 * usage -- 317 * print a usage message and die 318 */ 319 void 320 usage() 321 { 322 fputs(gettext("usage: install [-cs] [-g group] [-m mode] [-o owner] file ... destination\n"), stderr); 323 fputs(gettext(" install -d [-g group] [-m mode] [-o owner] dir\n"), stderr); 324 exit(1); 325 } 326 327 /* 328 * mkdirp -- 329 * make a directory and parents if needed 330 */ 331 int 332 mkdirp(dir, mode) 333 char *dir; 334 int mode; 335 { 336 int err; 337 char *slash; 338 char *strrchr(); 339 extern int errno; 340 341 if (mkdir(dir, mode) == 0) 342 return (0); 343 if (errno != ENOENT) 344 return (-1); 345 slash = strrchr(dir, '/'); 346 if (slash == NULL) 347 return (-1); 348 *slash = '\0'; 349 err = mkdirp(dir, 0777); 350 *slash = '/'; 351 if (err) 352 return (err); 353 return mkdir(dir, mode); 354 } 355