/*
* 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();
int
main(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]);
return (rc);
}
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)
char *str;
{
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);
}