sbase

suckless unix tools
git clone git://git.2f30.org/sbase.git
Log | Files | Refs | README | LICENSE

commit 2f128ab050b39ced864fa24c6afc0eb6e6225f55
parent db952ed18cbd0ea2cee89be43277db186b20f356
Author: Eivind Uggedal <eivind@uggedal.com>
Date:   Mon Feb 15 09:44:35 +0100

install: bsd make compatibility

Diffstat:
Makefile | 21+++++++++++----------
install.1 | 88-------------------------------------------------------------------------------
install.c | 257-------------------------------------------------------------------------------
xinstall.1 | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
xinstall.c | 257+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 356 insertions(+), 355 deletions(-)
diff --git a/Makefile b/Makefile @@ -103,7 +103,6 @@ BIN =\ getconf\ grep\ head\ - install.out\ join\ hostname\ kill\ @@ -162,13 +161,14 @@ BIN =\ which\ whoami\ xargs\ + xinstall\ yes LIBUTFOBJ = $(LIBUTFSRC:.c=.o) LIBUTILOBJ = $(LIBUTILSRC:.c=.o) OBJ = $(BIN:=.o) $(LIBUTFOBJ) $(LIBUTILOBJ) -SRC = $(foreach F,$(BIN:.out=),$(F:=.c)) -MAN = $(foreach F,$(BIN:.out=),$(F:=.1)) +SRC = $(BIN:=.c) +MAN = $(BIN:=.1) all: $(BIN) @@ -179,9 +179,6 @@ $(OBJ): $(HDR) config.mk .o: $(CC) $(LDFLAGS) -o $@ $< $(LIB) -install.out: install.o - $(CC) $(LDFLAGS) -o $@ $^ $(LIB) - .c.o: $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< @@ -201,14 +198,15 @@ 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 - mv -f $(DESTDIR)$(PREFIX)/bin/install.out $(DESTDIR)$(PREFIX)/bin/install - cd $(DESTDIR)$(PREFIX)/bin && ln -f test [ && chmod 755 $(BIN:.out=) + cd $(DESTDIR)$(PREFIX)/bin && ln -f test [ && chmod 755 $(BIN) + mv -f $(DESTDIR)$(PREFIX)/bin/xinstall $(DESTDIR)$(PREFIX)/bin/install 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) + mv -f $(DESTDIR)$(MANPREFIX)/man1/xinstall.1 $(DESTDIR)$(MANPREFIX)/man1/install.1 uninstall: - cd $(DESTDIR)$(PREFIX)/bin && rm -f $(BIN:.out=) [ + cd $(DESTDIR)$(PREFIX)/bin && rm -f $(BIN) [ xinstall cd $(DESTDIR)$(MANPREFIX)/man1 && rm -f $(MAN) dist: clean @@ -231,6 +229,7 @@ sbase-box: $(LIB) $(SRC) for f in $(SRC); do echo "int $${f%.c}_main(int, char **);"; done >> build/$@.c echo 'int main(int argc, char *argv[]) { char *s = basename(argv[0]);' >> build/$@.c echo 'if(!strcmp(s,"sbase-box")) { argc--; argv++; s = basename(argv[0]); } if(0) ;' >> build/$@.c + echo "else if (!strcmp(s, \"install\")) return xinstall_main(argc, argv);" >> build/$@.c echo "else if (!strcmp(s, \"[\")) return test_main(argc, argv);" >> build/$@.c for f in $(SRC); do echo "else if(!strcmp(s, \"$${f%.c}\")) return $${f%.c}_main(argc, argv);"; done >> build/$@.c echo 'else { fputs("[ ", stdout);' >> build/$@.c @@ -243,11 +242,13 @@ 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:.out=); do ln -sf sbase-box $(DESTDIR)$(PREFIX)/bin/"$$f"; done + for f in $(BIN); do ln -sf sbase-box $(DESTDIR)$(PREFIX)/bin/"$$f"; done ln -sf sbase-box $(DESTDIR)$(PREFIX)/bin/[ + mv -f $(DESTDIR)$(PREFIX)/bin/xinstall $(DESTDIR)$(PREFIX)/bin/install 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) + mv -f $(DESTDIR)$(MANPREFIX)/man1/xinstall.1 $(DESTDIR)$(MANPREFIX)/man1/install.1 clean: rm -f $(BIN) $(OBJ) $(LIB) sbase-box sbase-$(VERSION).tar.gz diff --git a/install.1 b/install.1 @@ -1,88 +0,0 @@ -.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. diff --git a/install.c b/install.c @@ -1,257 +0,0 @@ -/* 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; -} diff --git a/xinstall.1 b/xinstall.1 @@ -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. diff --git a/xinstall.c b/xinstall.c @@ -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; +}