diff options
Diffstat (limited to 'usr/src/ucbcmd/install.d/install.c')
-rw-r--r-- | usr/src/ucbcmd/install.d/install.c | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/usr/src/ucbcmd/install.d/install.c b/usr/src/ucbcmd/install.d/install.c new file mode 100644 index 0000000000..f0ec328457 --- /dev/null +++ b/usr/src/ucbcmd/install.d/install.c @@ -0,0 +1,354 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1996 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <fcntl.h> +#include <grp.h> +#include <pwd.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <locale.h> + +#define DEF_GROUP "staff" /* default group */ +#define DEF_OWNER "root" /* default owner */ +#define DEF_MODE 0755 /* default mode */ + +char *group = DEF_GROUP; +char *owner = DEF_OWNER; +int mode = DEF_MODE; +int sflag = 0; +struct passwd *pp; +struct group *gp; +extern int errno; +int copy(); +void usage(); + +main(argc, argv) + int argc; + char **argv; +{ + extern char *optarg; + extern int optind; + struct stat stb; + char *dirname; + int ch; + int i; + int rc; + int dflag = 0; + int gflag = 0; + int oflag = 0; + int mflag = 0; + + (void) setlocale(LC_ALL, ""); + +#if !defined(TEXT_DOMAIN) +#define TEXT_DOMAIN "SYS_TEST" +#endif + (void) textdomain(TEXT_DOMAIN); + + while ((ch = getopt(argc, argv, "dcg:o:m:s")) != EOF) + switch((char)ch) { + case 'c': + break; /* always do "copy" */ + case 'd': + dflag++; + break; + case 'g': + gflag++; + group = optarg; + break; + case 'm': + mflag++; + mode = atoo(optarg); + break; + case 'o': + oflag++; + owner = optarg; + break; + case 's': + sflag++; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + /* get group and owner id's */ + if (!(gp = getgrnam(group))) { + fprintf(stderr, gettext("install: unknown group %s.\n"), group); + exit(1); + } + if (!(pp = getpwnam(owner))) { + fprintf(stderr, gettext("install: unknown user %s.\n"), owner); + exit(1); + } + + if (dflag) { /* install a directory */ + int exists = 0; + + if (argc != 1) + usage(); + dirname = argv[0]; + if (mkdirp(dirname, 0777) < 0) { + exists = errno == EEXIST; + if (!exists) { + fprintf(stderr, gettext("install: mkdir: %s: %s\n"), dirname, strerror(errno)); + exit(1); + } + } + if (stat(dirname, &stb) < 0) { + fprintf(stderr, gettext("install: stat: %s: %s\n"), dirname, strerror(errno)); + exit(1); + } + if ((stb.st_mode&S_IFMT) != S_IFDIR) { + fprintf(stderr, gettext("install: %s is not a directory\n"), dirname); + } + /* make sure directory setgid bit is inherited */ + mode = (mode & ~S_ISGID) | (stb.st_mode & S_ISGID); + if (mflag && chmod(dirname, mode)) { + fprintf(stderr, gettext("install: chmod: %s: %s\n"), dirname, strerror(errno)); + if (!exists) + (void) unlink(dirname); + exit(1) ; + } + if (oflag && chown(dirname, pp->pw_uid, -1) && errno != EPERM) { + fprintf(stderr, gettext("install: chown: %s: %s\n"), dirname, strerror(errno)); + if (!exists) + (void) unlink(dirname); + exit(1) ; + } + if (gflag && chown(dirname, -1, gp->gr_gid) && errno != EPERM) { + fprintf(stderr, gettext("install: chgrp: %s: %s\n"), dirname, strerror(errno)); + if (!exists) + (void) unlink(dirname); + exit(1) ; + } + exit(0); + } + + if (argc < 2) + usage(); + + if (argc > 2) { /* last arg must be a directory */ + if (stat(argv[argc-1], &stb) < 0) + usage(); + if ((stb.st_mode&S_IFMT) != S_IFDIR) + usage(); + } + rc = 0; + for (i = 0; i < argc-1; i++) + rc |= install(argv[i], argv[argc-1]); + exit(rc); + /* NOTREACHED */ +} + +int +install(from, to) + char *from, *to; +{ + int to_fd; + int devnull; + int status = 0; + char *path; + struct stat from_sb, to_sb; + static char pbuf[MAXPATHLEN]; + char buf[MAXPATHLEN + 10]; + + /* check source */ + if (stat(from, &from_sb)) { + fprintf(stderr, gettext("install: %s: %s\n"), from, strerror(errno)); + return (1); + } + /* special case for removing files */ + devnull = !strcmp(from, "/dev/null"); + if (!devnull && !((from_sb.st_mode&S_IFMT) == S_IFREG)) { + fprintf(stderr, gettext("install: %s isn't a regular file.\n"), from); + return (1); + } + + /* build target path, find out if target is same as source */ + if (!stat(path = to, &to_sb)) { + if ((to_sb.st_mode&S_IFMT) == S_IFDIR) { + char *C, *strrchr(); + + (void) sprintf(path = pbuf, "%s/%s", to, (C = strrchr(from, '/')) ? ++C : from); + if (stat(path, &to_sb)) + goto nocompare; + } + if ((to_sb.st_mode&S_IFMT) != S_IFREG) { + fprintf(stderr, gettext("install: %s isn't a regular file.\n"), path); + return (1); + } + if (to_sb.st_dev == from_sb.st_dev && to_sb.st_ino == from_sb.st_ino) { + fprintf(stderr, gettext("install: %s and %s are the same file.\n"), from, path); + return (1); + } + /* unlink now... avoid ETXTBSY errors later */ + (void) unlink(path); + } + +nocompare: + /* open target, set mode, owner, group */ + if ((to_fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0)) < 0) { + fprintf(stderr, gettext("install: %s: %s\n"), path, strerror(errno)); + return (1); + } + if (fchmod(to_fd, mode)) { + fprintf(stderr, gettext("install: chmod: %s: %s\n"), path, strerror(errno)); + status = 1; + close(to_fd); + goto inst_done; + } + if (!devnull) { + status = copy(from, to_fd, path); /* copy */ + close(to_fd); + } + if (sflag) { + sprintf(buf, "strip %s", path); + system(buf); + } + if (chown(path, pp->pw_uid, gp->gr_gid) && errno != EPERM) { + fprintf(stderr, gettext("install: chown: %s: %s\n"), path, strerror(errno)); + status = 1; + } + +inst_done: + if (status) + (void) unlink(path); + return (status); +} + +/* + * copy -- + * copy from one file to another + */ +int +copy(from_name, to_fd, to_name) + int to_fd; + char *from_name, *to_name; +{ + int n, from_fd; + int status = 0; + char buf[MAXBSIZE]; + + if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) { + fprintf(stderr, gettext("install: open: %s: %s\n"), from_name, strerror(errno)); + return (1); + } + while ((n = read(from_fd, buf, sizeof(buf))) > 0) + if (write(to_fd, buf, n) != n) { + fprintf(stderr, gettext("install: write: %s: %s\n"), to_name, strerror(errno)); + status = 1; + goto copy_done; + } + if (n == -1) { + fprintf(stderr, gettext("install: read: %s: %s\n"), from_name, strerror(errno)); + status = 1; + goto copy_done; + } + +copy_done: + (void) close(from_fd); + return (status); +} + +/* + * atoo -- + * octal string to int + */ +int +atoo(str) + register char *str; +{ + register int val; + + for (val = 0; isdigit(*str); ++str) + val = val * 8 + *str - '0'; + return(val); +} + + +/* + * usage -- + * print a usage message and die + */ +void +usage() +{ + fputs(gettext("usage: install [-cs] [-g group] [-m mode] [-o owner] file ... destination\n"), stderr); + fputs(gettext(" install -d [-g group] [-m mode] [-o owner] dir\n"), stderr); + exit(1); +} + +/* + * mkdirp -- + * make a directory and parents if needed + */ +int +mkdirp(dir, mode) + char *dir; + int mode; +{ + int err; + char *slash; + char *strrchr(); + extern int errno; + + if (mkdir(dir, mode) == 0) + return (0); + if (errno != ENOENT) + return (-1); + slash = strrchr(dir, '/'); + if (slash == NULL) + return (-1); + *slash = '\0'; + err = mkdirp(dir, 0777); + *slash = '/'; + if (err) + return (err); + return mkdir(dir, mode); +} |