From ba12e68e0561fe2e00ff2a8da73c809e5e4c6e2d Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Fri, 28 Nov 2025 20:04:18 +0000 Subject: Add fstab2s6rc (untested), prepare for 2.6.4.0 --- .gitignore | 1 + NEWS | 3 +- doc/fstab2s6rc.html | 136 +++++++ doc/index.html | 7 +- doc/upgrade.html | 5 +- package/deps-build | 5 +- package/deps.mak | 4 + package/info | 2 +- package/modes | 1 + src/s6-linux-utils/deps-exe/fstab2s6rc | 1 + src/s6-linux-utils/fstab2s6rc.c | 647 +++++++++++++++++++++++++++++++++ src/s6-linux-utils/s6-mount.c | 18 +- src/s6-linux-utils/s6-swapoff.c | 22 +- src/s6-linux-utils/s6-swapon.c | 23 +- src/s6-linux-utils/s6-umount.c | 23 +- tools/gen-multicall.sh | 12 +- 16 files changed, 865 insertions(+), 45 deletions(-) create mode 100644 doc/fstab2s6rc.html create mode 100644 src/s6-linux-utils/deps-exe/fstab2s6rc create mode 100644 src/s6-linux-utils/fstab2s6rc.c diff --git a/.gitignore b/.gitignore index c6e68cd..5bb120b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ /src/include/s6-linux-utils/config.h /src/multicall/s6-linux-utils.c /s6-linux-utils +/fstab2s6rc /rngseed /s6-chroot /s6-freeramdisk diff --git a/NEWS b/NEWS index dde0bf3..7d8db99 100644 --- a/NEWS +++ b/NEWS @@ -1,10 +1,11 @@ Changelog for s6-linux-utils. -In 2.6.3.1 +In 2.6.4.0 ---------- - Bugfixes. - Support of shared libraries on MacOS. + - New binary: fstab2s6rc. In 2.6.3.0 diff --git a/doc/fstab2s6rc.html b/doc/fstab2s6rc.html new file mode 100644 index 0000000..388258a --- /dev/null +++ b/doc/fstab2s6rc.html @@ -0,0 +1,136 @@ + + + + + + s6-linux-utils: the fstab2s6rc program + + + + + + +

+s6-linux-utils
+Software
+skarnet.org +

+ +

The fstab2s6rc program

+ +

+ fstab2s6rc reads the /etc/fstab file, listing the filesystems and swap partitions +to mount at boot time, and builds a set of service definition directories from it, meant to +be fed to s6-rc-compile, having the +effect of mounting these partitions when run by s6-rc. +

+ +

+ This method has several advantages over the classic mount -a: +

+ + + +

+ fstab2s6rc is an offline tool. It does not perform mounts or unmounts itself; +it just converts the data in /etc/fstab, which is in a format usable by mount, +into a format usable — after compilation — by s6-rc. +

+ +

Interface

+ +
+     fstab2s6rc [ -A | -a ] [ -U | -u ] [ -E | -e ] [ -F fstab ] [ -m mode ] [ -B bundle ] [ -d basedep ] dir
+
+ + + +

Options

+ +
+
-F fstab, --fstab=fstab
+
Read mount point information from file fstab instead of /etc/fstab.
+ +
-m mode, --mode=mode
+
Create dir with permissions mode. mode is interpreted in octal.
+ +
-B bundle, --bundle=bundle
+
Create a bundle named bundle containing all the created services. +The mount point services will also be grouped under a bundle named bundle-mounts +and the swap services will be grouped under a bundle named bundle-swaps. +Services marked noauto will not be included in these bundles.
+ +
-d dep, --base-dependency=dep
+
Add a dependency to a service named dep to all the created services. +This is useful e.g. in a boot sequence to ensure that the mounts will not start before +a certain point.
+ +
-A, --include-noauto
+
Include mount points and swaps marked noauto in the output. These +services will not be marked as essential or recommended, and they will not be included +in any bundle, but they will be there. This is the default.
+ +
-a, --exclude-noauto
+
Exclude mount points and swaps marked noauto. No service will be created +for these fstab entries.
+ +
-U, --without-uuid
+
The created services will use s6-linux-utils commands such as +s6-mount and s6-swapon. +This makes the created services only depend on s6-linux-utils, but the fstab +entries must not contain util-linux-specific syntax such as UUID= or +LABEL= in place of device names. This is the default.
+ +
-u, --with-uuid
+
The created services will use util-linux commands such as +mount and +swapon. Running +the services will depend on having such commands installed, but syntax +for labels and uuids will be understood.
+ +
-E, --essential
+
Mark the services as essential, and do not create down scripts +for them. This makes services suitable to be part of a base init sequence where +all the listed filesystems are mounted early, and never unmounted until right +before the machine reboots. (noauto entries will not be marked as +essential.) This is the default.
+ +
-e, --not-essential
+
Mark the services as recommended rather than essential; create down +scripts to unmount the filesystem. This makes services suitable for being called +later than the base init sequence, as an optional part of a system's +functionality. Stopping the services will unmount the +corresponding filesystems and turn off the corresponding swap devices. +noauto entries will not be marked as recommended.
+
+ +

Exit codes

