New command with corresponding man page. Includes the flags:

-s strip binary
-d create directory
-D create missing directories
-t DIR target directory
-m MODE permission bits
-o USER set owner
-g GROUP set group

Installed files are copied, and default mode is 755.

Signed-off-by: Mattias Andrée <maandree@kth.se>
This commit is contained in:
Mattias Andrée 2016-02-12 14:33:09 +01:00 committed by sin
parent 038dffaa50
commit db952ed18c
5 changed files with 356 additions and 6 deletions

View File

@ -103,6 +103,7 @@ BIN =\
getconf\
grep\
head\
install.out\
join\
hostname\
kill\
@ -166,8 +167,8 @@ BIN =\
LIBUTFOBJ = $(LIBUTFSRC:.c=.o)
LIBUTILOBJ = $(LIBUTILSRC:.c=.o)
OBJ = $(BIN:=.o) $(LIBUTFOBJ) $(LIBUTILOBJ)
SRC = $(BIN:=.c)
MAN = $(BIN:=.1)
SRC = $(foreach F,$(BIN:.out=),$(F:=.c))
MAN = $(foreach F,$(BIN:.out=),$(F:=.1))
all: $(BIN)
@ -178,6 +179,9 @@ $(OBJ): $(HDR) config.mk
.o:
$(CC) $(LDFLAGS) -o $@ $< $(LIB)
install.out: install.o
$(CC) $(LDFLAGS) -o $@ $^ $(LIB)
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
@ -197,13 +201,14 @@ confstr_l.h limits_l.h sysconf_l.h pathconf_l.h: getconf.sh
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin
cd $(DESTDIR)$(PREFIX)/bin && ln -f test [ && chmod 755 $(BIN)
mv -f $(DESTDIR)$(PREFIX)/bin/install.out $(DESTDIR)$(PREFIX)/bin/install
cd $(DESTDIR)$(PREFIX)/bin && ln -f test [ && chmod 755 $(BIN:.out=)
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
for m in $(MAN); do sed "s/^\.Os sbase/.Os sbase $(VERSION)/g" < "$$m" > $(DESTDIR)$(MANPREFIX)/man1/"$$m"; done
cd $(DESTDIR)$(MANPREFIX)/man1 && chmod 644 $(MAN)
uninstall:
cd $(DESTDIR)$(PREFIX)/bin && rm -f $(BIN) [
cd $(DESTDIR)$(PREFIX)/bin && rm -f $(BIN:.out=) [
cd $(DESTDIR)$(MANPREFIX)/man1 && rm -f $(MAN)
dist: clean
@ -238,7 +243,7 @@ sbase-box-install: sbase-box
mkdir -p $(DESTDIR)$(PREFIX)/bin
cp -f sbase-box $(DESTDIR)$(PREFIX)/bin
chmod 755 $(DESTDIR)$(PREFIX)/bin/sbase-box
for f in $(BIN); do ln -sf sbase-box $(DESTDIR)$(PREFIX)/bin/"$$f"; done
for f in $(BIN:.out=); do ln -sf sbase-box $(DESTDIR)$(PREFIX)/bin/"$$f"; done
ln -sf sbase-box $(DESTDIR)$(PREFIX)/bin/[
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
for m in $(MAN); do sed "s/^\.Os sbase/.Os sbase $(VERSION)/g" < "$$m" > $(DESTDIR)$(MANPREFIX)/man1/"$$m"; done

1
README
View File

@ -42,6 +42,7 @@ The following tools are implemented:
=*|o grep .
=*|o head .
=*|x hostname .
=*|x install .
=* o join .
=*|o kill .
=*|o link .

1
TODO
View File

@ -8,7 +8,6 @@ awk
bc
diff
ed manpage
install
patch
stty

88
install.1 Normal file
View File

@ -0,0 +1,88 @@
.Dd 2016-02-12
.Dt INSTALL 1
.Os sbase
.Sh NAME
.Nm install
.Nd copy files and set attributes
.Sh SYNOPSIS
.Nm
.Op Fl g Ar group
.Op Fl o Ar owner
.Op Fl m Ar mode
.Po
.Fl d Ar dir ...
|
.Op Fl sD
.Po
.Fl t Ar dest
.Ar source ...
|
.Ar source ...
.Ar dest
.Pc
.Pc
.Sh DESCRIPTION
.Nm
copies
.Ar source
to
.Ar dest .
If more than one
.Ar source
is given
.Ar dest
has to be a directory.
.Nm
can also change the attributes of the copies.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl d
Create the directories
.Ar dir .
.It Fl D
Create missing parent directories to
.Ar dest .
If
.Fl t
is used, the
.Ar dest
itself is also created if missing.
.It Fl g Ar group
Change the installed files' group to
.Ar group .
This may be a group name or a group identifier.
.It Fl m Ar mode
Change the file modes. Both numerical and symbolic
values are supported. See
.Xr chmod 1
for the syntex.
Default mode 0755. If a file has the mode 0644 and
is copied with
.It Fl o Ar owner
Change the installed files' owner to
.Ar owner .
This may be a user name or a user identifier.
.It Fl s
Remove unnecessary symbols using
.Xr strip 1 .
Failure to strip a file does not imply failure to install the file.
.It Fl t Ar dest
Copy files into the directory
.Ar dest .
.Nm install ,
the copy's mode will be 0755 unless
.Fl m
is used to select another mode. When the symbolic
notation is used, the base mode is 0000.
.Sh SEE ALSO
.Xr chmod 1 ,
.Xr chown 1 ,
.Xr cp 1 ,
.Xr mkdir 1 ,
.Xr strip 1
.Sh STANDARDS
The
.Nm
utility is not standardized. This implementation is a subset
of the GNU implementation and a subset with extensions to
the FreeBSD implementation.

257
install.c Normal file
View File

@ -0,0 +1,257 @@
/* See LICENSE file for copyright and license details. */
#include <grp.h>
#include <pwd.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "util.h"
#include "text.h"
static int Dflag = 0;
static int sflag = 0;
static gid_t group;
static uid_t owner;
static mode_t mode = 0755;
static void
make_dir(char *dir, int was_missing)
{
if (!mkdir(dir, was_missing ? 0755 : mode)) {
if (!was_missing && (lchown(dir, owner, group) < 0))
eprintf("lchmod %s:", dir);
} else if (errno != EEXIST) {
eprintf("mkdir %s:", dir);
}
}
static void
make_dirs(char *dir, int was_missing)
{
char *p;
for (p = strchr(dir + (dir[0] == '/'), '/'); p; p = strchr(p + 1, '/')) {
*p = '\0';
make_dir(dir, was_missing);
*p = '/';
}
make_dir(dir, was_missing);
}
static void
strip(const char *filename)
{
pid_t pid = fork();
switch (pid) {
case -1:
eprintf("fork:");
case 0:
execlp("strip", "strip", "--", filename, (char *)0);
eprintf("exec: strip:");
default:
waitpid(pid, NULL, 0);
break;
}
}
static int
install(const char *s1, const char *s2, int depth)
{
DIR *dp;
FILE *f1, *f2;
struct dirent *d;
struct stat st;
ssize_t r;
char target[PATH_MAX], ns1[PATH_MAX], ns2[PATH_MAX];
if (stat(s1, &st) < 0)
eprintf("stat %s:", s1);
if (S_ISLNK(st.st_mode)) {
if ((r = readlink(s1, target, sizeof(target) - 1)) >= 0) {
target[r] = '\0';
if (unlink(s2) < 0 && errno != ENOENT)
eprintf("unlink %s:", s2);
else if (symlink(target, s2) < 0)
eprintf("symlink %s -> %s:", s2, target);
}
} else if (S_ISDIR(st.st_mode)) {
if (!(dp = opendir(s1)))
eprintf("opendir %s:", s1);
if (mkdir(s2, mode | 0111) < 0 && errno != EEXIST)
eprintf("mkdir %s:", s2);
while ((d = readdir(dp))) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
estrlcpy(ns1, s1, sizeof(ns1));
if (s1[strlen(s1) - 1] != '/')
estrlcat(ns1, "/", sizeof(ns1));
estrlcat(ns1, d->d_name, sizeof(ns1));
estrlcpy(ns2, s2, sizeof(ns2));
if (s2[strlen(s2) - 1] != '/')
estrlcat(ns2, "/", sizeof(ns2));
estrlcat(ns2, d->d_name, sizeof(ns2));
fnck(ns1, ns2, install, depth + 1);
}
closedir(dp);
} else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) ||
S_ISSOCK(st.st_mode) || S_ISFIFO(st.st_mode)) {
if (unlink(s2) < 0 && errno != ENOENT)
eprintf("unlink %s:", s2);
else if (mknod(s2, (st.st_mode & ~07777) | mode, st.st_rdev) < 0)
eprintf("mknod %s:", s2);
} else {
if (!(f1 = fopen(s1, "r")))
eprintf("fopen %s:", s1);
if (!(f2 = fopen(s2, "w"))) {
if (unlink(s2) < 0 && errno != ENOENT)
eprintf("unlink %s:", s2);
else if (!(f2 = fopen(s2, "w")))
eprintf("fopen %s:", s2);
}
concat(f1, s1, f2, s2);
fchmod(fileno(f2), mode);
if (fclose(f2) == EOF)
eprintf("fclose %s:", s2);
if (fclose(f1) == EOF)
eprintf("fclose %s:", s1);
if (sflag)
strip(s2);
}
if (lchown(s2, owner, group) < 0)
eprintf("lchown %s:", s2);
return 0;
}
static void
usage(void)
{
eprintf("usage: %s [-g group] [-o owner] [-m mode] (-d dir ... | [-Ds] (-t dest source ... | source ... dest))\n", argv0);
}
int
main(int argc, char *argv[])
{
int dflag = 0;
char *gflag = 0;
char *oflag = 0;
char *mflag = 0;
char *tflag = 0;
struct group *gr;
struct passwd *pw;
struct stat st;
char *p;
ARGBEGIN {
case 'd':
dflag = 1;
break;
case 'D':
Dflag = 1;
break;
case 's':
sflag = 1;
break;
case 'g':
gflag = EARGF(usage());
break;
case 'o':
oflag = EARGF(usage());
break;
case 'm':
mflag = EARGF(usage());
break;
case 't':
tflag = EARGF(usage());
break;
default:
usage();
} ARGEND
if (argc < 1 + (!tflag & !dflag) || dflag & (Dflag | sflag | !!tflag))
usage();
if (gflag) {
errno = 0;
gr = getgrnam(gflag);
if (gr) {
group = gr->gr_gid;
} else {
if (errno)
eprintf("getgrnam %s:", gflag);
group = estrtonum(gflag, 0, UINT_MAX);
}
} else {
group = getgid();
}
if (oflag) {
errno = 0;
pw = getpwnam(oflag);
if (pw) {
owner = pw->pw_uid;
} else {
if (errno)
eprintf("getpwnam %s:", oflag);
owner = estrtonum(oflag, 0, UINT_MAX);
}
} else {
owner = getuid();
}
if (mflag) {
mode = parsemode(mflag, mode, 0);
if (mode < 0)
return 1;
}
if (tflag) {
memmove(argv - 1, argv, argc);
argv[argc++] = tflag;
}
if (tflag || argc > 2) {
if (stat(argv[argc - 1], &st) < 0) {
if ((errno == ENOENT) && Dflag) {
make_dirs(argv[argc - 1], 1);
} else {
eprintf("stat %s:", argv[argc - 1]);
}
} else if (!S_ISDIR(st.st_mode)) {
eprintf("%s: not a directory\n", argv[argc - 1]);
}
}
if (dflag) {
for (; *argv; argc--, argv++)
make_dirs(*argv, 0);
} else {
if (stat(argv[argc - 1], &st) < 0) {
if (errno != ENOENT)
eprintf("stat %s:", argv[argc - 1]);
if (tflag || argc > 2) {
p = strrchr(argv[argc - 1], '/');
*p = '\0';
make_dirs(argv[argc - 1], 1);
*p = '/';
} else {
make_dirs(argv[argc - 1], 1);
}
}
enmasse(argc, argv, install);
}
return 0;
}