Home | History | Annotate | Download | only in install.d
      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