logo

utils-std

Collection of commonly available Unix tools
commit: a34efc85f4fd027385e0a1842c00883f116a0b6e
parent ff61a3d2270fe08be2798dca3ad0bd966803eff2
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sat,  4 May 2024 23:40:57 +0200

cmd/install: Add support for -d mode

Diffstat:

MMakefile4++--
Mcmd/install.19+++++++++
Mcmd/install.c51+++++++++++++++++++++++++++++++++++++++++++++++----
Mmakeless.sh2+-
Atest-cmd/install.t42++++++++++++++++++++++++++++++++++++++++++
5 files changed, 101 insertions(+), 7 deletions(-)

diff --git a/Makefile b/Makefile @@ -150,6 +150,6 @@ cmd/expr: cmd/expr.tab.c Makefile rm -f ${<:=.gcov} ${@:=.gcda} ${@:=.gcno} $(CC) -std=c99 $(CFLAGS) -o $@ cmd/expr.tab.c $(LDFLAGS) $(LDSTATIC) -cmd/install: cmd/install.c lib/mode.c lib/user_group_parse.c lib/user_group_parse.h lib/path.c lib/path.h Makefile +cmd/install: cmd/install.c lib/mode.c lib/user_group_parse.c lib/user_group_parse.h lib/path.c lib/path.h lib/mkdir.c lib/mkdir.h Makefile rm -f ${<:=.gcov} ${@:=.gcda} ${@:=.gcno} - $(CC) -std=c99 $(CFLAGS) -o $@ cmd/install.c lib/mode.c lib/user_group_parse.c lib/path.c $(LDFLAGS) $(LDSTATIC) + $(CC) -std=c99 $(CFLAGS) -o $@ cmd/install.c lib/mode.c lib/user_group_parse.c lib/path.c lib/mkdir.c $(LDFLAGS) $(LDSTATIC) diff --git a/cmd/install.1 b/cmd/install.1 @@ -15,6 +15,13 @@ .Op Fl o Ar owner .Op Ar source... .Op Ar destination +.Nm +.Fl d +.Op Fl c +.Op Fl g Ar group +.Op Fl m Ar mode +.Op Fl o Ar owner +.Ar directory... .Sh DESCRIPTION .Nm copies the given @@ -35,6 +42,8 @@ is specified. .Bl -tag -width _o_owner .It Fl c Copy the file, default behavior in all modern implementations. +.It Fl d +Create directories, including their parents. .It Fl g Ar group Sets group ownership. .It Fl m Ar mode diff --git a/cmd/install.c b/cmd/install.c @@ -5,6 +5,7 @@ #define _POSIX_C_SOURCE 200809L #define _GNU_SOURCE // copy_file_range +#include "../lib/mkdir.h" #include "../lib/mode.h" #include "../lib/path.h" #include "../lib/user_group_parse.h" @@ -19,7 +20,11 @@ #include <sys/stat.h> #include <unistd.h> // getopt, copy_file_range -bool preserve_times = false; +bool preserve_times = false, create_directories = false; + +// See lib/mkdir.c +bool mkdir_parents_verbose = false; +mode_t mkdir_parents_filemask; mode_t mode = 00755; uid_t user = (uid_t)-1; @@ -186,7 +191,10 @@ do_install(char *src, char *dest, bool is_dir) static void usage() { - fprintf(stderr, "Usage: install [-cp] [-g group] [-m mode] [-o owner] source... destination\n"); + fprintf(stderr, "\ +Usage: install [-cp] [-g group] [-m mode] [-o owner] source... destination\n\ + install -d [-c] [-g group] [-m mode] [-o owner] directory...\n\ +"); } int @@ -194,14 +202,20 @@ main(int argc, char *argv[]) { const char *errstr = NULL; + mkdir_parents_filemask = umask(0); + umask(mkdir_parents_filemask); + int c = -1; - while((c = getopt(argc, argv, ":cpg:m:o:")) != -1) + while((c = getopt(argc, argv, ":cdpg:m:o:")) != -1) { switch(c) { case 'c': // ignore, modern default behavior break; + case 'd': + create_directories = true; + break; case 'p': preserve_times = true; break; @@ -219,10 +233,14 @@ main(int argc, char *argv[]) return 1; } break; + case ':': + fprintf(stderr, "install: Missing operand for option: '-%c'\n", optopt); + usage(); + return 1; case '?': fprintf(stderr, "install: Unknown option '-%c'\n", optopt); usage(); - break; + return 1; } } @@ -231,6 +249,31 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; + if(create_directories) + { + for(int i = 0; i < argc; i++) + { + char *dest = argv[i]; + + if(mkdir_parents(dest, mode) != 0) return -1; + + if(user != (uid_t)-1 || group != (gid_t)-1) + { + if(chown(dest, user, group) < 0) + { + fprintf(stderr, + "%s: Error: Failed changing ownership of '%s': %s\n", + argv0, + dest, + strerror(errno)); + return -1; + } + } + } + + return 0; + } + if(argc == 2) { if(do_install(argv[0], argv[1], false) < 0) return 1; diff --git a/makeless.sh b/makeless.sh @@ -25,7 +25,7 @@ $CC -std=c99 $CFLAGS -o cmd/echo cmd/echo.c $LDFLAGS $LDSTATIC $CC -std=c99 $CFLAGS -o cmd/env cmd/env.c $LDFLAGS $LDSTATIC $CC -std=c99 $CFLAGS -o cmd/false cmd/false.c $LDFLAGS $LDSTATIC $CC -std=c99 $CFLAGS -o cmd/id cmd/id.c $LDFLAGS $LDSTATIC -$CC -std=c99 $CFLAGS -o cmd/install cmd/install.c lib/mode.c lib/user_group_parse.c lib/path.c $LDFLAGS $LDSTATIC +$CC -std=c99 $CFLAGS -o cmd/install cmd/install.c lib/mode.c lib/user_group_parse.c lib/path.c lib/mkdir.c $LDFLAGS $LDSTATIC $CC -std=c99 $CFLAGS -o cmd/link cmd/link.c $LDFLAGS $LDSTATIC $CC -std=c99 $CFLAGS -o cmd/ln cmd/ln.c $LDFLAGS $LDSTATIC $CC -std=c99 $CFLAGS -o cmd/logname cmd/logname.c $LDFLAGS $LDSTATIC diff --git a/test-cmd/install.t b/test-cmd/install.t @@ -0,0 +1,42 @@ +#!/usr/bin/env cram +# SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me> +# SPDX-License-Identifier: MPL-2.0 + + $ export PATH="$TESTDIR/../cmd:$PATH" + +# Using chmod -v + to get permission bits, + with no perm nor who doesn't changes mode bits + + $ test "$(command -v install)" = "$TESTDIR/../cmd/install" + $ test "$(command -v chmod)" = "$TESTDIR/../cmd/chmod" + + $ umask 002 + + $ test ! -e src + $ touch src + $ install -m 755 src dest + $ chmod -v 755 dest + chmod: Permissions already set to 00755/-rwxr-xr-x for 'dest' + $ chmod -v 755 src + chmod: Permissions changed from 00664/-rw-rw-r-- to 00755/-rwxr-xr-x for 'src' + $ rm -f src dest + +install -d + $ test ! -e foo.d + $ install -d foo.d + $ test -d foo.d + $ rm -fr foo.d + + $ test ! -e enoent.d + $ install -d enoent.d/dir + $ test -d enoent.d + $ test -d enoent.d/dir + $ rm -fr enoent.d + + $ install -d -m 755 dest.d + $ chmod -v 755 dest.d + chmod: Permissions already set to 00755/drwxr-xr-x for 'dest.d' + $ rm -fr dest.d + +No files should be left + $ find . + .