+ +
+
0
Success.
+
1
Invalid fstab file.
+
100
Incorrect usage.
+
111
system call failed
+ + + + diff --git a/doc/index.html b/doc/index.html index 52c02ce..67fcb58 100644 --- a/doc/index.html +++ b/doc/index.html @@ -50,6 +50,8 @@ The Linux kernel must be 3.5 or later. 2.14.5.0 or later. It's a build-time requirement. It's also a run-time requirement if you link against the shared version of the skalibs library. +
  • execline version +2.9.8.0 or later. It's a build-time requirement.
  • Licensing

    @@ -63,8 +65,8 @@ library.
    • The current released version of s6-linux-utils is -2.6.3.1. -You can access its checksum here.
    • +2.6.4.0. +You can access its checksum here.
    • Alternatively, you can checkout a copy of the s6-linux-utils git repository: @@ -107,6 +109,7 @@ the previous versions of s6-linux-utils and the current one.
    • (Miscellaneous tools)

        +
      • The fstab2s6rc program
      • The rngseed program
      • The s6-chroot program
      • The s6-freeramdisk program
      • diff --git a/doc/upgrade.html b/doc/upgrade.html index 2747b1c..b373afe 100644 --- a/doc/upgrade.html +++ b/doc/upgrade.html @@ -18,12 +18,15 @@

        What has changed in s6-linux-utils

        -

        in 2.6.3.1

        +

        in 2.6.4.0

        • skalibs dependency bumped to 2.14.5.0.
        • +
        • execline +dependency (to 2.9.8.0) introduced.
        • Shared libraries are now supported on MacOS.
        • +
        • New binary: fstab2s6rc.

        in 2.6.3.0

        diff --git a/package/deps-build b/package/deps-build index fb4d1da..32de94b 100644 --- a/package/deps-build +++ b/package/deps-build @@ -1,2 +1,3 @@ -true true /package/prog/skalibs 2.14.4.0 libskarnet -$usensss false /package/admin/nsss 0.2.1.0 libnsss +true true /package/prog/skalibs 2.14.5.0 libskarnet +$usensss false /package/admin/nsss 0.2.1.1 libnsss +true true /package/admin/execline 2.9.8.0 diff --git a/package/deps.mak b/package/deps.mak index 7ce090c..6440245 100644 --- a/package/deps.mak +++ b/package/deps.mak @@ -10,6 +10,8 @@ src/libs6ps/s6ps_pwcache.o src/libs6ps/s6ps_pwcache.lo: src/libs6ps/s6ps_pwcache src/libs6ps/s6ps_statparse.o src/libs6ps/s6ps_statparse.lo: src/libs6ps/s6ps_statparse.c src/include-local/s6ps.h src/libs6ps/s6ps_ttycache.o src/libs6ps/s6ps_ttycache.lo: src/libs6ps/s6ps_ttycache.c src/libs6ps/s6ps-internal.h src/include-local/s6ps.h src/libs6ps/s6ps_wchan.o src/libs6ps/s6ps_wchan.lo: src/libs6ps/s6ps_wchan.c src/include-local/s6ps.h +src/multicall/s6-linux-utils.o src/multicall/s6-linux-utils.lo: src/multicall/s6-linux-utils.c src/include/s6-linux-utils/config.h src/include-local/s6ps.h +src/s6-linux-utils/fstab2s6rc.o src/s6-linux-utils/fstab2s6rc.lo: src/s6-linux-utils/fstab2s6rc.c src/include/s6-linux-utils/config.h src/s6-linux-utils/rngseed.o src/s6-linux-utils/rngseed.lo: src/s6-linux-utils/rngseed.c src/include/s6-linux-utils/config.h src/s6-linux-utils/s6-chroot.o src/s6-linux-utils/s6-chroot.lo: src/s6-linux-utils/s6-chroot.c src/s6-linux-utils/s6-freeramdisk.o src/s6-linux-utils/s6-freeramdisk.lo: src/s6-linux-utils/s6-freeramdisk.c @@ -29,6 +31,8 @@ libs6ps.a.xyzzy:src/libs6ps/s6ps_cache.lo src/libs6ps/s6ps_grcache.lo src/libs6p endif s6-linux-utils: EXTRA_LIBS := ${SYSCLOCK_LIB} ${MAYBEPTHREAD_LIB} s6-linux-utils: src/multicall/s6-linux-utils.o libs6ps.a.xyzzy ${LIBNSSS} -lskarnet +fstab2s6rc: EXTRA_LIBS := +fstab2s6rc: src/s6-linux-utils/fstab2s6rc.o -lskarnet rngseed: EXTRA_LIBS := ${SYSCLOCK_LIB} rngseed: src/s6-linux-utils/rngseed.o -lskarnet s6-chroot: EXTRA_LIBS := diff --git a/package/info b/package/info index 2b1c106..f129083 100644 --- a/package/info +++ b/package/info @@ -1,4 +1,4 @@ package=s6-linux-utils -version=2.6.3.1 +version=2.6.4.0 category=admin package_macro_name=S6_LINUX_UTILS diff --git a/package/modes b/package/modes index aad1e20..13c1ca4 100644 --- a/package/modes +++ b/package/modes @@ -1,3 +1,4 @@ +fstab2s6rc 0755 rngseed 0744 s6-chroot 0744 s6-freeramdisk 0744 diff --git a/src/s6-linux-utils/deps-exe/fstab2s6rc b/src/s6-linux-utils/deps-exe/fstab2s6rc new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/s6-linux-utils/deps-exe/fstab2s6rc @@ -0,0 +1 @@ +-lskarnet diff --git a/src/s6-linux-utils/fstab2s6rc.c b/src/s6-linux-utils/fstab2s6rc.c new file mode 100644 index 0000000..e7fa3b8 --- /dev/null +++ b/src/s6-linux-utils/fstab2s6rc.c @@ -0,0 +1,647 @@ +/* ISC license. */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define USAGE "fstab2s6rc [ -A | -a ] [ -U | -u ] [ -E | -e ] [ -F fstab ] [ -m mode ] [ -B bundle ] [ -d basedep ] dir" +#define dieusage() strerr_dieusage(100, USAGE) +#define dienomem() do { strerr_warnfu1sys("stralloc_catb") ; return 111 ; } while (0) + +enum fstab_golb_e +{ + FSTAB_GOLB_SKIPNOAUTO = 0x01, + FSTAB_GOLB_UUID = 0x02, + FSTAB_GOLB_NOESSENTIAL = 0x04, +} ; + +enum fstab_gola_e +{ + FSTAB_GOLA_FSTAB, + FSTAB_GOLA_MODE, + FSTAB_GOLA_BUNDLE, + FSTAB_GOLA_BASEDEP, + FSTAB_GOLA_N +} ; + +enum fstab_flags_e +{ + FSTAB_FLAG_NOFAIL = 0x01, + FSTAB_FLAG_NOAUTO = 0x02, + FSTAB_FLAG_ISUUID = 0x04, + FSTAB_FLAG_ISLABEL = 0x08, +} ; + +typedef struct fstabent_s fstabent, *fstabent_ref ; +struct fstabent_s +{ + size_t device ; + size_t mountpoint ; + size_t qmountpoint ; + size_t type ; + size_t opts ; + size_t servicename ; + uint32_t flags ; + genalloc sublist ; /* fstabent */ +} ; +#define FSTABENT_ZERO { .submounts = GENALLOC_ZERO } + +typedef struct swapent_s swapent, *swapent_ref ; +struct swapent_s +{ + size_t device ; + size_t opts ; + size_t servicename ; + uint32_t flags ; +} ; + + +static int process_device (stralloc *sa, char const *dev, uint32_t *flags) +{ + if (str_start(dev, "UUID=")) + { + if (!stralloc_cats(sa, dev + 5) || !stralloc_0(sa)) dienomem() ; + *flags |= FSTAB_FLAG_ISUUID ; + } + else if (str_start(dev, "LABEL=")) + { + if (!string_quotes(sa, dev + 6) || !stralloc_0(sa)) dienomem() ; + *flags |= FSTAB_FLAG_ISLABEL ; + } + else if (!string_quotes(sa, dev) || !stralloc_0(sa)) dienomem() ; + return 0 ; +} + +static int process_opts (stralloc *sa, char *opts, uint32_t *flags) +{ + static char const *const ignore[] = + { + "comment", + "defaults", + "owner", + "user", + } ; + size_t sabase = sa->len ; + size_t len = strlen(opts) ; + size_t pos = 0 ; + while (pos < len) + { + size_t i = str_chr(opts + pos, ',') ; + opts[pos + i] = 0 ; + if (!strncmp(opts + pos, "x-", 2)) ; + else if (!strcmp(opts + pos, "nofail")) *flags |= FSTAB_FLAG_NOFAIL ; + else if (!strcmp(opts + pos, "noauto")) *flags |= FSTAB_FLAG_NOAUTO ; + else if (bsearch(opts + pos, ignore, sizeof(ignore)/sizeof(char const *), sizeof(char const *), &str_bcmp)) ; + else + if (!stralloc_cats(sa, opts + pos) || !stralloc_catb(sa, ",", 1)) dienomem() ; + pos += i+1 ; + } + if (sa->len > sabase) sa->s[sa->len - 1] = 0 ; + return 0 ; +} + +static int process_servicename (stralloc *sa, char const *name, int isswap) +{ + size_t len = strlen(name) + 1 ; + size_t i = name[0] == '/' ? 1 : 0 ; + if (!stralloc_cats(sa, isswap ? "swap-" : "mount-")) dienomem() ; + while (i < len) + if (!stralloc_catb(sa, name[i] == '/' ? ":" : name + i, 1)) dienomem() ; + return 0 ; +} + +static inline int add_swap (struct mntent *mnt, genalloc *ga, stralloc *sa, uint64_t options) +{ + swapent f = { .flags = 0 } ; + int e ; + f.device = sa->len ; + if (options & FSTAB_GOLB_UUID) + { + e = process_device(sa, mnt->mnt_fsname, &f.flags) ; + if (e) return e ; + } + else + if (!string_quotes(sa, mnt->mnt_fsname) || !stralloc_0(sa)) dienomem() ; + f.opts = sa->len ; + e = process_opts(sa, mnt->mnt_opts, &f.flags) ; + if (e) return e ; + f.servicename = sa->len ; + e = process_servicename(sa, mnt->mnt_fsname, 1) ; + if (e) return e ; + if (genalloc_catb(swapent, ga, &f, 1)) dienomem() ; + return 0 ; +} + +static genalloc *findpoint (char const *dir, genalloc *ga, char const *s) +{ + size_t n = genalloc_len(fstabent, ga) ; + fstabent *t = genalloc_s(fstabent, ga) ; + for (unsigned int i = 0 ; i < n ; i++) + { + size_t fslen = strlen(s + t[i].mountpoint) ; + if (!strncmp(dir, s + t[i].mountpoint, fslen)) + { + if (!dir[fslen]) + { + strerr_warnfu2x("duplicate mount point: ", dir) ; + return 0 ; + } + if (dir[fslen] == '/') + return findpoint(dir, &t[i].sublist, s) ; + } + } + return ga ; +} + +static inline int add_fs (struct mntent *mnt, genalloc *ga, stralloc *sa, uint64_t options) +{ + fstabent f = { .flags = 0 } ; + int e ; + ga = findpoint(mnt->mnt_dir, ga, sa->s) ; + if (!ga) return 1 ; + + f.device = sa->len ; + if (options & FSTAB_GOLB_UUID) + { + e = process_device(sa, mnt->mnt_fsname, &f.flags) ; + if (e) return e ; + } + else + if (!string_quotes(sa, mnt->mnt_fsname) || !stralloc_0(sa)) dienomem() ; + f.mountpoint = sa->len ; + if (!stralloc_cats(sa, mnt->mnt_dir) || !stralloc_0(sa)) dienomem() ; + f.qmountpoint = sa->len ; + if (!string_quotes(sa, mnt->mnt_dir) || !stralloc_0(sa)) dienomem() ; + f.type = sa->len ; + if (!stralloc_cats(sa, mnt->mnt_type) || !stralloc_0(sa)) dienomem() ; + f.opts = sa->len ; + e = process_opts(sa, mnt->mnt_opts, &f.flags) ; + if (e) return e ; + f.servicename = sa->len ; + e = process_servicename(sa, mnt->mnt_dir, 0) ; + if (e) return e ; + if (!genalloc_catb(fstabent, ga, &f, 1)) dienomem() ; + return 0 ; +} + +static int write_dependencies (char const *dir, char const *myname, fstabent const *tab, size_t n, char const *s) +{ + size_t dirlen = strlen(dir) ; + size_t mylen = myname ? strlen(myname) : 0 ; + int e ; + + for (size_t i = 0 ; i < n ; i++) + { + if (myname) + { + size_t slen = strlen(s + tab[i].servicename) ; + char fn[dirlen + 18 + slen + mylen] ; + memcpy(fn, dir, dirlen) ; + fn[dirlen] = '/' ; + memcpy(fn + dirlen + 1, s + tab[i].servicename, slen) ; + memcpy(fn + dirlen + 1 + slen, "/dependencies.d/", 16) ; + memcpy(fn + dirlen + slen + 17, myname, mylen + 1) ; + if (!openwritenclose_unsafe5(fn, "", 0, 0, 0)) { strerr_warnfu2sys("touch ", fn) ; return 111 ; } + } + e = write_dependencies(dir, s + tab[i].servicename, genalloc_s(fstabent, &tab[i].sublist), genalloc_len(fstabent, &tab[i].sublist), s) ; + if (e) return e ; + } + return 0 ; +} + +static inline int write_fses (char const *dir, fstabent const *tab, size_t n, char const *s, uint64_t options, char const *bundle, char const *basedep) +{ + char buf[4096] ; + buffer b ; + int fd ; + size_t dirlen = strlen(dir) ; + for (size_t i = 0 ; i < n ; i++) + { + mode_t m = umask(0) ; + size_t slen = strlen(s + tab[i].servicename) ; + char fn[dirlen + slen + 19] ; + memcpy(fn, dir, dirlen) ; + fn[dirlen] = '/' ; + memcpy(fn + dirlen + 1, s + tab[i].servicename, slen + 1) ; + if (mkdir(fn, 0755) == -1) { strerr_warnfu2sys("mkdir ", fn) ; return 111 ; } + memcpy(fn + dirlen + 1 + slen, "/dependencies.d", 16) ; + if (mkdir(fn, 0755) == -1) { strerr_warnfu2sys("mkdir ", fn) ; return 111 ; } + umask(m) ; + + memcpy(fn + dirlen + 2 + slen, "type", 5) ; + if (!openwritenclose_unsafe5(fn, "oneshot\n", 8, 0, 0)) goto err1n ; + + if (!(tab[i].flags & FSTAB_FLAG_NOAUTO)) + { + memcpy(fn + dirlen + 2 + slen, "flag-", 5) ; + memcpy(fn + dirlen + 7 + slen, options & FSTAB_GOLB_NOESSENTIAL ? "essential" : "recommended", options & FSTAB_GOLB_NOESSENTIAL ? 10 : 12) ; + if (!openwritenclose_unsafe5(fn, "", 0, 0, 0)) goto err1n ; + } + + memcpy(fn + dirlen + 2 + slen, "down", 5) ; + if (tab[i].flags & FSTAB_FLAG_NOAUTO || options & FSTAB_GOLB_NOESSENTIAL) + { + fd = open_create(fn) ; + if (fd == -1) { strerr_warnfu3sys("open ", fn, " for writing") ; return 111 ; } + buffer_init(&b, &buffer_write, fd, buf, 4096) ; + if (buffer_puts(&b, EXECLINE_EXTBINPREFIX "foreground { ") < 0) goto err1 ; + if (options & FSTAB_GOLB_UUID) + { + if (buffer_puts(&b, "umount -l -- ") < 0) goto err1 ; + } + else + { + if (buffer_puts(&b, S6_LINUX_UTILS_BINPREFIX "s6-umount -- ") < 0) goto err1 ; + } + if (buffer_puts(&b, s + tab[i].qmountpoint) < 0 + || buffer_puts(&b, " }\n" EXECLINE_EXTBINPREFIX "exit 0") < 0 + || buffer_putflush(&b, "\n", 1) < 0) goto err1 ; + fd_close(fd) ; + goto ok1 ; + err1: + fd_close(fd) ; + err1n: + strerr_warnfu2sys("write to ", fn) ; + return 111 ; + ok1: + } + else if (!openwritenclose_unsafe5(fn, "", 0, 0, 0)) goto err2n ; + + memcpy(fn + dirlen + 2 + slen, "up", 3) ; + fd = open_create(fn) ; + if (fd == -1) { strerr_warnfu3sys("open ", fn, " for writing") ; return 111 ; } + buffer_init(&b, &buffer_write, fd, buf, 4096) ; + if (tab[i].flags & FSTAB_FLAG_NOFAIL) + if (buffer_puts(&b, EXECLINE_EXTBINPREFIX "foreground { ") < 0) goto err2 ; + if (options & FSTAB_GOLB_UUID) + { + if (buffer_puts(&b, "mount") < 0) goto err2 ; + if (tab[i].flags & FSTAB_FLAG_ISUUID) + { + if (buffer_puts(&b, " -U ") < 0 + || buffer_puts(&b, s + tab[i].device) < 0) goto err2 ; + } + else if (tab[i].flags & FSTAB_FLAG_ISLABEL) + { + if (buffer_puts(&b, " -L ") < 0 + || buffer_puts(&b, s + tab[i].device) < 0) goto err2 ; + } + } + else + { + if (buffer_puts(&b, S6_LINUX_UTILS_BINPREFIX "s6-mount") < 0) goto err2 ; + } + if (buffer_puts(&b, " -t ") < 0 + || buffer_puts(&b, s + tab[i].type) < 0) goto err2 ; + if (s[tab[i].opts]) + { + if (buffer_puts(&b, " -o ") < 0 + || buffer_puts(&b, s + tab[i].opts) < 0) goto err2 ; + } + if (buffer_put(&b, " -- ", 1) < 0) goto err2 ; + if (!(options & FSTAB_GOLB_UUID && (tab[i].flags & (FSTAB_FLAG_ISUUID | FSTAB_FLAG_ISLABEL)))) + { + if (buffer_puts(&b, s + tab[i].device) < 0 + || buffer_put(&b, " ", 1) < 0) goto err2 ; + } + if (buffer_puts(&b, s + tab[i].qmountpoint) < 0) goto err2 ; + if (tab[i].flags & FSTAB_FLAG_NOFAIL) + if (buffer_puts(&b, " }\n" EXECLINE_EXTBINPREFIX "exit 0") < 0) goto err2 ; + if (buffer_putflush(&b, "\n", 1) < 0) goto err2 ; + fd_close(fd) ; + goto ok2 ; + err2: + fd_close(fd) ; + err2n: + strerr_warnfu2sys("write to ", fn) ; + return 111 ; + ok2: + } + + if (bundle) + { + mode_t m = umask(0) ; + size_t blen = strlen(bundle) ; + char bdir[dirlen + blen + 20] ; + memcpy(bdir, dir, dirlen) ; + memcpy(bdir + dirlen, "-mounts", 7) ; + bdir[dirlen + 7] = '/' ; + memcpy(bdir + dirlen + 7, bundle, blen + 1) ; + if (mkdir(bdir, 0755) == -1) { strerr_warnfu2sys("mkdir ", bdir) ; return 111 ; } + memcpy(bdir + dirlen + blen + 8, "/type", 6) ; + if (!openwritenclose_unsafe5(bdir, "bundle\n", 7, 0, 0)) { strerr_warnfu2sys("write to ", bdir) ; return 111 ; } + memcpy(bdir + dirlen + blen + 8, "contents.d", 11) ; + if (mkdir(bdir, 0755) == -1) { strerr_warnfu2sys("mkdir ", bdir) ; return 111 ; } + umask(m) ; + bdir[dirlen + blen + 19] = '/' ; + for (size_t i = 0 ; i < n ; i++) if (!(tab[i].flags & FSTAB_FLAG_NOAUTO)) + { + size_t slen = strlen(s + tab[i].servicename) ; + char sfn[dirlen + blen + 21 + slen] ; + memcpy(sfn, bdir, dirlen + blen + 20) ; + memcpy(sfn + dirlen + blen + 20, s + tab[i].servicename, slen + 1) ; + if (!openwritenclose_unsafe5(sfn, "", 0, 0, 0)) { strerr_warnfu2sys("touch ", sfn) ; return 111 ; } + } + } + + return write_dependencies(dir, basedep, tab, n, s) ; +} + +static inline int write_swaps (char const *dir, swapent const *tab, size_t n, char const *s, uint64_t options, char const *bundle, char const *basedep) +{ + char buf[4096] ; + buffer b ; + int fd ; + size_t dirlen = strlen(dir) ; + size_t bdlen = basedep ? strlen(basedep) : 0 ; + for (size_t i = 0 ; i < n ; i++) + { + mode_t m = umask(0) ; + size_t slen = strlen(s + tab[i].servicename) ; + char fn[dirlen + slen + 19 + bdlen] ; + memcpy(fn, dir, dirlen) ; + fn[dirlen] = '/' ; + memcpy(fn + dirlen + 1, s + tab[i].servicename, slen + 1) ; + if (mkdir(fn, 0755) == -1) { strerr_warnfu2sys("mkdir ", fn) ; return 111 ; } + memcpy(fn + dirlen + 1 + slen, "/dependencies.d", 16) ; + if (mkdir(fn, 0755) == -1) { strerr_warnfu2sys("mkdir ", fn) ; return 111 ; } + umask(m) ; + + if (basedep) + { + fn[dirlen + slen + 16] = '/' ; + memcpy(fn + dirlen + slen + 17, basedep, bdlen + 1) ; + if (!openwritenclose_unsafe5(fn, "", 0, 0, 0)) goto err1n ; + } + + memcpy(fn + dirlen + 2 + slen, "type", 5) ; + if (!openwritenclose_unsafe5(fn, "oneshot\n", 8, 0, 0)) goto err1n ; + + if (!(tab[i].flags & FSTAB_FLAG_NOAUTO)) + { + memcpy(fn + dirlen + 2 + slen, "flag-", 5) ; + memcpy(fn + dirlen + 7 + slen, options & FSTAB_GOLB_NOESSENTIAL ? "essential" : "recommended", options & FSTAB_GOLB_NOESSENTIAL ? 10 : 12) ; + if (!openwritenclose_unsafe5(fn, "", 0, 0, 0)) goto err1n ; + } + + memcpy(fn + dirlen + 2 + slen, "down", 5) ; + if (tab[i].flags & FSTAB_FLAG_NOAUTO || options & FSTAB_GOLB_NOESSENTIAL) + { + fd = open_create(fn) ; + if (fd == -1) { strerr_warnfu3sys("open ", fn, " for writing") ; return 111 ; } + buffer_init(&b, &buffer_write, fd, buf, 4096) ; + if (buffer_puts(&b, EXECLINE_EXTBINPREFIX "foreground { ") < 0) goto err1 ; + if (options & FSTAB_GOLB_UUID) + { + if (buffer_puts(&b, "swapoff ") < 0) goto err1 ; + if (tab[i].flags & FSTAB_FLAG_ISUUID) + { + if (buffer_puts(&b, "-U ") < 0) goto err1 ; + } + else if (tab[i].flags & FSTAB_FLAG_ISLABEL) + { + if (buffer_puts(&b, "-L ") < 0) goto err1 ; + } + } + else + { + if (buffer_puts(&b, S6_LINUX_UTILS_BINPREFIX "s6-swapoff -- ") < 0) goto err1 ; + } + if (buffer_puts(&b, s + tab[i].device) < 0 + || buffer_puts(&b, " }\n" EXECLINE_EXTBINPREFIX "exit 0") < 0 + || buffer_putflush(&b, "\n", 1) < 0) goto err1 ; + fd_close(fd) ; + goto ok1 ; + err1: + fd_close(fd) ; + err1n: + strerr_warnfu2sys("write to ", fn) ; + return 111 ; + ok1: + } + else if (!openwritenclose_unsafe5(fn, "", 0, 0, 0)) goto err2n ; + + memcpy(fn + dirlen + 2 + slen, "up", 3) ; + fd = open_create(fn) ; + if (fd == -1) { strerr_warnfu3sys("open ", fn, " for writing") ; return 111 ; } + buffer_init(&b, &buffer_write, fd, buf, 4096) ; + if (tab[i].flags & FSTAB_FLAG_NOFAIL) + if (buffer_puts(&b, EXECLINE_EXTBINPREFIX "foreground { ") < 0) goto err2 ; + if (options & FSTAB_GOLB_UUID) + { + if (buffer_puts(&b, "swapon") < 0) goto err2 ; + if (tab[i].flags & FSTAB_FLAG_ISUUID) + { + if (buffer_puts(&b, " -U ") < 0 + || buffer_puts(&b, s + tab[i].device) < 0) goto err2 ; + } + else if (tab[i].flags & FSTAB_FLAG_ISLABEL) + { + if (buffer_puts(&b, " -L ") < 0 + || buffer_puts(&b, s + tab[i].device) < 0) goto err2 ; + } + if (s[tab[i].opts]) + { + if (buffer_puts(&b, " -o ") < 0 + || buffer_puts(&b, s + tab[i].opts) < 0) goto err2 ; + } + } + else + { + if (buffer_puts(&b, S6_LINUX_UTILS_BINPREFIX "s6-swapon --") < 0) goto err2 ; + } + if (buffer_put(&b, " ", 1) < 0 + || buffer_puts(&b, s + tab[i].device) < 0) goto err2 ; + if (tab[i].flags & FSTAB_FLAG_NOFAIL) + if (buffer_puts(&b, " }\n" EXECLINE_EXTBINPREFIX "exit 0") < 0) goto err2 ; + if (buffer_putflush(&b, "\n", 1) < 0) goto err2 ; + fd_close(fd) ; + goto ok2 ; + err2: + fd_close(fd) ; + err2n: + strerr_warnfu2sys("write to ", fn) ; + return 111 ; + ok2: + } + + if (bundle) + { + size_t blen = strlen(bundle) ; + char bdir[dirlen + blen + 19] ; + memcpy(bdir, dir, dirlen) ; + memcpy(bdir + dirlen, "-swaps", 6) ; + bdir[dirlen + 6] = '/' ; + memcpy(bdir + dirlen + 7, bundle, blen + 1) ; + if (mkdir(bdir, 0755) == -1) { strerr_warnfu2sys("mkdir ", bdir) ; return 111 ; } + memcpy(bdir + dirlen + blen + 7, "/type", 6) ; + if (!openwritenclose_unsafe5(bdir, "bundle\n", 7, 0, 0)) { strerr_warnfu2sys("write to ", bdir) ; return 111 ; } + memcpy(bdir + dirlen + blen + 7, "contents.d", 11) ; + if (mkdir(bdir, 0755) == -1) { strerr_warnfu2sys("mkdir ", bdir) ; return 111 ; } + bdir[dirlen + blen + 18] = '/' ; + for (size_t i = 0 ; i < n ; i++) if (!(tab[i].flags & FSTAB_FLAG_NOAUTO)) + { + size_t slen = strlen(s + tab[i].servicename) ; + char sfn[dirlen + blen + 20 + slen] ; + memcpy(sfn, bdir, dirlen + blen + 19) ; + memcpy(sfn + dirlen + blen + 19, s + tab[i].servicename, slen + 1) ; + if (!openwritenclose_unsafe5(sfn, "", 0, 0, 0)) { strerr_warnfu2sys("touch ", sfn) ; return 111 ; } + } + } + return 0 ; +} + +static inline int write_bundle (char const *dir, char const *bundle) +{ + mode_t m = umask(0) ; + size_t dirlen = strlen(dir) ; + size_t blen = strlen(bundle) ; + char bdir[dirlen + 22 + 2 * blen] ; + memcpy(bdir, dir, dirlen) ; + bdir[dirlen] = '/' ; + memcpy(bdir + dirlen + 1, bundle, blen + 1) ; + if (mkdir(bdir, 0755) == -1) { strerr_warnfu2sys("mkdir ", bdir) ; return 111 ; } + memcpy(bdir + dirlen + blen + 1, "/type", 6) ; + if (!openwritenclose_unsafe5(bdir, "bundle\n", 7, 0, 0)) { strerr_warnfu2sys("write to ", bdir) ; return 111 ; } + memcpy(bdir + dirlen + blen + 2, "contents.d", 11) ; + if (mkdir(bdir, 0755) == -1) { strerr_warnfu2sys("mkdir ", bdir) ; return 111 ; } + umask(m) ; + bdir[dirlen + blen + 13] = '/' ; + memcpy(bdir + dirlen + blen + 14, bundle, blen) ; + memcpy(bdir + dirlen + 14 + 2 * blen, "-swaps", 7) ; + if (!openwritenclose_unsafe5(bdir, "", 0, 0, 0)) { strerr_warnfu2sys("touch ", bdir) ; return 111 ; } + memcpy(bdir + dirlen + 15 + 2 * blen, "mounts", 7) ; + if (!openwritenclose_unsafe5(bdir, "", 0, 0, 0)) { strerr_warnfu2sys("touch ", bdir) ; return 111 ; } + return 0 ; +} + +static inline int doit (char const *fstab, char const *dir, uint64_t options, char const *bundle, char const *basedep, stralloc *sa) +{ + genalloc fses = GENALLOC_ZERO ; /* fstabent */ + genalloc swaps = GENALLOC_ZERO ; /* swapent */ + int e ; + + FILE *in = setmntent(fstab, "re") ; + for (;;) + { + struct mntent *mnt ; + errno = 0 ; + mnt = getmntent(in) ; + if (!mnt) break ; + if (options & FSTAB_GOLB_SKIPNOAUTO && hasmntopt(mnt, "noauto")) continue ; + if (strcmp(mnt->mnt_type, "swap")) + e = add_fs(mnt, &fses, sa, options) ; + else + e = add_swap(mnt, &swaps, sa, options) ; + if (e) + { + endmntent(in) ; + return e ; + } + } + if (errno) + { + strerr_warnfu2sys("getmntent ", fstab) ; + endmntent(in) ; + return e ; + } + endmntent(in) ; + + e = write_fses(dir, genalloc_s(fstabent, &fses), genalloc_len(fstabent, &fses), sa->s, options, bundle, basedep) ; + if (e) return e ; + e = write_swaps(dir, genalloc_s(swapent, &swaps), genalloc_len(swapent, &swaps), sa->s, options, bundle, basedep) ; + if (e) return e ; + if (bundle) + { + e = write_bundle(dir, bundle) ; + if (e) return e ; + } + + return 0 ; +} + +int main (int argc, char const *const *argv) +{ + static gol_bool const rgolb[] = + { + { .so = 'A', .lo = "include-noauto", .clear = FSTAB_GOLB_SKIPNOAUTO, .set = 0 }, + { .so = 'a', .lo = "exclude-noauto", .clear = 0, .set = FSTAB_GOLB_SKIPNOAUTO }, + { .so = 'U', .lo = "without-uuid", .clear = FSTAB_GOLB_UUID, .set = 0 }, + { .so = 'u', .lo = "with-uuid", .clear = 0, .set = FSTAB_GOLB_UUID }, + { .so = 'E', .lo = "essential", .clear = FSTAB_GOLB_NOESSENTIAL, .set = 0 }, + { .so = 'e', .lo = "not-essential", .clear = 0, .set = FSTAB_GOLB_NOESSENTIAL }, + } ; + static gol_arg const rgola[] = + { + { .so = 'F', .lo = "fstab", .i = FSTAB_GOLA_FSTAB }, + { .so = 'm', .lo = "mode", .i = FSTAB_GOLA_MODE }, + { .so = 'B', .lo = "bundle", .i = FSTAB_GOLA_BUNDLE }, + { .so = 'd', .lo = "base-dependency", .i = FSTAB_GOLA_BASEDEP }, + } ; + stralloc storage = STRALLOC_ZERO ; + uint64_t wgolb = 0 ; + unsigned int mode = 0755 ; + unsigned int golc ; + char const *wgola[FSTAB_GOLA_N] = { 0 } ; + + PROG = "fstab2s6rc" ; + wgola[FSTAB_GOLA_FSTAB] = "/etc/fstab" ; + golc = GOL_main(argc, argv, rgolb, rgola, &wgolb, wgola) ; + argc -= golc ; argv += golc ; + if (!argc) dieusage() ; + if (wgola[FSTAB_GOLA_MODE] && !uint0_oscan(wgola[FSTAB_GOLA_MODE], &mode)) dieusage() ; + + if (access(argv[0], F_OK) == -1) + { + if (errno != ENOENT) strerr_diefu2sys(111, "access ", argv[0]) ; + } + else strerr_dief2x(111, argv[0], "already exists") ; + + { + mode_t m = umask(0) ; + int e ; + size_t dirlen = strlen(argv[0]) ; + char dir[dirlen + 8] ; + memcpy(dir, argv[0], dirlen) ; + memcpy(dir + dirlen, ":XXXXXX", 8) ; + if (!mkdtemp(dir)) strerr_diefu2sys(111, "mkdtemp ", dir) ; + umask(m) ; + e = doit(wgola[FSTAB_GOLA_FSTAB], dir, wgolb, wgola[FSTAB_GOLA_BUNDLE], wgola[FSTAB_GOLA_BASEDEP], &storage) ; + if (e) + { + rm_rf(dir) ; + _exit(e) ; + } + if (chmod(dir, mode) == -1) + { + rm_rf(dir) ; + strerr_diefu2sys(111, "chmod ", dir) ; + } + if (rename(dir, argv[0]) == -1) + { + rm_rf(dir) ; + strerr_diefu4sys(111, "rename ", dir, " to ", argv[0]) ; + } + } + return 0 ; +} diff --git a/src/s6-linux-utils/s6-mount.c b/src/s6-linux-utils/s6-mount.c index 997ef33..4d20424 100644 --- a/src/s6-linux-utils/s6-mount.c +++ b/src/s6-linux-utils/s6-mount.c @@ -15,7 +15,7 @@ #include "mount-constants.h" -#define USAGE "s6-mount -a [ -z fstab ] | s6-mount [ -n ] [ -t type ] [ -o option[,option...] ]... device mountpoint" +#define USAGE "s6-mount [ -a ] [ -z fstab ] | s6-mount [ -n ] [ -t type ] [ -o option[,option...] ]... device mountpoint" #define dienomem() strerr_diefu1sys(111, "stralloc_catb") struct mount_flag_modif_s @@ -100,25 +100,29 @@ static void mount_scanopt (stralloc *data, unsigned long *flags, char const *s) static int mountall (char const *fstab) { - struct mntent *d ; int e = 0 ; + stralloc data = STRALLOC_ZERO ; FILE *yuck = setmntent(fstab, "r") ; if (!yuck) strerr_diefu2sys(111, "open ", fstab) ; - while ((d = getmntent(yuck))) + for (;;) { unsigned long flags = 0 ; - stralloc data = STRALLOC_ZERO ; + struct mntent *d ; + errno = 0 ; + d = getmntent(yuck) ; + if (!d) break ; mount_scanopt(&data, &flags, d->mnt_opts) ; - if (!stralloc_0(&data)) - strerr_diefu1sys(111, "build data string") ; + if (!stralloc_0(&data)) strerr_diefu1sys(111, "build data string") ; if (mount(d->mnt_fsname, d->mnt_dir, d->mnt_type, flags, data.s) == -1) { e++ ; strerr_warnwu4sys("mount ", d->mnt_fsname, " on ", d->mnt_dir) ; } - stralloc_free(&data) ; + data.len = 0 ; } + if (errno) strerr_diefu2sys(111, "getmntent on ", fstab) ; endmntent(yuck) ; + // stralloc_free(&data) ; return e ; } diff --git a/src/s6-linux-utils/s6-swapoff.c b/src/s6-linux-utils/s6-swapoff.c index 13a2530..905d9e8 100644 --- a/src/s6-linux-utils/s6-swapoff.c +++ b/src/s6-linux-utils/s6-swapoff.c @@ -5,14 +5,15 @@ #include #include +#include #include #include -#include +#include #include #include #include -#define USAGE "s6-swapoff device s6-swapoff -a" +#define USAGE "s6-swapoff [ -a ] [ device ]" static int swapoffall (void) { @@ -44,10 +45,17 @@ static int swapoffall (void) int main (int argc, char const *const *argv) { + static gol_bool const rgolb[] = + { + { .so = 'a', .lo = "all", .clear = 0, .set = 1 }, + } ; + uint64_t wgolb = 0 ; + unsigned int golc ; PROG = "s6-swapoff" ; - if (argc < 2) strerr_dieusage(100, USAGE) ; - if ((argv[1][0] == '-') && (argv[1][1] == 'a') && !argv[1][2]) - return swapoffall() ; - if (swapoff(argv[1]) == -1) strerr_diefu2sys(111, "swapoff ", argv[1]) ; - return 0 ; + golc = gol_main(argc, argv, rgolb, 1, 0, 0, &wgolb, 0) ; + argc -= golc ; argv += golc ; + if (wgolb & 1) _exit(swapoffall()) ; + if (!argc) strerr_dieusage(100, USAGE) ; + if (swapoff(argv[0]) == -1) strerr_diefu2sys(111, "swapoff ", argv[0]) ; + _exit(0) ; } diff --git a/src/s6-linux-utils/s6-swapon.c b/src/s6-linux-utils/s6-swapon.c index d9166a7..f55f1ce 100644 --- a/src/s6-linux-utils/s6-swapon.c +++ b/src/s6-linux-utils/s6-swapon.c @@ -6,9 +6,10 @@ #include #include -#include +#include +#include -#define USAGE "s6-swapon device s6-swapon -a" +#define USAGE "s6-swapon [ -a ] [ device ]" static int swaponall (void) { @@ -28,11 +29,17 @@ static int swaponall (void) int main (int argc, char const *const *argv) { + static gol_bool const rgolb[] = + { + { .so = 'a', .lo = "all", .clear = 0, .set = 1 }, + } ; + uint64_t wgolb = 0 ; + unsigned int golc ; PROG = "s6-swapon" ; - if (argc < 2) strerr_dieusage(100, USAGE) ; - if ((argv[1][0] == '-') && (argv[1][1] == 'a') && !argv[1][2]) - return swaponall() ; - if (swapon(argv[1], 0) == -1) - strerr_diefu2sys(111, "swapon ", argv[1]) ; - return 0 ; + golc = gol_main(argc, argv, rgolb, 1, 0, 0, &wgolb, 0) ; + argc -= golc ; argv += golc ; + if (wgolb & 1) _exit(swaponall()) ; + if (!argc) strerr_dieusage(100, USAGE) ; + if (swapon(argv[0], 0) == -1) strerr_diefu2sys(111, "swapon ", argv[0]) ; + _exit(0) ; } diff --git a/src/s6-linux-utils/s6-umount.c b/src/s6-linux-utils/s6-umount.c index 8a9b918..256ab00 100644 --- a/src/s6-linux-utils/s6-umount.c +++ b/src/s6-linux-utils/s6-umount.c @@ -2,15 +2,17 @@ #include #include +#include +#include #include #include -#include +#include #include #include #include -#define USAGE "s6-umount mountpoint s6-umount -a" +#define USAGE "s6-umount [ -a ] [ mountpoint ]" #define UMOUNTALL_MAXLINES 512 @@ -58,10 +60,17 @@ static int umountall (void) int main (int argc, char const *const *argv) { + static gol_bool const rgolb[] = + { + { .so = 'a', .lo = "all", .clear = 0, .set = 1 }, + } ; + uint64_t wgolb = 0 ; + unsigned int golc ; PROG = "s6-umount" ; - if (argc < 2) strerr_dieusage(100, USAGE) ; - if ((argv[1][0] == '-') && (argv[1][1] == 'a') && !argv[1][2]) - return umountall() ; - if (umount(argv[1]) == -1) strerr_diefu2sys(111, "umount ", argv[1]) ; - return 0 ; + golc = gol_main(argc, argv, rgolb, 1, 0, 0, &wgolb, 0) ; + argc -= golc ; argv += golc ; + if (wgolb & 1) _exit(umountall()) ; + if (!argc) strerr_dieusage(100, USAGE) ; + if (umount(argv[0]) == -1) strerr_diefu2sys(111, "unmount ", argv[0]) ; + _exit(0) ; } diff --git a/tools/gen-multicall.sh b/tools/gen-multicall.sh index 130f5b0..bac28d7 100755 --- a/tools/gen-multicall.sh +++ b/tools/gen-multicall.sh @@ -9,7 +9,7 @@ echo '/* ISC license. */' echo echo '#include ' echo -{ echo '#include ' ; echo '#include ' ; cat src/$P/*.c | grep '^#include <' | grep -vF '' ; echo '#include ' ; cat src/$P/*.c | grep '^#include <' | grep -vF -e 'name) ; -} EOF for i in `ls -1 src/$P/deps-exe` ; do @@ -72,7 +66,7 @@ static int ${p}_main (int argc, char const *const *argv, char const *const *envp multicall_app const *p ; PROG = "$P" ; if (argc < 2) dieusage() ; - p = bsearch(argv[1], multicall_apps, sizeof(multicall_apps) / sizeof(multicall_app), sizeof(multicall_app), &multicall_app_cmp) ; + p = bsearch(argv[1], multicall_apps, sizeof(multicall_apps) / sizeof(multicall_app), sizeof(multicall_app), &str_bcmp) ; if (!p) strerr_dief2x(100, "unknown subcommand: ", argv[1]) ; return (*(p->mainf))(argc-1, argv+1, envp) ; } @@ -82,7 +76,7 @@ int main (int argc, char const *const *argv, char const *const *envp) multicall_app const *p ; char const *name = strrchr(argv[0], '/') ; if (name) name++ ; else name = argv[0] ; - p = bsearch(name, multicall_apps, sizeof(multicall_apps) / sizeof(multicall_app), sizeof(multicall_app), &multicall_app_cmp) ; + p = bsearch(name, multicall_apps, sizeof(multicall_apps) / sizeof(multicall_app), sizeof(multicall_app), &str_bcmp) ; return p ? (*(p->mainf))(argc, argv, envp) : ${p}_main(argc, argv, envp) ; } EOF -- cgit v1.3.1