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:
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 .
+ .