hbase

heirloom base
git clone git://git.2f30.org/hbase
Log | Files | Refs | README

install.c (9124B)


      1 /*
      2  * install - (BSD style) install files
      3  *
      4  * Gunnar Ritter, Freiburg i. Br., Germany, March 2003.
      5  */
      6 /*
      7  * Copyright (c) 2003 Gunnar Ritter
      8  *
      9  * This software is provided 'as-is', without any express or implied
     10  * warranty. In no event will the authors be held liable for any damages
     11  * arising from the use of this software.
     12  *
     13  * Permission is granted to anyone to use this software for any purpose,
     14  * including commercial applications, and to alter it and redistribute
     15  * it freely, subject to the following restrictions:
     16  *
     17  * 1. The origin of this software must not be misrepresented; you must not
     18  *    claim that you wrote the original software. If you use this software
     19  *    in a product, an acknowledgment in the product documentation would be
     20  *    appreciated but is not required.
     21  *
     22  * 2. Altered source versions must be plainly marked as such, and must not be
     23  *    misrepresented as being the original software.
     24  *
     25  * 3. This notice may not be removed or altered from any source distribution.
     26  */
     27 
     28 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
     29 #define	USED	__attribute__ ((used))
     30 #elif defined __GNUC__
     31 #define	USED	__attribute__ ((unused))
     32 #else
     33 #define	USED
     34 #endif
     35 static const char sccsid[] USED = "@(#)/usr/ucb/install.sl	1.12 (gritter) 5/29/05";
     36 
     37 #include	<sys/types.h>
     38 #include	<sys/stat.h>
     39 #include	<fcntl.h>
     40 #include	<unistd.h>
     41 #include	<stdio.h>
     42 #include	<string.h>
     43 #include	<stdlib.h>
     44 #include	<errno.h>
     45 #include	<libgen.h>
     46 #include	<limits.h>
     47 #include	<pwd.h>
     48 #include	<grp.h>
     49 
     50 enum	okay {
     51 	OKAY = 0,
     52 	STOP = 1
     53 };
     54 
     55 static int	mflag;			/* -m option present */
     56 static int	sflag;			/* strip files */
     57 static mode_t	mode = 0755;		/* mode to set */
     58 static int	dflag;			/* create directories */
     59 static int	gflag;			/* set group */
     60 static gid_t	group;			/* group to set */
     61 static int	oflag;			/* set owner */
     62 static uid_t	owner;			/* owner to set */
     63 static int	errcnt;			/* count of errors */
     64 static char	*progname;		/* argv[0] to main */
     65 
     66 void *
     67 srealloc(void *op, size_t size)
     68 {
     69 	void	*np;
     70 
     71 	if ((np = realloc(op, size)) == NULL) {
     72 		write(2, "no memory\n", 10);
     73 		_exit(077);
     74 	}
     75 	return np;
     76 }
     77 
     78 void *
     79 smalloc(size_t size)
     80 {
     81 	return srealloc(NULL, size);
     82 }
     83 
     84 uid_t
     85 getowner(const char *string)
     86 {
     87 	struct passwd	*pwd;
     88 	char	*x;
     89 	long	val;
     90 
     91 	if ((pwd = getpwnam(string)) != NULL)
     92 		return pwd->pw_uid;
     93 	val = strtoul(string, &x, 10);
     94 	if (*x != '\0' || *string == '+' || *string == '-') {
     95 		fprintf(stderr, "%s: unknown user %s.\n", progname, string);
     96 		exit(1);
     97 	}
     98 	return val;
     99 }
    100 
    101 gid_t
    102 getgroup(const char *string)
    103 {
    104 	struct group	*grp;
    105 	char	*x;
    106 	long	val;
    107 
    108 	if ((grp = getgrnam(string)) != NULL)
    109 		return grp->gr_gid;
    110 	val = strtoul(string, &x, 10);
    111 	if (*x != '\0' || *string == '+' || *string == '-') {
    112 		fprintf(stderr, "%s: unknown group %s.\n", progname, string);
    113 		exit(1);
    114 	}
    115 	return val;
    116 }
    117 
    118 void
    119 getpath(const char *path, char **file, char **filend, size_t *sz, size_t *slen)
    120 {
    121 	*sz = 14 + strlen(path) + 2;
    122 	*file = smalloc(*sz);
    123 	*filend = *file;
    124 	if (path[0] == '/' && path[1] == '\0')
    125 		*(*filend)++ = '/';
    126 	else {
    127 		const char	*cp = path;
    128 		while ((*(*filend)++ = *cp++) != '\0');
    129 		(*filend)[-1] = '/';
    130 	}
    131 	*slen = *filend - *file;
    132 }
    133 
    134 void
    135 setpath(const char *base, char **file, char **filend,
    136 		size_t slen, size_t *sz, size_t *ss)
    137 {
    138 	if (slen + (*ss = strlen(base)) >= *sz) {
    139 		*sz += slen + *ss + 15;
    140 		*file = srealloc(*file, *sz);
    141 		*filend = &(*file)[slen];
    142 	}
    143 	strcpy(*filend, base);
    144 }
    145 
    146 void
    147 fdcopy(const char *src, const struct stat *ssp, const int sfd,
    148 		const char *tgt, const struct stat *dsp, const int dfd)
    149 {
    150 	char	*buf;
    151 	size_t	bufsize;
    152 	ssize_t	rsz, wo, wt;
    153 
    154 	if ((bufsize = ssp->st_blksize) < dsp->st_blksize)
    155 		if ((bufsize = dsp->st_blksize) <= 0)
    156 			bufsize = 512;
    157 	buf = smalloc(bufsize);
    158 	while ((rsz = read(sfd, buf, bufsize)) > 0) {
    159 		wt = 0;
    160 		do {
    161 			if ((wo = write(dfd, buf + wt, rsz - wt)) < 0) {
    162 				fprintf(stderr, "%s: write: %s: %s\n",
    163 						progname, tgt,
    164 						strerror(errno));
    165 				errcnt |= 01;
    166 				unlink(tgt);
    167 				free(buf);
    168 				return;
    169 			}
    170 			wt += wo;
    171 		} while (wt < rsz);
    172 	}
    173 	if (rsz < 0) {
    174 		fprintf(stderr, "%s: read: %s: %s\n",
    175 				progname, src, strerror(errno));
    176 		errcnt |= 01;
    177 		unlink(tgt);
    178 	}
    179 	free(buf);
    180 }
    181 
    182 static void
    183 usage(void)
    184 {
    185 	fprintf(stderr, "\
    186 usage: %s [-cs] [-g group] [-m mode] [-o owner] file ...  destination\n\
    187        %s  -d   [-g group] [-m mode] [-o owner] dir\n",
    188        		progname, progname);
    189 	exit(2);
    190 }
    191 
    192 static void
    193 strip(const char *file)
    194 {
    195 	const char	cpr[] = "strip ";
    196 	char	*cmd, *cp;
    197 	const char	*sp;
    198 
    199 	cp = cmd = smalloc(strlen(cpr) + strlen(file) + 1);
    200 	for (sp = cpr; *sp; sp++)
    201 		*cp++ = *sp;
    202 	for (sp = file; *sp; sp++)
    203 		*cp++ = *sp;
    204 	*cp = '\0';
    205 	system(cmd);
    206 	free(cmd);
    207 }
    208 
    209 static enum okay
    210 chgown(const char *fn, struct stat *sp)
    211 {
    212 	struct stat	st;
    213 
    214 	if (sp == NULL) {
    215 		if (stat(fn, &st) < 0) {
    216 			fprintf(stderr, "%s: stat: %s: %s\n",
    217 					progname, fn, strerror(errno));
    218 			errcnt |= 1;
    219 			return STOP;
    220 		}
    221 		sp = &st;
    222 	}
    223 	if (!oflag)
    224 		owner = sp->st_uid;
    225 	if (!gflag)
    226 		group = sp->st_gid;
    227 	if (chown(fn, owner, group) < 0) {
    228 		fprintf(stderr, "%s: chown: %s: %s\n", progname, fn,
    229 				strerror(errno));
    230 		errcnt |= 01;
    231 		return STOP;
    232 	}
    233 	return OKAY;
    234 }
    235 
    236 static enum okay
    237 check(const char *src, const char *tgt, const struct stat *dsp,
    238 		struct stat *ssp)
    239 {
    240 	if (stat(src, ssp) < 0) {
    241 		fprintf(stderr, "%s: %s: %s\n", progname, src,
    242 				strerror(errno));
    243 		errcnt |= 01;
    244 		return STOP;
    245 	}
    246 	if ((ssp->st_mode&S_IFMT) != S_IFREG && strcmp(src, "/dev/null")) {
    247 		fprintf(stderr, "%s: %s isn't a regular file.\n",
    248 				progname, src);
    249 		errcnt |= 01;
    250 		return STOP;
    251 	}
    252 	if (dsp && (ssp->st_dev == dsp->st_dev && ssp->st_ino == dsp->st_ino)) {
    253 		fprintf(stderr, "%s: %s and %s are the same file.\n",
    254 				progname, src, tgt);
    255 		errcnt |= 01;
    256 		return STOP;
    257 	}
    258 	return OKAY;
    259 }
    260 
    261 static void
    262 cp(const char *src, const char *tgt, struct stat *dsp)
    263 {
    264 	struct stat	sst, nst;
    265 	int	sfd, dfd;
    266 
    267 	if (check(src, tgt, dsp, &sst) != OKAY)
    268 		return;
    269 	unlink(tgt);
    270 	if ((dfd = creat(tgt, 0700)) < 0 || fchmod(dfd, 0700) < 0 ||
    271 			fstat(dfd, &nst) < 0) {
    272 		fprintf(stderr, "%s: %s: %s\n", progname, src,
    273 				strerror(errno));
    274 		errcnt |= 01;
    275 		if (dfd >= 0)
    276 			close(dfd);
    277 		return;
    278 	}
    279 	if ((sfd = open(src, O_RDONLY)) < 0) {
    280 		fprintf(stderr, "%s: open: %s: %s\n", progname, src,
    281 				strerror(errno));
    282 		errcnt |= 01;
    283 		return;
    284 	}
    285 	fdcopy(src, &sst, sfd, tgt, &nst, dfd);
    286 	close(dfd);
    287 	close(sfd);
    288 	if (sflag)
    289 		strip(tgt);
    290 	if (oflag || gflag)
    291 		chgown(tgt, &nst);
    292 	if (chmod(tgt, mode) < 0) {
    293 		fprintf(stderr, "%s: %s: %s\n", progname, tgt, strerror(errno));
    294 		errcnt |= 01;
    295 	}
    296 }
    297 
    298 static void
    299 installf(int ac, char **av)
    300 {
    301 	struct stat	dst, ust;
    302 
    303 	if (lstat(av[ac-1], &dst) == 0) {
    304 		if ((dst.st_mode&S_IFMT) != S_IFLNK ||
    305 				stat(av[ac-1], &ust) < 0)
    306 			ust = dst;
    307 		if ((ust.st_mode&S_IFMT) == S_IFDIR) {
    308 			char	*copy, *cend;
    309 			size_t	sz, slen, ss;
    310 			int	i;
    311 
    312 			getpath(av[ac-1], &copy, &cend, &sz, &slen);
    313 			for (i = 0; i < ac-1; i++) {
    314 				setpath(basename(av[i]), &copy, &cend,
    315 						slen, &sz, &ss);
    316 				cp(av[i], copy, stat(copy, &dst) < 0 ?
    317 						NULL : &dst);
    318 			}
    319 		} else if (ac > 2)
    320 			usage();
    321 		else
    322 			cp(av[0], av[1], &ust);
    323 	} else if (ac > 2)
    324 		usage();
    325 	else
    326 		cp(av[0], av[1], NULL);
    327 }
    328 
    329 static enum okay
    330 makedir(const char *dir)
    331 {
    332 	struct stat	st;
    333 
    334 	if (mkdir(dir, 0777) < 0) {
    335 		if (errno == EEXIST) {
    336 			if (stat(dir, &st) < 0 ||
    337 					(st.st_mode&S_IFMT) != S_IFDIR){
    338 				fprintf(stderr, "%s: %s is not a directory\n",
    339 						progname, dir);
    340 				errcnt |= 01;
    341 				return STOP;
    342 			}
    343 		} else {
    344 			fprintf(stderr, "%s: mkdir: %s: %s\n",
    345 					progname, dir, strerror(errno));
    346 			errcnt |= 01;
    347 			return STOP;
    348 		}
    349 	}
    350 	return OKAY;
    351 }
    352 static void
    353 installd(char *dir)
    354 {
    355 	struct stat	st;
    356 	int	sgid_bit;
    357 	char	*slash;
    358 	char	c;
    359 
    360 	slash = dir;
    361 	do {
    362 		while (*slash == '/')
    363 			slash++;
    364 		while (*slash != '/' && *slash != '\0')
    365 			slash++;
    366 		c = *slash;
    367 		*slash = '\0';
    368 		if (makedir(dir) != OKAY)
    369 			return;
    370 		if (c == '\0') {
    371 			if (oflag || gflag)
    372 				if (chgown(dir, NULL) != OKAY)
    373 					return;
    374 			if (mflag) {
    375 				sgid_bit = stat(dir, &st) == 0 &&
    376 					st.st_mode&S_ISGID ? S_ISGID : 0;
    377 				if (chmod(dir, mode | sgid_bit) < 0) {
    378 					fprintf(stderr, "%s: chmod: %s: %s\n",
    379 							progname, dir,
    380 							strerror(errno));
    381 					errcnt |= 01;
    382 					return;
    383 				}
    384 			}
    385 		}
    386 		*slash = c;
    387 	} while (c != '\0');
    388 }
    389 
    390 int
    391 main(int argc, char **argv)
    392 {
    393 	const char	optstring[] = "csg:m:o:d";
    394 	int	i;
    395 
    396 	progname = basename(argv[0]);
    397 	while ((i = getopt(argc, argv, optstring)) != EOF) {
    398 		switch (i) {
    399 		case 'c':
    400 			/* no-op */
    401 			break;
    402 		case 's':
    403 			sflag = 1;
    404 			break;
    405 		case 'g':
    406 			gflag = 1;
    407 			group = getgroup(optarg);
    408 			break;
    409 		case 'm':
    410 			mflag = 1;
    411 			mode = strtol(optarg, NULL, 8);
    412 			break;
    413 		case 'o':
    414 			oflag = 1;
    415 			owner = getowner(optarg);
    416 			break;
    417 		case 'd':
    418 			dflag = 1;
    419 			break;
    420 		default:
    421 			usage();
    422 		}
    423 	}
    424 	if (dflag) {
    425 		if (argc == optind || argc > optind + 1)
    426 			usage();
    427 		if (mflag)
    428 			mode &= ~(mode_t)S_ISGID;
    429 		installd(argv[optind]);
    430 	} else {
    431 		if (argc < optind + 2)
    432 			usage();
    433 		installf(argc - optind, &argv[optind]);
    434 	}
    435 	return errcnt;
    436 }