config

OpenBSD system configuration
git clone git://jacobedwards.org/config
Log | Files | Refs | README

commit bbae32aa29d8d4c86c2c5084d65a0671c037cb04
parent 35deefa23a8925b483fae697f749a2f6cd4a0e32
Author: Jacob R. Edwards <n/a>
Date:   Fri, 11 Feb 2022 16:42:01 -0800

Update module installing system

The new program (a shell script) doesn't support linking files.
Instead, it shows a diff and allows the user to decide to update
the target file or not.

That it shows a diff is a major improvement, the old program didn't
tell you anything except that there was a conflict, and you had to
manually resolve them. Perhaps linking could be re-incorperated,
keeping the diffs and conflict resolution.

Diffstat:
MMakefile | 6+++---
Mglobal/Makefile | 2+-
Dlib/Makefile | 22----------------------
Alib/commands.make | 3+++
Alib/modsync | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dlib/module.c | 176-------------------------------------------------------------------------------
Mlib/module.make | 15++++-----------
Mlib/subdirs.make | 6+++++-
Mlocal/Makefile | 1-
9 files changed, 133 insertions(+), 215 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,5 +1,5 @@ -subdirs = local - -all: install +subdirs =\ + global\ + local\ .include "lib/subdirs.make" diff --git a/global/Makefile b/global/Makefile @@ -1,5 +1,5 @@ lib = ../lib -act = force copy +flags = -o root:wheel dest = / mods =\ doas\ diff --git a/lib/Makefile b/lib/Makefile @@ -1,22 +0,0 @@ -cc = cc -cflags = -Wall -Wno-write-strings -ldflags = -static -src = module.c -name = module - -all: ${name} - -.c.o: - ${cc} ${cflags} -c -o $@ $< - -${name}: Makefile - -${name}: ${name}.c - ${cc} ${cflags} -o ${name} ${name}.c ${ldflags} - - -clean: - rm -f ${name} - -.SUFFIXES: .c .o -.PHONY: clean install uninstall diff --git a/lib/commands.make b/lib/commands.make @@ -0,0 +1,3 @@ +# Sync script commands (first is default) + +commands = push pull diff stop diff --git a/lib/modsync b/lib/modsync @@ -0,0 +1,117 @@ +#!/bin/sh +# Copyright 2022 Jacob R. Edwards +# Configuration module syncing script +# +# This script should conform to POSIX, because why not: +POSIXLY_CORRECT= + +error() { + echo "$*" 1>&2 + exit 1 +} + +usererror() { + error "usage: $name [push|pull|diff|stop] [-dnop] dest module ..." + test "${1:-}" && + error "$@" +} + +ask() { + # No yes-forever answer, use yes(1) + test -t && + echo -n "$1? [$2] " 1>&2 + sed '1{ s/^$/'$2'/; q; }' | grep -q '^[Yy]' +} + +# Could be dynamically generated for efficiency, install(1) is also +# an option. +install() { + echo "$2" 1>&2 + mkdir -p "$(dirname "$2")" + cp -p "$1" "$2" + test "$owner" && + chown "$owner" "$2" + test "$perms" && + chmod "$perms" "$2" +} + +filesync() { + # Fix diff(1) output, I cannot get it to produce it for the + # file I want when pulling. + if ! test -f "$2" + then + install "$1" "$2" + elif $forcediff || test "$1" -nt "$2" -o "$1" -ot "$2" + then + if ! diff -u "$2" "$1" 1>&2 + then + $patch && ask patch y && + install "$1" "$2" + else + touch -r "$1" "$2" + fi + fi +} + +modsync() { + cmd="$1" + mod="$2" + dir="$3" + + case "$cmd" in + (push) sync() filesync "$1" "$2" ;; + (pull) sync() filesync "$2" "$1" ;; + (stop) sync() rm -v "$2" ;; + (*) usererror "$name: '$1': Invalid command" ;; + esac + + for file in $(cd "$mod" && find . -type f | cut -c 3-) + do + sync "$mod/$file" "$dir/$file" + done +} + +# Unset variables are unchecked on purpose, nounset (-u) handles it +set -eu + +IFS=' +' +name="$(basename "$0")" + +# Assume exit is due to user error, namely an unset variable +trap usererror 0 + +if test "$1" = 'diff' +then + shift + set -- push -n "$@" +fi + +cmd="$1" +shift + +patch=true +owner= +perms= +forcediff=false +while expr x"$1" : x- > /dev/null +do + case "$1" in + (-n) patch=false ;; + (-o) owner="$2"; shift ;; + (-p) perms="$2"; shift ;; + (-d) forcediff=true ;; + (*) usererror "$name: '$1': Invalid option" ;; + esac + shift +done + +dir="$1" +shift + +trap "" 0 + +for mod in "$@" +do + modsync "$cmd" "$mod" "$dir" +done diff --git a/lib/module.c b/lib/module.c @@ -1,176 +0,0 @@ -#define const - -#include <sys/stat.h> -#include <sys/wait.h> - -#include <errno.h> -#include <fts.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#define SHIFT(N) { argc -= N; argv += N; } - -static int argtoo; /* Install given directories too, not just their contents. */ -static int force; /* Install even if the target exists. */ -static int (*action)(char *, char *); /* Install function (link, copy, or none). */ -static int check; /* Ask for confirmation instead of exiting. */ - -void -die(char *s) -{ - perror(s); - exit(1); -} - -int -copy(char *a, char *b) -{ - int status; - pid_t pid; - - pid = fork(); - if (pid == 0) { - execv("/bin/cp", (char *[]){ "cp", "-p", a, b, NULL }); - perror("/bin/cp"); - _exit(1); - } - - if (pid < 0 || waitpid(pid, &status, 0) < 0) - return 1; - return WEXITSTATUS(status); -} - -int -none(char *a, char *b) -{ - return 0; -} - -int -confirm(char *a, char *b) -{ - char c, answer; - - if (force) - return 1; - if (!check) - return 0; - - fprintf(stderr, "%s -> %s? ", a, b); - answer = fgetc(stdin); - do - c = fgetc(stdin); - while (c != '\n' && c != EOF); - return answer == 'y' || answer == 'Y'; -} - -int -main(int argc, char *argv[]) -{ - FTS *fts; - FTSENT *ent; - char new[PATH_MAX]; - char prefix[PATH_MAX]; - int status; - size_t arglen; - struct stat st; - char *progname; - - progname = *argv; - if (argc < 4) { -usage: - fprintf(stderr, "usage: %s [force | check] action source ... target\n", progname); - return 1; - } - - SHIFT(1); - if (strcmp(*argv, "force") == 0) { - force = 1; - SHIFT(1); - } else if (strcmp(*argv, "check") == 0) { - check = 1; - SHIFT(1); - } - - if (strcmp(argv[0], "copy") == 0) - action = copy; - else if (strcmp(argv[0], "link") == 0) - action = link; - else { - action = none; - if (strcmp(argv[0], "remove") == 0) - force = 1; - else if (strcmp(argv[0], "list") == 0) - force = 0; - else - goto usage; - } - SHIFT(1); - - if (realpath(argv[--argc], prefix) == NULL) - die(argv[argc]); - argv[argc] = NULL; - - fts = fts_open(argv, 0, NULL); - if (fts == NULL) - die("fts_open"); - - arglen = 0; - while ((ent = fts_read(fts))) { - if (!argtoo && ent->fts_level == 0 && ent->fts_info == FTS_D) { - arglen = strlen(ent->fts_path); - if (ent->fts_path[arglen - 1] != '/') - ++arglen; - continue; - } - if (snprintf(new, sizeof(new), "%s/%s", prefix, ent->fts_path + arglen) >= sizeof(new)) { - errno = ENAMETOOLONG; - die(ent->fts_path); - } - - errno = 0; - if (stat(new, &st) < 0 && errno != ENOENT) - die(new); - - status = 0; - switch (ent->fts_info) { - case FTS_DNR: - case FTS_ERR: - case FTS_NS: - errno = ent->fts_errno; - die(ent->fts_path); - case FTS_DP: - break; - case FTS_D: - if (errno == ENOENT || !S_ISDIR(st.st_mode)) - status = mkdir(new, ent->fts_statp->st_mode); - break; - case FTS_F: - if (errno != ENOENT && action == link && st.st_ino == ent->fts_statp->st_ino) - ; - else { - if (errno == ENOENT) - status = action(ent->fts_accpath, new); - else if (confirm(ent->fts_accpath, new)) - status = (unlink(new) || action(ent->fts_accpath, new)); - else if (!check && action != none) { - errno = EEXIST; - status = 1; - } - if (!status) - puts(new); - } - break; - default: - fprintf(stderr, "%s: Not a regular file.\n", ent->fts_path); - status = 1; - } - if (status) - die(new); - } - - return fts_close(fts) != 0; -} diff --git a/lib/module.make b/lib/module.make @@ -1,15 +1,8 @@ # Module targets -all: install +.include "commands.make" -lib: - make -C ${lib} - -install: lib - ${lib}/module ${act} ${mods} ${dest} - -uninstall: lib - ${lib}/module remove ${mods} ${dest} - -.PHONY: all lib install uninstall +${commands}: + ${lib}/modsync $@ ${flags} ${userflags} ${dest} ${mods} +.PHONY: ${commands} diff --git a/lib/subdirs.make b/lib/subdirs.make @@ -1,6 +1,10 @@ # Make sub-directories -install uninstall: +.include "commands.make" + +${commands}: .for subdir in ${subdirs} make -C ${subdir} $@ .endfor + +.PHONY: ${commands} diff --git a/local/Makefile b/local/Makefile @@ -1,5 +1,4 @@ lib = ../lib -act = link dest = ${HOME} mods =\ bin\