diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2014-09-19 02:53:32 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2014-09-19 02:53:32 +0000 |
commit | bea0037dbdd979603fb0b5be8b43f5478c1f6fec (patch) | |
tree | 5776ae3af5a3e83d41c7087f70713952b6360988 /src | |
download | s6-portable-utils-bea0037dbdd979603fb0b5be8b43f5478c1f6fec.tar.xz |
initial commit
Diffstat (limited to 'src')
78 files changed, 3505 insertions, 0 deletions
diff --git a/src/skaembutils/deps-exe/s6-basename b/src/skaembutils/deps-exe/s6-basename new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-basename @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-cat b/src/skaembutils/deps-exe/s6-cat new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-cat @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-chmod b/src/skaembutils/deps-exe/s6-chmod new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-chmod @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-chown b/src/skaembutils/deps-exe/s6-chown new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-chown @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-clock b/src/skaembutils/deps-exe/s6-clock new file mode 100644 index 0000000..a11a5f4 --- /dev/null +++ b/src/skaembutils/deps-exe/s6-clock @@ -0,0 +1,2 @@ +-lskarnet +${SYSCLOCK_LIB} diff --git a/src/skaembutils/deps-exe/s6-cut b/src/skaembutils/deps-exe/s6-cut new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-cut @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-dirname b/src/skaembutils/deps-exe/s6-dirname new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-dirname @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-echo b/src/skaembutils/deps-exe/s6-echo new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-echo @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-env b/src/skaembutils/deps-exe/s6-env new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-env @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-expr b/src/skaembutils/deps-exe/s6-expr new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-expr @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-false b/src/skaembutils/deps-exe/s6-false new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/skaembutils/deps-exe/s6-false diff --git a/src/skaembutils/deps-exe/s6-format-filter b/src/skaembutils/deps-exe/s6-format-filter new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-format-filter @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-grep b/src/skaembutils/deps-exe/s6-grep new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-grep @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-head b/src/skaembutils/deps-exe/s6-head new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-head @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-linkname b/src/skaembutils/deps-exe/s6-linkname new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-linkname @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-ln b/src/skaembutils/deps-exe/s6-ln new file mode 100644 index 0000000..e027835 --- /dev/null +++ b/src/skaembutils/deps-exe/s6-ln @@ -0,0 +1,3 @@ +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/skaembutils/deps-exe/s6-ls b/src/skaembutils/deps-exe/s6-ls new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-ls @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-maximumtime b/src/skaembutils/deps-exe/s6-maximumtime new file mode 100644 index 0000000..1840bc1 --- /dev/null +++ b/src/skaembutils/deps-exe/s6-maximumtime @@ -0,0 +1,2 @@ +-lskarnet +${TAINNOW_LIB} diff --git a/src/skaembutils/deps-exe/s6-mkdir b/src/skaembutils/deps-exe/s6-mkdir new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-mkdir @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-mkfifo b/src/skaembutils/deps-exe/s6-mkfifo new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-mkfifo @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-nice b/src/skaembutils/deps-exe/s6-nice new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-nice @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-nuke b/src/skaembutils/deps-exe/s6-nuke new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-nuke @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-pause b/src/skaembutils/deps-exe/s6-pause new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/skaembutils/deps-exe/s6-pause diff --git a/src/skaembutils/deps-exe/s6-printenv b/src/skaembutils/deps-exe/s6-printenv new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-printenv @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-quote b/src/skaembutils/deps-exe/s6-quote new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-quote @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-quote-filter b/src/skaembutils/deps-exe/s6-quote-filter new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-quote-filter @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-rename b/src/skaembutils/deps-exe/s6-rename new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-rename @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-rmrf b/src/skaembutils/deps-exe/s6-rmrf new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-rmrf @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-sleep b/src/skaembutils/deps-exe/s6-sleep new file mode 100644 index 0000000..1840bc1 --- /dev/null +++ b/src/skaembutils/deps-exe/s6-sleep @@ -0,0 +1,2 @@ +-lskarnet +${TAINNOW_LIB} diff --git a/src/skaembutils/deps-exe/s6-sort b/src/skaembutils/deps-exe/s6-sort new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-sort @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-sync b/src/skaembutils/deps-exe/s6-sync new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/skaembutils/deps-exe/s6-sync diff --git a/src/skaembutils/deps-exe/s6-tail b/src/skaembutils/deps-exe/s6-tail new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-tail @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-test b/src/skaembutils/deps-exe/s6-test new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-test @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-touch b/src/skaembutils/deps-exe/s6-touch new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-touch @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-true b/src/skaembutils/deps-exe/s6-true new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/skaembutils/deps-exe/s6-true diff --git a/src/skaembutils/deps-exe/s6-uniquename b/src/skaembutils/deps-exe/s6-uniquename new file mode 100644 index 0000000..e027835 --- /dev/null +++ b/src/skaembutils/deps-exe/s6-uniquename @@ -0,0 +1,3 @@ +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/skaembutils/deps-exe/s6-unquote b/src/skaembutils/deps-exe/s6-unquote new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-unquote @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-unquote-filter b/src/skaembutils/deps-exe/s6-unquote-filter new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/skaembutils/deps-exe/s6-unquote-filter @@ -0,0 +1 @@ +-lskarnet diff --git a/src/skaembutils/deps-exe/s6-update-symlinks b/src/skaembutils/deps-exe/s6-update-symlinks new file mode 100644 index 0000000..e027835 --- /dev/null +++ b/src/skaembutils/deps-exe/s6-update-symlinks @@ -0,0 +1,3 @@ +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/skaembutils/s6-basename.c b/src/skaembutils/s6-basename.c new file mode 100644 index 0000000..113e14b --- /dev/null +++ b/src/skaembutils/s6-basename.c @@ -0,0 +1,45 @@ +/* ISC license. */ + +#include <skalibs/sgetopt.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/bytestr.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/djbunix.h> + +#define USAGE "s6-basename [ -n ] file [ suffix ]" + +int main (int argc, char const *const *argv) +{ + stralloc sa = STRALLOC_ZERO ; + int nl = 1 ; + PROG = "s6-basename" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "n", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'n' : nl = 0 ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (!argc) strerr_dieusage(100, USAGE) ; + if (!sabasename(&sa, argv[0], str_len(argv[0]))) + strerr_diefu2sys(111, "get basename of ", argv[0]) ; + if (argc >= 2) + { + unsigned int n = str_len(argv[1]) ; + if ((n < sa.len) && !byte_diff(argv[1], n, sa.s + sa.len - n)) + sa.len -= n ; + } + if (nl && !stralloc_catb(&sa, "\n", 1)) + strerr_diefu2sys(111, "get basename of ", argv[0]) ; + if (allwrite(1, sa.s, sa.len) < sa.len) + strerr_diefu1sys(111, "write to stdout") ; + return 0 ; +} diff --git a/src/skaembutils/s6-cat.c b/src/skaembutils/s6-cat.c new file mode 100644 index 0000000..f0166be --- /dev/null +++ b/src/skaembutils/s6-cat.c @@ -0,0 +1,12 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/strerr2.h> +#include <skalibs/djbunix.h> + +int main (void) +{ + PROG = "s6-cat" ; + if (fd_cat(0, 1) < 0) strerr_diefu1sys(111, "fd_cat") ; + return 0 ; +} diff --git a/src/skaembutils/s6-chmod.c b/src/skaembutils/s6-chmod.c new file mode 100644 index 0000000..9cf6f80 --- /dev/null +++ b/src/skaembutils/s6-chmod.c @@ -0,0 +1,34 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <skalibs/uint.h> +#include <skalibs/strerr2.h> + +#define USAGE "s6-chmod mode file" + +int main (int argc, char const *const *argv) +{ + mode_t mode = 0 ; + unsigned int m ; + PROG = "s6-chmod" ; + if (argc < 3) strerr_dieusage(100, USAGE) ; + if (!uint0_oscan(argv[1], &m)) strerr_dieusage(100, USAGE) ; + + if (m & 0001) mode |= S_IXOTH ; + if (m & 0002) mode |= S_IWOTH ; + if (m & 0004) mode |= S_IROTH ; + if (m & 0010) mode |= S_IXGRP ; + if (m & 0020) mode |= S_IWGRP ; + if (m & 0040) mode |= S_IRGRP ; + if (m & 0100) mode |= S_IXUSR ; + if (m & 0200) mode |= S_IWUSR ; + if (m & 0400) mode |= S_IRUSR ; + if (m & 01000) mode |= S_ISVTX ; + if (m & 02000) mode |= S_ISGID ; + if (m & 04000) mode |= S_ISUID ; + + if (chmod(argv[2], mode) == -1) + strerr_diefu2sys(111, "change mode of ", argv[2]) ; + return 0 ; +} diff --git a/src/skaembutils/s6-chown.c b/src/skaembutils/s6-chown.c new file mode 100644 index 0000000..ef6a4a0 --- /dev/null +++ b/src/skaembutils/s6-chown.c @@ -0,0 +1,60 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <unistd.h> +#include <skalibs/sgetopt.h> +#include <skalibs/uint.h> +#include <skalibs/strerr2.h> +#include <skalibs/djbunix.h> + +#define USAGE "s6-chown [ -U ] [ -u uid ] [ -g gid ] file" + +int main (int argc, char const *const *argv, char const *const *envp) +{ + int uid = -1, gid = -1 ; + PROG = "s6-chown" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "Uu:g:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'u': + { + unsigned int u ; + if (!uint0_scan(l.arg, &u)) strerr_dieusage(100, USAGE) ; + uid = u ; + break ; + } + case 'g': + { + unsigned int g ; + if (!uint0_scan(l.arg, &g)) strerr_dieusage(100, USAGE) ; + gid = g ; + break ; + } + case 'U': + { + unsigned int x ; + char const *s = env_get2(envp, "UID") ; + if (!s) strerr_dienotset(100, "UID") ; + if (!uint0_scan(s, &x)) strerr_dieinvalid(100, "UID") ; + uid = x ; + s = env_get2(envp, "GID") ; + if (!s) strerr_dienotset(100, "GID") ; + if (!uint0_scan(s, &x)) strerr_dieinvalid(100, "GID") ; + gid = x ; + break ; + } + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (!argc) strerr_dieusage(100, USAGE) ; + if (chown(*argv, uid, gid) == -1) + strerr_diefu2sys(111, "chown ", argv[0]) ; + return 0 ; +} diff --git a/src/skaembutils/s6-clock.c b/src/skaembutils/s6-clock.c new file mode 100644 index 0000000..822500a --- /dev/null +++ b/src/skaembutils/s6-clock.c @@ -0,0 +1,31 @@ +/* ISC license. */ + +#include <skalibs/allreadwrite.h> +#include <skalibs/strerr2.h> +#include <skalibs/tai.h> + +#define USAGE "s6-clock [ tai64nlabel ]" + +static int getit (void) +{ + char fmt[TIMESTAMP+1] ; + timestamp(fmt) ; + fmt[TIMESTAMP] = '\n' ; + if (allwrite(1, fmt, TIMESTAMP+1) < TIMESTAMP+1) + strerr_diefu1sys(111, "write to stdout") ; + return 0 ; +} + +static int setit (char const *h) +{ + tain_t a ; + if (!timestamp_scan(h, &a)) strerr_dieusage(100, USAGE) ; + if (!tain_setnow(&a)) strerr_diefu1sys(111, "taia_setnow") ; + return 0 ; +} + +int main (int argc, char const *const *argv) +{ + PROG = "s6-clock" ; + return (argc < 2) ? getit() : setit(argv[1]) ; +} diff --git a/src/skaembutils/s6-cut.c b/src/skaembutils/s6-cut.c new file mode 100644 index 0000000..bb729d0 --- /dev/null +++ b/src/skaembutils/s6-cut.c @@ -0,0 +1,212 @@ +/* ISC license. */ + +#include <errno.h> +#include <stdlib.h> +#include <skalibs/sgetopt.h> +#include <skalibs/bytestr.h> +#include <skalibs/uint.h> +#include <skalibs/diuint.h> +#include <skalibs/buffer.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/djbunix.h> +#include <skalibs/skamisc.h> + +#define USAGE "s6-cut [ -b list | -c list | -f list ] [ -d delim ] [ -n ] [ -s ] [ file... ]" + +static int diuint_cmpleft (void const *a, void const *b) +{ + return ((diuint const *)a)->left - ((diuint const *)b)->left ; +} + +static void diuintalloc_normalize (genalloc *list) +{ + unsigned int i = 1, cur = 0 ; + unsigned int len = genalloc_len(diuint, list) ; + register diuint *const s = genalloc_s(diuint, list) ; + qsort(s, len, sizeof(diuint), &diuint_cmpleft) ; + for (; i < len ; i++) + if (!s[cur].right) break ; + else if (s[i].left > s[cur].right) s[++cur] = s[i] ; + else if (s[cur].right < s[i].right) + s[cur].right = s[i].right ; + genalloc_setlen(diuint, list, cur+1) ; +} + +static void scanlist (genalloc *list, char const *s) +{ + register unsigned int i = 0 ; + genalloc_setlen(diuint, list, 0) ; + while (s[i]) + { + char const sep[4] = ", \t" ; + diuint iv ; + if (s[i] == '-') iv.left = 1 ; + else + { + unsigned int j = uint_scan(s+i, &iv.left) ; + if (!j || !iv.left) strerr_dief2x(100, "invalid list argument: ", s) ; + i += j ; + } + if (s[i] != '-') iv.right = iv.left ; + else + { + unsigned int j = uint_scan(s + ++i, &iv.right) ; + if (!j) iv.right = 0 ; + else if (iv.right < iv.left) + strerr_dief2x(100, "invalid list argument: ", s) ; + else i += j ; + } + switch (byte_chr(sep, 4, s[i])) + { + case 0 : + case 1 : + case 2 : i++ ; + case 3 : break ; + case 4 : + strerr_dief2x(100, "invalid list argument: ", s) ; + } + if (!genalloc_append(diuint, list, &iv)) + strerr_diefu1sys(111, "build interval list") ; + } +} + +static int doit (int fd, diuint const *s, unsigned int len, unsigned int flags, char delim) +{ + char buf[BUFFER_INSIZE] ; + buffer b = BUFFER_INIT(&buffer_flush1read, fd, buf, BUFFER_INSIZE) ; + for (;;) + { + int r ; + satmp.len = 0 ; + r = skagetln(&b, &satmp, '\n') ; + if ((r == -1) && (errno != EPIPE)) return 0 ; + if (!r) break ; + if (flags & 2) + { + register unsigned int i = 0 ; + for (; i < len ; i++) + { + register unsigned int j = s[i].right ; + if (s[i].left >= satmp.len) break ; + if (!j || (j > satmp.len)) + { + j = satmp.len ; + r = 0 ; + } + if (buffer_put(buffer_1, satmp.s + s[i].left - 1, j + 1 - s[i].left) == -1) + return 0 ; + } + } + else + { + register unsigned int i = 0, j = 0, count = 1 ; + for (; i < len ; i++) + { + for (; count < s[i].left ; count++) + { + j += byte_chr(satmp.s + j, satmp.len - j, delim) ; + if (j == satmp.len) break ; + j++ ; + } + if (j == satmp.len) + { + if (count == 1) + { + if ((flags & 1) && (buffer_put(buffer_1, satmp.s, satmp.len) < 0)) + return 0 ; + r = 0 ; + } + break ; + } + for (; !s[i].right || (count <= s[i].right) ; count++) + { + register unsigned int k = byte_chr(satmp.s + j, satmp.len - j, delim) ; + if ((count > s[0].left) && (buffer_put(buffer_1, &delim, 1) < 0)) return 0 ; + if (buffer_put(buffer_1, satmp.s + j, k) < 0) return 0 ; + j += k ; + if (j == satmp.len) + { + r = 0 ; + break ; + } + j++ ; + } + if (j == satmp.len) break ; + } + } + if ((r > 0) && (buffer_put(buffer_1, "\n", 1) < 0)) return 0 ; + } + return 1 ; +} + +int main (int argc, char const *const *argv) +{ + genalloc list = GENALLOC_ZERO ; /* array of diuint */ + char delim = '\t' ; + unsigned int what = 0 ; + PROG = "s6-cut" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + int flagnodel = 1 ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "nsb:c:f:d:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'n': break ; /* ignored */ + case 's': flagnodel = 0 ; break ; + case 'd': delim = *l.arg ; break ; + case 'b': + case 'c': + { + if (what) strerr_dieusage(100, USAGE) ; + what = 2 ; + scanlist(&list, l.arg) ; + break ; + } + case 'f': + { + if (what) strerr_dieusage(100, USAGE) ; + what = 4 ; + scanlist(&list, l.arg) ; + break ; + } + default : strerr_dieusage(100, USAGE) ; + } + } + what += flagnodel ; + argc -= l.ind ; argv += l.ind ; + } + if (!genalloc_len(diuint, &list)) strerr_dieusage(100, USAGE) ; + diuintalloc_normalize(&list) ; + + if (!argc) + { + if (!doit(0, genalloc_s(diuint, &list), genalloc_len(diuint, &list), what, delim)) + strerr_diefu1sys(111, "cut stdin") ; + } + else + { + for (; *argv ; argv++) + { + if ((argv[0][0] == '-') && !argv[0][1]) + { + if (!doit(0, genalloc_s(diuint, &list), genalloc_len(diuint, &list), what, delim)) + strerr_diefu1sys(111, "process stdin") ; + } + else + { + int fd = open_readb(*argv) ; + if (fd == -1) + strerr_diefu3sys(111, "open ", *argv, " for reading") ; + if (!doit(fd, genalloc_s(diuint, &list), genalloc_len(diuint, &list), what, delim)) + strerr_diefu2sys(111, "cut ", *argv) ; + fd_close(fd) ; + } + } + } + return 0 ; +} diff --git a/src/skaembutils/s6-dirname.c b/src/skaembutils/s6-dirname.c new file mode 100644 index 0000000..5883180 --- /dev/null +++ b/src/skaembutils/s6-dirname.c @@ -0,0 +1,40 @@ +/* ISC license. */ + +#include <skalibs/sgetopt.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/bytestr.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/djbunix.h> + +#define USAGE "s6-dirname [ -n ] file" + +int main (int argc, char const *const *argv) +{ + stralloc sa = STRALLOC_ZERO ; + int nl = 1 ; + PROG = "s6-dirname" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "n", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'n' : nl = 0 ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + + if (!argc) strerr_dieusage(100, USAGE) ; + if (!sadirname(&sa, argv[0], str_len(argv[0]))) + strerr_diefu2sys(111, "get dirname of ", argv[0]) ; + if (nl && !stralloc_catb(&sa, "\n", 1)) + strerr_diefu2sys(111, "get dirname of ", argv[0]) ; + if (allwrite(1, sa.s, sa.len) < sa.len) + strerr_diefu1sys(111, "write to stdout") ; + return 0 ; +} diff --git a/src/skaembutils/s6-echo.c b/src/skaembutils/s6-echo.c new file mode 100644 index 0000000..6d30576 --- /dev/null +++ b/src/skaembutils/s6-echo.c @@ -0,0 +1,38 @@ +/* ISC license. */ + +#include <skalibs/sgetopt.h> +#include <skalibs/buffer.h> +#include <skalibs/strerr2.h> + +#define USAGE "s6-echo [ -n ] [ -s sep ] args..." + +int main (int argc, char const *const *argv) +{ + char sep = ' ' ; + char donl = 1 ; + PROG = "s6-echo" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "ns:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'n': donl = 0 ; break ; + case 's': sep = *l.arg ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + for ( ; *argv ; argv++) + if ((buffer_puts(buffer_1small, *argv) < 0) + || (argv[1] && (buffer_put(buffer_1small, &sep, 1) == -1))) + goto err ; + if (donl && (buffer_put(buffer_1small, "\n", 1) == -1)) goto err ; + if (!buffer_flush(buffer_1small)) goto err ; + return 0 ; +err: + strerr_diefu1sys(111, "write to stdout") ; +} diff --git a/src/skaembutils/s6-env.c b/src/skaembutils/s6-env.c new file mode 100644 index 0000000..b2e1312 --- /dev/null +++ b/src/skaembutils/s6-env.c @@ -0,0 +1,43 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/sgetopt.h> +#include <skalibs/bytestr.h> +#include <skalibs/strerr2.h> +#include <skalibs/env.h> +#include <skalibs/djbunix.h> +#include <s6-portable-utils/config.h> + +#define USAGE "s6-env [ -i ] [ name=value... ] prog..." + +int main (int argc, char const *const *argv, char const *const *envp) +{ + stralloc modifs = STRALLOC_ZERO ; + char const *arg_zero[2] = { S6_PORTABLE_UTILS_BINPREFIX "s6-printenv", 0 } ; + char const *env_zero[1] = { 0 } ; + PROG = "s6-env" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "i", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'i': envp = env_zero ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + for (; argc ; argc--, argv++) + { + if (!(*argv)[str_chr(*argv, '=')]) break ; + if (!stralloc_cats(&modifs, *argv) || !stralloc_0(&modifs)) + strerr_diefu1sys(111, "stralloc_cats") ; + } + if (!argc) argv = arg_zero ; + pathexec_r(argv, envp, env_len(envp), modifs.s, modifs.len) ; + stralloc_free(&modifs) ; + strerr_dieexec((errno == ENOENT) ? 127 : 126, argv[0]) ; +} diff --git a/src/skaembutils/s6-expr.c b/src/skaembutils/s6-expr.c new file mode 100644 index 0000000..4404d44 --- /dev/null +++ b/src/skaembutils/s6-expr.c @@ -0,0 +1,211 @@ +/* ISC license. */ + +#include <unistd.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/bytestr.h> +#include <skalibs/uint.h> +#include <skalibs/fmtscan.h> +#include <skalibs/strerr2.h> + +#define USAGE "s6-expr arithmetic expression" + +enum opnum +{ + T_DATA, + T_AND, + T_OR, + T_LEFTP, + T_RIGHTP, + T_EQUAL, + T_NEQUAL, + T_GREATER, + T_GREATERE, + T_LESSER, + T_LESSERE, + T_PLUS, + T_MINUS, + T_TIMES, + T_DIV, + T_MOD +} ; + +struct token +{ + char const *string ; + enum opnum op ; + unsigned int type ; +} ; + +struct node +{ + enum opnum op ; + unsigned int type ; + unsigned int arg1 ; + unsigned int arg2 ; + int data ; +} ; + +static unsigned int lex (struct node *tree, char const *const *argv) +{ + static struct token const tokens[16] = + { + { "+", T_PLUS, 3 }, + { "-", T_MINUS, 3 }, + { "*", T_TIMES, 2 }, + { "/", T_DIV, 2 }, + { "%", T_MOD, 2 }, + { "(", T_LEFTP, 7 }, + { ")", T_RIGHTP, 8 }, + { "=", T_EQUAL, 4 }, + { "!=", T_NEQUAL, 4 }, + { "<", T_LESSER, 4 }, + { "<=", T_LESSERE, 4 }, + { ">", T_GREATER, 4 }, + { ">=", T_GREATERE, 4 }, + { "|", T_OR, 6 }, + { "&", T_AND, 5 }, + { 0, 0, 0 } + } ; + register unsigned int pos = 0 ; + + for (; argv[pos] ; pos++) + { + register unsigned int i = 0 ; + for (i = 0 ; tokens[i].string ; i++) + if (!str_diff(argv[pos], tokens[i].string)) + { + tree[pos].op = tokens[i].op ; + tree[pos].type = tokens[i].type ; + break ; + } + if (!tokens[i].string) + { + tree[pos].op = T_DATA ; + tree[pos].type = 0 ; + if (!int_scan(argv[pos], &tree[pos].data)) + strerr_dief1x(2, "invalid expression") ; + } + } + return pos ; +} + +static void reduce (struct node *tree, register unsigned int *stack, register unsigned int *sp, unsigned int type) +{ + if (tree[stack[*sp-1]].type == type) + { + tree[stack[*sp-1]].arg1 = stack[*sp-2] ; + tree[stack[*sp-1]].arg2 = stack[*sp] ; + stack[*sp-2] = stack[*sp-1] ; + *sp -= 2 ; + } + tree[stack[*sp]].type = type + 7 ; +} + +static unsigned int parse (struct node *tree, unsigned int n) +{ + static char const table[9][15] = + { + "xsssssssxzzzzzz", + "xxxxxxxx!zzzzzz", + "mxxxxxxxMszzzzz", + "mxxxxxxxMaszzzz", + "mxxxxxxxMacszzz", + "mxxxxxxxMacAszz", + "mxxxxxxxMacAOsz", + "xsssssssxzzzzzz", + "mxxxxxxxMacAOEs" + } ; + unsigned int stack[n] ; + unsigned int sp = 0, pos = 0 ; + char cont = 1 ; + stack[0] = n + 1 ; + tree[n].type = 8 ; /* add ) for the final reduce */ + tree[n+1].type = 1 ; /* add EOF */ + while (cont) + { + switch (table[tree[pos].type][tree[stack[sp]].type]) + { + case 'x' : _exit(2) ; + case '!' : cont = 0 ; break ; + case 's' : stack[++sp] = pos++ ; break ; + case 'm' : reduce(tree, stack, &sp, 2) ; break ; + case 'a' : reduce(tree, stack, &sp, 3) ; break ; + case 'c' : reduce(tree, stack, &sp, 4) ; break ; + case 'A' : reduce(tree, stack, &sp, 5) ; break ; + case 'O' : reduce(tree, stack, &sp, 6) ; break ; + case 'E' : tree[stack[sp]].type = 14 ; break ; + case 'M' : + { + if (tree[stack[sp-2]].type != 7) _exit(2) ; + stack[sp-2] = stack[sp-1] ; + sp -= 2 ; + reduce(tree, stack, &sp, 2) ; + break ; + } + case 'z' : + default : strerr_dief1x(101, "internal error in parse, please submit a bug-report.") ; /* can't happen */ + } + } + if (sp != 2) strerr_dief1x(2, "invalid expression") ; + return stack[1] ; +} + +static int run (struct node const *tree, unsigned int root) +{ + switch (tree[root].op) + { + case T_DATA : + return tree[root].data ; + case T_OR : + { + int r = run(tree, tree[root].arg1) ; + return r ? r : run(tree, tree[root].arg2) ; + } + case T_AND : + { + int r = run(tree, tree[root].arg1) ; + return r ? run(tree, tree[root].arg2) ? r : 0 : 0 ; + } + case T_EQUAL : + return run(tree, tree[root].arg1) == run(tree, tree[root].arg2) ; + case T_NEQUAL : + return run(tree, tree[root].arg1) != run(tree, tree[root].arg2) ; + case T_GREATER : + return run(tree, tree[root].arg1) > run(tree, tree[root].arg2) ; + case T_GREATERE : + return run(tree, tree[root].arg1) >= run(tree, tree[root].arg2) ; + case T_LESSER : + return run(tree, tree[root].arg1) < run(tree, tree[root].arg2) ; + case T_LESSERE : + return run(tree, tree[root].arg1) <= run(tree, tree[root].arg2) ; + case T_PLUS : + return run(tree, tree[root].arg1) + run(tree, tree[root].arg2) ; + case T_MINUS : + return run(tree, tree[root].arg1) - run(tree, tree[root].arg2) ; + case T_TIMES : + return run(tree, tree[root].arg1) * run(tree, tree[root].arg2) ; + case T_DIV : + return run(tree, tree[root].arg1) / run(tree, tree[root].arg2) ; + case T_MOD : + return run(tree, tree[root].arg1) % run(tree, tree[root].arg2) ; + default: strerr_dief1x(101, "internal error in run, please submit a bug-report") ; + } +} + +int main (int argc, char const *const *argv) +{ + char fmt[UINT_FMT+1] ; + int val ; + unsigned int len ; + PROG = "s6-expr" ; + if (argc <= 1) return 2 ; + { + struct node tree[argc + 1] ; + val = run(tree, parse(tree, lex(tree, argv+1))) ; + } + len = int_fmt(fmt, val) ; + fmt[len++] = '\n' ; + if (allwrite(1, fmt, len) < len) + strerr_diefu1sys(111, "write to stdout") ; + return !val ; +} diff --git a/src/skaembutils/s6-false.c b/src/skaembutils/s6-false.c new file mode 100644 index 0000000..fb13dcd --- /dev/null +++ b/src/skaembutils/s6-false.c @@ -0,0 +1,6 @@ +/* ISC license. */ + +int main () +{ + return 1 ; +} diff --git a/src/skaembutils/s6-format-filter.c b/src/skaembutils/s6-format-filter.c new file mode 100644 index 0000000..78e4437 --- /dev/null +++ b/src/skaembutils/s6-format-filter.c @@ -0,0 +1,61 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/strerr2.h> +#include <skalibs/buffer.h> +#include <skalibs/stralloc.h> +#include <skalibs/skamisc.h> + +#define USAGE "s6-format-filter format [ args... ]" + +int main (int argc, char const *const *argv) +{ + stralloc src = STRALLOC_ZERO ; + stralloc dst = STRALLOC_ZERO ; + char vars[12] = "s0123456789" ; + char const *args[12] = { "" } ; + char const *format ; + PROG = "s6-format-filter" ; + argc-- ; args[1] = *argv++ ; + if (!argc--) strerr_dieusage(100, USAGE) ; + format = *argv++ ; + if (argc > 9) argc = 9 ; + vars[argc+2] = 0 ; + { + register unsigned int i = 0 ; + for (; i < (unsigned int)argc ; i++) args[2+i] = argv[i] ; + } + if (!string_format(&dst, vars, format, args)) + strerr_diefu1sys(111, "compile format") ; + + for (;;) + { + register int r ; + src.len = 0 ; + dst.len = 0 ; + r = skagetln(buffer_0f1, &src, '\n') ; + if (!r) break ; + else if (r < 0) + { + if ((errno != EPIPE) || !stralloc_0(&src)) + strerr_diefu1sys(111, "read from stdin") ; + } + else src.s[src.len-1] = 0 ; + args[0] = src.s ; + if (!string_format(&dst, vars, format, args)) + { + int e = errno ; + buffer_flush(buffer_1) ; + errno = e ; + strerr_diefu1sys(111, "format") ; + } + if (r > 0) + { + if (!stralloc_catb(&dst, "\n", 1)) + strerr_diefu1sys(111, "format") ; + } + if (buffer_put(buffer_1, dst.s, dst.len) < 0) + strerr_diefu1sys(111, "write to stdout") ; + } + return 0 ; +} diff --git a/src/skaembutils/s6-grep.c b/src/skaembutils/s6-grep.c new file mode 100644 index 0000000..cd991e7 --- /dev/null +++ b/src/skaembutils/s6-grep.c @@ -0,0 +1,136 @@ +/* ISC license. */ + +#include <errno.h> +#include <regex.h> +#include <string.h> +#include <skalibs/bytestr.h> +#include <skalibs/sgetopt.h> +#include <skalibs/buffer.h> +#include <skalibs/uint.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/skamisc.h> + +#define USAGE "s6-grep [ -E | -F ] [ -i ] [ -c ] [ -n ] [ -q ] [ -v ] pattern" + +typedef struct flags_s flags_t, *flags_t_ref ; +struct flags_s +{ + unsigned int extended : 1 ; + unsigned int ignorecase: 1 ; + unsigned int fixed : 1 ; + unsigned int count : 1 ; + unsigned int num : 1 ; + unsigned int quiet : 1 ; + unsigned int not : 1 ; +} ; +#define FLAGS_ZERO { .extended = 0, .ignorecase = 0, .fixed = 0, .count = 0, .num = 0, .quiet = 0, .not = 0 } + +int main (int argc, char const *const *argv) +{ + unsigned int count = 0 ; + flags_t flags = FLAGS_ZERO ; + PROG = "s6-grep" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "EFicnqv", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'E': flags.extended = 1 ; break ; + case 'F': flags.fixed = 1 ; break ; + case 'i': flags.ignorecase = 1 ; break ; + case 'c': flags.count = 1 ; break ; + case 'n': flags.num = 1 ; break ; + case 'q': flags.quiet = 1 ; break ; + case 'v': flags.not = 1 ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (!argc) strerr_dieusage(100, USAGE) ; + { + stralloc line = STRALLOC_ZERO ; + regex_t re ; + unsigned int num = 0 ; + unsigned int arglen ; + if (flags.fixed) + { + if (flags.ignorecase) arglen = str_len(argv[0]) ; + } + else + { + register int e = regcomp(&re, argv[0], REG_NOSUB | (flags.extended ? REG_EXTENDED : 0) | (flags.ignorecase ? REG_ICASE : 0)) ; + if (e) + { + char buf[256] ; + regerror(e, &re, buf, 256) ; + strerr_diefu2x(111, "compile regular expression: ", buf) ; + } + } + + for (;;) + { + register int r ; + line.len = 0 ; + r = skagetln(buffer_0f1, &line, '\n') ; + if (!r) break ; + if (r < 0) + { + if ((errno != EPIPE) || !stralloc_catb(&line, "\n", 1)) + strerr_diefu1sys(111, "read from stdin") ; + } + num++ ; line.s[line.len-1] = 0 ; + if (flags.fixed) + { + if (flags.ignorecase) + r = case_str(line.s, argv[0]) >= arglen ; + else + r = !strstr(line.s, argv[0]) ; + } + else + { + r = regexec(&re, line.s, 0, 0, 0) ; + if (r && r != REG_NOMATCH) + { + char buf[256] ; + regerror(r, &re, buf, 256) ; + strerr_diefu2x(111, "match regular expression: ", buf) ; + } + } + line.s[line.len-1] = '\n' ; + if (!r ^ flags.not) + { + count++ ; + if (!flags.quiet && !flags.count) + { + if (flags.num) + { + char fmt[UINT_FMT] ; + register unsigned int n = uint_fmt(fmt, num) ; + fmt[n++] = ':' ; + if (buffer_put(buffer_1, fmt, n) < (int)n) + strerr_diefu1sys(111, "write to stdout") ; + } + if (buffer_put(buffer_1, line.s, line.len) < (int)line.len) + strerr_diefu1sys(111, "write to stdout") ; + } + } + } + if (flags.quiet) return !count ; + stralloc_free(&line) ; + if (!flags.fixed) regfree(&re) ; + } + if (flags.count) + { + char fmt[UINT_FMT] ; + register unsigned int n = uint_fmt(fmt, count) ; + fmt[n++] = '\n' ; + if (buffer_put(buffer_1, fmt, n) < (int)n) + strerr_diefu1sys(111, "write to stdout") ; + } + return !count ; +} diff --git a/src/skaembutils/s6-head.c b/src/skaembutils/s6-head.c new file mode 100644 index 0000000..1ef24c0 --- /dev/null +++ b/src/skaembutils/s6-head.c @@ -0,0 +1,159 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/sgetopt.h> +#include <skalibs/bytestr.h> +#include <skalibs/uint.h> +#include <skalibs/buffer.h> +#include <skalibs/siovec.h> +#include <skalibs/strerr2.h> +#include <skalibs/djbunix.h> + +#define USAGE "s6-head [ -S ] [ -1..9 | -n lines | -c chars ] [ file... ]" +#define dieusage() strerr_dieusage(100, USAGE) + +typedef int headfunc_t (int, unsigned int) ; +typedef headfunc_t *headfunc_t_ref ; + +static int dolines (int fd, unsigned int lines) +{ + char buf[BUFFER_INSIZE] ; + buffer in = BUFFER_INIT(&buffer_read, fd, buf, BUFFER_INSIZE) ; + buffer out = BUFFER_INIT(&buffer_write, 1, buf, BUFFER_INSIZE) ; + siovec_t v[2] ; + while (lines) + { + unsigned int w = 0 ; + register int r = buffer_fill(&in) ; + if (r <= 0) return !r ; + out.c.n = in.c.n ; out.c.p = in.c.p ; + buffer_rpeek(&in, v) ; + for (;;) + { + unsigned int n = siovec_len(v, 2) ; + register unsigned int i ; + if (!n) break ; + i = siovec_bytechr(v, 2, '\n') ; + if (i < n) + { + w += i+1 ; + siovec_seek(v, 2, i+1) ; + if (!--lines) + { + out.c.n = (out.c.p + w) % out.c.a ; + break ; + } + } + else siovec_seek(v, 2, i) ; + } + if (!buffer_flush(&out)) return 0 ; + in.c.n = out.c.n ; in.c.p = out.c.p ; + } + return 1 ; +} + +static int safedolines (int fd, unsigned int lines) +{ + char tmp[lines] ; + while (lines) + { + unsigned int r = allread(fd, tmp, lines) ; + if ((r < lines) && (errno != EPIPE)) return 0 ; + lines -= byte_count(tmp, r, '\n') ; + if (buffer_put(buffer_1, tmp, r) < (int)r) return 0 ; + } + if (!buffer_flush(buffer_1)) return 0 ; + return 1 ; +} + +static int safedochars (int fd, unsigned int chars) +{ + return (fd_catn(fd, 1, chars) >= chars) ; +} + +int main (int argc, char const *const *argv) +{ + headfunc_t_ref f ; + unsigned int lines = 10 ; + int islines = 1, safe = 0 ; + PROG = "s6-head" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + int done = 0 ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "S123456789n:c:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'S' : safe = 1 ; break ; + case '1' : + case '2' : + case '3' : + case '4' : + case '5' : + case '6' : + case '7' : + case '8' : + case '9' : + { + if (done) dieusage() ; + islines = 1 ; + lines = opt - '0' ; + done = 1 ; + break ; + } + case 'n' : + { + if (done || !uint0_scan(l.arg, &lines)) + strerr_dieusage(100, USAGE) ; + islines = 1 ; + done = 1 ; + break ; + } + case 'c' : + { + if (done || !uint0_scan(l.arg, &lines)) + strerr_dieusage(100, USAGE) ; + islines = 0 ; + done = 1 ; + break ; + } + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (argc) safe = 0 ; + f = islines ? safe ? &safedolines : &dolines : &safedochars ; + if (!argc) + { + if (!(*f)(0, lines)) + strerr_diefu1sys(111, "head stdin") ; + } + else + { + unsigned int i = 0 ; + for (; argv[i] ; i++) + { + int fd ; + if (argc >= 2) + { + if (i) buffer_putnoflush(buffer_1, "\n", 1) ; + buffer_putnoflush(buffer_1, "==> ", 4) ; + if ((buffer_puts(buffer_1, argv[i]) <= 0) + || (buffer_putflush(buffer_1, " <==\n", 5) < 0)) + strerr_diefu1sys(111, "write to stdout") ; + } + if ((argv[i][0] == '-') && !argv[i][1]) fd = 0 ; + else fd = open_readb(argv[i]) ; + if (fd == -1) + strerr_diefu3sys(111, "open ", argv[i], " for reading") ; + if (!(*f)(fd, lines)) + strerr_diefu2sys(111, "head ", argv[i]) ; + fd_close(fd) ; + } + } + return 0 ; +} diff --git a/src/skaembutils/s6-linkname.c b/src/skaembutils/s6-linkname.c new file mode 100644 index 0000000..a9425a1 --- /dev/null +++ b/src/skaembutils/s6-linkname.c @@ -0,0 +1,45 @@ +/* ISC license. */ + +#include <skalibs/bytestr.h> +#include <skalibs/buffer.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/djbunix.h> + +#define USAGE "s6-linkname [ -n ] [ -f ] link" +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv) +{ + stralloc sa = STRALLOC_ZERO ; + int path = 0, nl = 1 ; + PROG = "s6-linkname" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "nf", &l) ; + if (opt == -1) break ; + switch(opt) + { + case 'n' : nl = 0 ; break ; + case 'f' : path = 1 ; break ; + default : dieusage() ; + } + } + argv += l.ind ; argc -= l.ind ; + } + if (!argc) dieusage() ; + + if ((path ? sarealpath(&sa, *argv) : sareadlink(&sa, *argv)) < 0) + strerr_diefu2sys(111, "resolve ", *argv) ; + + if ((buffer_put(buffer_1small, sa.s, sa.len) < 0) + || (nl && (buffer_put(buffer_1small, "\n", 1)) < 0) + || (!buffer_flush(buffer_1small))) + strerr_diefu1sys(111, "write to stdout") ; + + /* stralloc_free(&sa) ; */ + return 0 ; +} diff --git a/src/skaembutils/s6-ln.c b/src/skaembutils/s6-ln.c new file mode 100644 index 0000000..7f6f7b6 --- /dev/null +++ b/src/skaembutils/s6-ln.c @@ -0,0 +1,145 @@ +/* ISC license. */ + +#include <skalibs/sysdeps.h> + +#ifdef SKALIBS_HASLINKAT +#include <skalibs/nonposix.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <skalibs/sgetopt.h> +#include <skalibs/bytestr.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/djbunix.h> +#include <skalibs/random.h> +#include <skalibs/skamisc.h> + +#define USAGE "s6-ln [ -s ] [ -f ] [ -L ] [ -P ] src... dest" + +typedef int linkfunc_t (char const *, char const *) ; +typedef linkfunc_t *linkfunc_t_ref ; + +typedef void ln_t (char const *, char const *, linkfunc_t_ref) ; +typedef ln_t *ln_t_ref ; + +#ifdef SKALIBS_HASLINKAT + +static int linknoderef (char const *old, char const *new) +{ + return linkat(AT_FDCWD, old, AT_FDCWD, new, 0) ; +} + +static int linkderef (char const *old, char const *new) +{ + return linkat(AT_FDCWD, old, AT_FDCWD, new, AT_SYMLINK_FOLLOW) ; +} + +#else /* can't implement SUSv4, default to link */ + +# define linknoderef link +# define linkderef link + +#endif + +static void force (char const *old, char const *new, linkfunc_t_ref doit) +{ + if ((*doit)(old, new) == -1) + { + unsigned int base = satmp.len ; + if (errno != EEXIST) + strerr_diefu5sys(111, "make a link", " from ", new, " to ", old) ; + if (!stralloc_catb(&satmp, new, str_len(new)) + || (random_sauniquename(&satmp, 8) == -1) + || !stralloc_0(&satmp)) + strerr_diefu2sys(111, "make a unique name for ", old) ; + if ((*doit)(old, satmp.s + base) == -1) + strerr_diefu3sys(111, "make a link", " to ", old) ; + if (rename(satmp.s + base, new) == -1) + { + unlink(satmp.s + base) ; + strerr_diefu2sys(111, "atomically replace ", new) ; + } + satmp.len = base ; + } +} + +static void noforce (char const *old, char const *new, linkfunc_t_ref doit) +{ + if ((*doit)(old, new) == -1) + strerr_diefu5sys(111, "make a link", " from ", new, " to ", old) ; +} + +int main (int argc, char const *const *argv) +{ + linkfunc_t_ref mylink = &link ; /* default to system behaviour */ + ln_t_ref f = &noforce ; + PROG = "s6-ln" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "sfLP", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 's': mylink = &symlink ; break ; + case 'f': f = &force ; break ; + case 'L': if (mylink != &symlink) mylink = &linkderef ; break ; + case 'P': if (mylink != &symlink) mylink = &linknoderef ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (argc < 2) strerr_dieusage(100, USAGE) ; + if (argc > 2) + { + stralloc sa = STRALLOC_ZERO ; + unsigned int i = 0 ; + unsigned int base ; + if (!stralloc_cats(&sa, argv[argc-1]) || !stralloc_catb(&sa, "/", 1)) + strerr_diefu1sys(111, "stralloc_cats") ; + base = sa.len ; + for (; i < (unsigned int)(argc-1) ; i++) + { + sa.len = base ; + if (!sabasename(&sa, argv[i], str_len(argv[i]))) + strerr_diefu1sys(111, "sabasename") ; + if (!stralloc_0(&sa)) strerr_diefu1sys(111, "stralloc_0") ; + (*f)(argv[i], sa.s, mylink) ; + } + return 0 ; + } + + { + struct stat st ; + if (stat(argv[1], &st) < 0) + { + if (errno != ENOENT) strerr_diefu2sys(111, "stat ", argv[1]) ; + (*f)(argv[0], argv[1], mylink) ; + return 0 ; + } + if (!S_ISDIR(st.st_mode)) + { + (*f)(argv[0], argv[1], mylink) ; + return 0 ; + } + } + + { + stralloc sa = STRALLOC_ZERO ; + if (!stralloc_cats(&sa, argv[1]) + || !stralloc_catb(&sa, "/", 1) + || !sabasename(&sa, argv[0], str_len(argv[0])) + || !stralloc_0(&sa)) + strerr_diefu1sys(111, "stralloc_catb") ; + (*f)(argv[0], sa.s, mylink) ; + } + return 0 ; +} diff --git a/src/skaembutils/s6-ls.c b/src/skaembutils/s6-ls.c new file mode 100644 index 0000000..25045a7 --- /dev/null +++ b/src/skaembutils/s6-ls.c @@ -0,0 +1,56 @@ +/* ISC license. */ + +#include <skalibs/sgetopt.h> +#include <skalibs/bytestr.h> +#include <skalibs/direntry.h> +#include <skalibs/buffer.h> +#include <skalibs/strerr2.h> + +#define USAGE "s6-ls [ -0 ] [ -a | -A ] [ -x exclude ] dir" + +int main (int argc, char const *const *argv) +{ + unsigned int all = 0 ; + char const *exclude = 0 ; + char delim = '\n' ; + PROG = "s6-ls" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "0aAx:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case '0': delim = '\0' ; break ; + case 'a': all = 1 ; break ; + case 'A': all = 2 ; break ; + case 'x': exclude = l.arg ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (!argc) strerr_dieusage(100, USAGE) ; + { + direntry *d ; + DIR *dir = opendir(*argv) ; + if (!dir) + strerr_diefu2sys(111, "open directory ", *argv) ; + while ((d = readdir(dir))) + { + if ((d->d_name[0] == '.') && (all < 2)) + { + if (!all || !d->d_name[1] || ((d->d_name[1] == '.') && !d->d_name[2])) continue ; + } + if (exclude && !str_diff(exclude, d->d_name)) continue ; + if ((buffer_puts(buffer_1, d->d_name) < 0) + || (buffer_put(buffer_1, &delim, 1) < 0)) + strerr_diefu1sys(111, "write to stdout") ; + } + dir_close(dir) ; + } + if (!buffer_flush(buffer_1)) + strerr_diefu1sys(111, "write to stdout") ; + return 0 ; +} diff --git a/src/skaembutils/s6-maximumtime.c b/src/skaembutils/s6-maximumtime.c new file mode 100644 index 0000000..571914f --- /dev/null +++ b/src/skaembutils/s6-maximumtime.c @@ -0,0 +1,99 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include <errno.h> +#include <unistd.h> +#include <skalibs/sgetopt.h> +#include <skalibs/uint.h> +#include <skalibs/error.h> +#include <skalibs/sig.h> +#include <skalibs/tai.h> +#include <skalibs/iopause.h> +#include <skalibs/selfpipe.h> +#include <skalibs/strerr2.h> +#include <skalibs/djbunix.h> + +#define USAGE "s6-maximumtime [ -0 | -a | -b | -i | -k | -q | -t | -x | -1 | -2 ] milliseconds prog..." + +int main (int argc, char const *const *argv, char const *const *envp) +{ + unsigned int timeout ; + tain_t stamp, deadline ; + iopause_fd x[1] = { { .fd = -1, .events = IOPAUSE_READ, .revents = 0 } } ; + pid_t pid = 0 ; + int tosend = SIGTERM ; + PROG = "s6-maximumtime" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "0abikqtx12", &l) ; + if (opt == -1) break ; + switch (opt) + { + case '0': tosend = 0 ; break ; + case 'a': tosend = SIGALRM ; break ; + case 'b': tosend = SIGABRT ; break ; + case 'i': tosend = SIGINT ; break ; + case 'k': tosend = SIGKILL ; break ; + case 'q': tosend = SIGQUIT ; break ; + case 't': tosend = SIGTERM ; break ; + case 'x': tosend = SIGXCPU ; break ; + case '1': tosend = SIGUSR1 ; break ; + case '2': tosend = SIGUSR2 ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + + if ((argc < 2) || !uint0_scan(argv[0], &timeout)) strerr_dieusage(100, USAGE) ; + if (!timeout) timeout = 1 ; + if (!tain_from_millisecs(&deadline, timeout)) + strerr_diefu1sys(111, "taia_from_millisecs") ; + + x[0].fd = selfpipe_init() ; + if (x[0].fd < 0) strerr_diefu1sys(111, "selfpipe_init") ; + + if (selfpipe_trap(SIGCHLD) < 0) strerr_diefu1sys(111, "selfpipe_trap") ; + + pid = child_spawn0(argv[1], argv+1, envp) ; + if (!pid) strerr_diefu2sys(111, "spawn ", argv[1]) ; + tain_now(&stamp) ; + tain_add(&deadline, &deadline, &stamp) ; + + for (;;) + { + int r = iopause_stamp(x, 1, &deadline, &stamp) ; + if (r < 0) strerr_diefu1sys(111, "iopause") ; + if (!r) break ; + if (x[0].revents & IOPAUSE_READ) + { + int cont = 1 ; + while (cont) + { + switch (selfpipe_read()) + { + case -1 : strerr_diefu1sys(111, "selfpipe_read") ; + case 0 : cont = 0 ; break ; + case SIGCHLD : + { + int wstat ; + if (wait_pid_nohang(pid, &wstat) == pid) + { + if (WIFSIGNALED(wstat)) + strerr_diew1x(111, "child process crashed") ; + else return WEXITSTATUS(wstat) ; + } + } + default : strerr_diefu1x(101, "internal error, please submit a bug-report.") ; + } + } + } + } + kill(pid, tosend) ; + errno = ETIMEDOUT ; + strerr_diewu1sys(99, "wait for child process") ; +} diff --git a/src/skaembutils/s6-mkdir.c b/src/skaembutils/s6-mkdir.c new file mode 100644 index 0000000..92bae67 --- /dev/null +++ b/src/skaembutils/s6-mkdir.c @@ -0,0 +1,79 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <skalibs/sgetopt.h> +#include <skalibs/bytestr.h> +#include <skalibs/uint.h> +#include <skalibs/buffer.h> +#include <skalibs/strerr2.h> + +#define USAGE "s6-mkdir [ -p ] [ -v ] [ -m mode ] dir" + +static int doit (char const *s, unsigned int mode, int verbose, int ee) +{ + if (mkdir(s, mode) == -1) + { + if (ee || (errno != EEXIST)) + { + strerr_warnwu2sys("mkdir ", s) ; + return 111 ; + } + } + else if (verbose) + { + buffer_puts(buffer_2, PROG) ; + buffer_puts(buffer_2, ": created directory ") ; + buffer_puts(buffer_2, s) ; + buffer_putflush(buffer_2, "\n", 1) ; + } + return 0 ; +} + +static int doparents (char const *s, unsigned int mode, int verbose) +{ + unsigned int n = str_len(s), i = 0 ; + char tmp[n+1] ; + for (; i < n ; i++) + { + if ((s[i] == '/') && i) + { + register int e ; + tmp[i] = 0 ; + e = doit(tmp, mode, verbose, 0) ; + if (e) return e ; + } + tmp[i] = s[i] ; + } + return doit(s, mode, verbose, 0) ; +} + +int main (int argc, char const *const *argv) +{ + int parents = 0, verbose = 0 ; + unsigned int mode = 0777 ; + int e = 0 ; + PROG = "s6-mkdir" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "pvm:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'p': parents = 1 ; break ; + case 'v': verbose = 1 ; break ; + case 'm': if (uint_oscan(l.arg, &mode)) break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + for ( ; *argv ; argv++) + e |= parents ? doparents(*argv, mode, verbose) : + doit(*argv, mode, verbose, 1) ; + return e ; +} diff --git a/src/skaembutils/s6-mkfifo.c b/src/skaembutils/s6-mkfifo.c new file mode 100644 index 0000000..9278eb9 --- /dev/null +++ b/src/skaembutils/s6-mkfifo.c @@ -0,0 +1,36 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <skalibs/sgetopt.h> +#include <skalibs/uint.h> +#include <skalibs/strerr2.h> +#include <skalibs/djbunix.h> + +#define USAGE "s6-mkfifo [ -m mode ] fifo..." + +int main (int argc, char const *const *argv) +{ + unsigned int mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH ; + PROG = "s6-mkfifo" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "m:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'm': if (uint0_oscan(l.arg, &mode)) break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (!argc) strerr_dieusage(100, USAGE) ; + umask(S_IXUSR|S_IXGRP|S_IXOTH) ; + for (; *argv ; argv++) + if (mkfifo(*argv, mode) < 0) + strerr_diefu2sys(111, "mkfifo ", *argv) ; + return 0 ; +} diff --git a/src/skaembutils/s6-nice.c b/src/skaembutils/s6-nice.c new file mode 100644 index 0000000..ec9f477 --- /dev/null +++ b/src/skaembutils/s6-nice.c @@ -0,0 +1,46 @@ +/* ISC license. */ + +#include <unistd.h> +#include <errno.h> +#include <skalibs/sgetopt.h> +#include <skalibs/uint.h> +#include <skalibs/fmtscan.h> +#include <skalibs/strerr2.h> +#include <skalibs/djbunix.h> + +#define USAGE "s6-nice [ -I | -i ] [ -n value ] prog..." + +int main (int argc, char const *const *argv, char const *const *envp) +{ + int incr = 10 ; + int strict = 0 ; + PROG = "s6-nice" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "Iin:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'I' : strict = 0 ; break ; + case 'i' : strict = 1 ; break ; + case 'n': if (!int_scan(l.arg, &incr)) strerr_dieusage(100, USAGE) ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (!argc) strerr_dieusage(100, USAGE) ; + + errno = 0 ; + if ((nice(incr) < 0) && errno) + { + char fmt[1+UINT_FMT] ; + fmt[int_fmt(fmt, incr)] = 0 ; + if (strict) strerr_diefu2sys(111, "nice to ", fmt) ; + else strerr_warnwu2sys("nice to ", fmt) ; + } + pathexec_run(argv[0], argv, envp) ; + strerr_dieexec((errno == ENOENT) ? 127 : 126, argv[0]) ; +} diff --git a/src/skaembutils/s6-nuke.c b/src/skaembutils/s6-nuke.c new file mode 100644 index 0000000..cda1279 --- /dev/null +++ b/src/skaembutils/s6-nuke.c @@ -0,0 +1,50 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <signal.h> +#include <errno.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/sig.h> + +#define USAGE "s6-nuke [ -h | -t | -k ]" + +int main (int argc, char const *const *argv) +{ + int doterm = 0, dohangup = 0, dokill = 0 ; + PROG = "s6-nuke" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "htk", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'h': dohangup = 1 ; break ; + case 't': doterm = 1 ; break ; + case 'k': dokill = 1 ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + + if (dohangup) + { + sig_ignore(SIGHUP) ; + kill(-1, SIGHUP) ; + } + + if (doterm) + { + sig_ignore(SIGTERM) ; + kill(-1, SIGTERM) ; + kill(-1, SIGCONT) ; + } + + if (dokill) kill(-1, SIGKILL) ; + + if (errno) strerr_diefu1sys(111, "kill") ; + return 0 ; +} diff --git a/src/skaembutils/s6-pause.c b/src/skaembutils/s6-pause.c new file mode 100644 index 0000000..8eafdce --- /dev/null +++ b/src/skaembutils/s6-pause.c @@ -0,0 +1,9 @@ +/* ISC license. */ + +#include <unistd.h> + +int main () +{ + pause() ; + return 0 ; +} diff --git a/src/skaembutils/s6-printenv.c b/src/skaembutils/s6-printenv.c new file mode 100644 index 0000000..3f4571b --- /dev/null +++ b/src/skaembutils/s6-printenv.c @@ -0,0 +1,51 @@ +/* ISC license. */ + +#include <skalibs/bytestr.h> +#include <skalibs/sgetopt.h> +#include <skalibs/buffer.h> +#include <skalibs/strerr2.h> +#include <skalibs/netstring.h> + +#define USAGE "s6-printenv [ -n ] [ -0 | -d delimchar ]" + +int main (int argc, char const *const *argv, char const *const *envp) +{ + char delim = '\n' ; + int zero = 0, nl = 1 ; + PROG = "s6-printenv" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "nd:0", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'n' : nl = 0 ; break ; + case 'd' : delim = *l.arg ; break ; + case '0' : zero = 1 ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (zero) delim = 0 ; + for (; *envp ; envp++) + { + if (delim || zero) + { + if ((buffer_puts(buffer_1, *envp) < 0) + || ((nl || envp[1]) && (buffer_put(buffer_1, &delim, 1) < 0))) + strerr_diefu1sys(111, "write to stdout") ; + } + else + { + unsigned int written = 0 ; + if (!netstring_put(buffer_1, *envp, str_len(*envp), &written)) + strerr_diefu1sys(111, "write a netstring to stdout") ; + } + } + if (!buffer_flush(buffer_1)) + strerr_diefu1sys(111, "write to stdout") ; + return 0 ; +} diff --git a/src/skaembutils/s6-quote-filter.c b/src/skaembutils/s6-quote-filter.c new file mode 100644 index 0000000..d9489a1 --- /dev/null +++ b/src/skaembutils/s6-quote-filter.c @@ -0,0 +1,72 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/buffer.h> +#include <skalibs/stralloc.h> +#include <skalibs/skamisc.h> + +#define USAGE "s6-quote-filter [ -u ] [ -d delim ]" + +int main (int argc, char const *const *argv) +{ + stralloc src = STRALLOC_ZERO ; + stralloc dst = STRALLOC_ZERO ; + char const *delim = "\"" ; + unsigned int delimlen ; + unsigned int startquote = 1 ; + PROG = "s6-quote-filter" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "ud:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'u' : startquote = 0 ; break ; + case 'd': delim = l.arg ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + delimlen = str_len(delim) ; + if (startquote) + { + if(!delimlen) strerr_dief1x(100, "no character to quote with!") ; + if (!stralloc_catb(&dst, delim, 1)) + strerr_diefu1sys(111, "stralloc_catb") ; + } + for (;;) + { + int r ; + src.len = 0 ; + r = skagetln(buffer_0f1, &src, '\n') ; + if (!r) break ; + if ((r < 0) && (errno != EPIPE)) + strerr_diefu1sys(111, "read from stdin") ; + dst.len = startquote ; + if (!string_quote_nodelim_mustquote(&dst, src.s, src.len - (r > 0), delim, delimlen)) + { + int e = errno ; + buffer_flush(buffer_1) ; + errno = e ; + strerr_diefu1sys(111, "quote") ; + } + if (startquote) + { + if (!stralloc_catb(&dst, delim, 1)) + strerr_diefu1sys(111, "stralloc_catb") ; + } + if (r > 0) + { + if (!stralloc_catb(&dst, "\n", 1)) + strerr_diefu1sys(111, "stralloc_catb") ; + } + if (buffer_put(buffer_1, dst.s, dst.len) < 0) + strerr_diefu1sys(111, "write to stdout") ; + } + return 0 ; +} diff --git a/src/skaembutils/s6-quote.c b/src/skaembutils/s6-quote.c new file mode 100644 index 0000000..b370e39 --- /dev/null +++ b/src/skaembutils/s6-quote.c @@ -0,0 +1,58 @@ +/* ISC license. */ + +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/stralloc.h> +#include <skalibs/skamisc.h> + +#define USAGE "s6-quote [ -n ] [ -u ] [ -d delim ] string" + +int main (int argc, char const *const *argv) +{ + stralloc sa = STRALLOC_ZERO ; + char const *delim = "\"" ; + unsigned int delimlen ; + int nl = 1 ; + int startquote = 1 ; + PROG = "s6-quote" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "nud:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'n' : nl = 0 ; break ; + case 'u' : startquote = 0 ; break ; + case 'd': delim = l.arg ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (!argc) strerr_dieusage(100, USAGE) ; + delimlen = str_len(delim) ; + if (startquote) + { + if (!delimlen) strerr_dief1x(100, "no character to quote with!") ; + if (!stralloc_catb(&sa, delim, 1)) + strerr_diefu1sys(111, "stralloc_catb") ; + } + if (!string_quote_nodelim_mustquote(&sa, *argv, str_len(*argv), delim, delimlen)) + strerr_diefu1sys(111, "quote") ; + if (startquote) + { + if (!stralloc_catb(&sa, delim, 1)) + strerr_diefu1sys(111, "stralloc_catb") ; + } + if (nl) + { + if (!stralloc_catb(&sa, "\n", 1)) + strerr_diefu1sys(111, "stralloc_catb") ; + } + if (allwrite(1, sa.s, sa.len) < sa.len) + strerr_diefu1sys(111, "write to stdout") ; + return 0 ; +} diff --git a/src/skaembutils/s6-rename.c b/src/skaembutils/s6-rename.c new file mode 100644 index 0000000..55c92fa --- /dev/null +++ b/src/skaembutils/s6-rename.c @@ -0,0 +1,16 @@ +/* ISC license. */ + +#include <unistd.h> +#include <stdio.h> +#include <skalibs/strerr2.h> + +#define USAGE "s6-rename old new" + +int main (int argc, char const *const *argv) +{ + PROG = "s6-rename" ; + if (argc < 3) strerr_dieusage(100, USAGE) ; + if (rename(argv[1], argv[2]) == -1) + strerr_diefu4sys(111, "rename ", argv[1], " to ", argv[2]) ; + return 0 ; +} diff --git a/src/skaembutils/s6-rmrf.c b/src/skaembutils/s6-rmrf.c new file mode 100644 index 0000000..4d57530 --- /dev/null +++ b/src/skaembutils/s6-rmrf.c @@ -0,0 +1,17 @@ +/* ISC license. */ + +#include <skalibs/strerr2.h> +#include <skalibs/djbunix.h> + +#define USAGE "s6-rmrf file ..." + +int main (int argc, char const *const *argv) +{ + char const *const *p = argv + 1 ; + PROG = "s6-rmrf" ; + if (argc < 2) strerr_dieusage(100, USAGE) ; + for (; *p ; p++) + if (rm_rf(*p) == -1) + strerr_diefu2sys(111, "remove ", argv[1]) ; + return 0 ; +} diff --git a/src/skaembutils/s6-sleep.c b/src/skaembutils/s6-sleep.c new file mode 100644 index 0000000..ea25514 --- /dev/null +++ b/src/skaembutils/s6-sleep.c @@ -0,0 +1,46 @@ +/* ISC license. */ + +#include <unistd.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/uint.h> +#include <skalibs/tai.h> +#include <skalibs/djbunix.h> +#include <skalibs/iopause.h> + +#define USAGE "s6-sleep [ -m ] duration prog..." + +int main (int argc, char const *const *argv, char const *const *envp) +{ + unsigned int n ; + int milli = 0 ; + PROG = "s6-sleep" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "m", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'm': milli = 1 ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (!argc) strerr_dieusage(100, USAGE) ; + if (!uint0_scan(argv[0], &n)) strerr_dieusage(100, USAGE) ; + + { + tain_t deadline ; + if (milli) tain_from_millisecs(&deadline, n) ; + else tain_uint(&deadline, n) ; + tain_now_g() ; + tain_add_g(&deadline, &deadline) ; + deepsleepuntil_g(&deadline) ; + } + + pathexec0_run(argv+1, envp) ; + strerr_dieexec(111, argv[1]) ; +} diff --git a/src/skaembutils/s6-sort.c b/src/skaembutils/s6-sort.c new file mode 100644 index 0000000..5b259b8 --- /dev/null +++ b/src/skaembutils/s6-sort.c @@ -0,0 +1,123 @@ +/* ISC license. */ + +#include <stdlib.h> +#include <errno.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/sgetopt.h> +#include <skalibs/bytestr.h> +#include <skalibs/buffer.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/djbunix.h> +#include <skalibs/skamisc.h> + +#define USAGE "s6-sort [ -bcfru0 ]" + +typedef int strncmp_t (char const *, unsigned int, char const *) ; +typedef strncmp_t *strncmp_t_ref ; +typedef int qsortcmp_t (void const *, void const *) ; +typedef qsortcmp_t *qsortcmp_t_ref ; + +static int flagnoblanks = 0, flagreverse = 0, flaguniq = 0 ; + +static int str_diffb_f (register char const *s1, register unsigned int n, register char const *s2) +{ + return str_diffb(s1, n, s2) ; +} + +static strncmp_t_ref comp = &str_diffb_f ; + +static int compit (register char const *s1, register unsigned int n1, register char const *s2, register unsigned int n2) +{ + register int r ; + if (flagnoblanks) + { + while ((*s1 == ' ') || (*s1 == '\t')) (s1++, n1--) ; + while ((*s2 == ' ') || (*s2 == '\t')) (s2++, n2--) ; + } + r = (*comp)(s1, n1 < n2 ? n1 : n2, s2) ; + if (!r) r = n1 - n2 ; + return flagreverse ? -r : r ; +} + +static int sacmp (stralloc const *a, stralloc const *b) +{ + return compit(a->s, a->len - 1, b->s, b->len - 1) ; +} + +static int slurplines (genalloc *lines, char sep) +{ + unsigned int i = 0 ; + for (;; i++) + { + stralloc sa = STRALLOC_ZERO ; + int r = skagetln(buffer_0, &sa, sep) ; + if (!r) break ; + if ((r < 0) && ((errno != EPIPE) || !stralloc_catb(&sa, &sep, 1))) + return -1 ; + stralloc_shrink(&sa) ; + if (!genalloc_append(stralloc, lines, &sa)) return -1 ; + } + return (int)i ; +} + +static void uniq (genalloc *lines) +{ + unsigned int len = genalloc_len(stralloc, lines) ; + register stralloc *s = genalloc_s(stralloc, lines) ; + register unsigned int i = 1 ; + for (; i < len ; i++) + if (!sacmp(s+i-1, s+i)) stralloc_free(s+i-1) ; +} + +static int outputlines (stralloc const *s, unsigned int len) +{ + register unsigned int i = 0 ; + for (; i < len ; i++) + if (buffer_put(buffer_1, s[i].s, s[i].len) < 0) return 0 ; + return buffer_flush(buffer_1) ; +} + +static int check (stralloc const *s, unsigned int len) +{ + register unsigned int i = 1 ; + for (; i < len ; i++) + if (sacmp(s+i-1, s+i) >= !flaguniq) return 0 ; + return 1 ; +} + +int main (int argc, char const *const *argv) +{ + genalloc lines = GENALLOC_ZERO ; /* array of stralloc */ + char sep = '\n' ; + int flagcheck = 0 ; + PROG = "s6-sort" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "bcfru0", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'b' : flagnoblanks = 1 ; break ; + case 'c' : flagcheck = 1 ; break ; + case 'f' : comp = &case_diffb ; break ; + case 'r' : flagreverse = 1 ; break ; + case 'u' : flaguniq = 1 ; break ; + case '0' : sep = '\0' ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + + if (slurplines(&lines, sep) < 0) strerr_diefu1sys(111, "read from stdin") ; + if (flagcheck) return !check(genalloc_s(stralloc, &lines), genalloc_len(stralloc, &lines)) ; + qsort(genalloc_s(stralloc, &lines), genalloc_len(stralloc, &lines), sizeof(stralloc), (qsortcmp_t_ref)&sacmp) ; + if (flaguniq) uniq(&lines) ; + if (!outputlines(genalloc_s(stralloc, &lines), genalloc_len(stralloc, &lines))) + strerr_diefu1sys(111, "write to stdout") ; + return 0 ; +} diff --git a/src/skaembutils/s6-sync.c b/src/skaembutils/s6-sync.c new file mode 100644 index 0000000..a8829cd --- /dev/null +++ b/src/skaembutils/s6-sync.c @@ -0,0 +1,9 @@ +/* ISC license. */ + +#include <unistd.h> + +int main (void) +{ + sync() ; + return 0 ; +} diff --git a/src/skaembutils/s6-tail.c b/src/skaembutils/s6-tail.c new file mode 100644 index 0000000..cc2d1f1 --- /dev/null +++ b/src/skaembutils/s6-tail.c @@ -0,0 +1,200 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/sgetopt.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/bytestr.h> +#include <skalibs/uint.h> +#include <skalibs/buffer.h> +#include <skalibs/strerr2.h> +#include <skalibs/djbunix.h> +#include <skalibs/skamisc.h> +#include <skalibs/siovec.h> + +#define USAGE "s6-tail [ -c chars | -n lines | -1..9 ] [ file ]" + +typedef int tailfunc_t (int, unsigned int) ; +typedef tailfunc_t *tailfunc_t_ref ; + +static int pluslines (int fd, unsigned int n) +{ + if (n) n-- ; + { + char buf[BUFFER_INSIZE] ; + buffer b = BUFFER_INIT(&buffer_read, fd, buf, BUFFER_INSIZE) ; + unsigned int count = 0 ; + while (count < n) + { + register int r = buffer_fill(&b) ; + if (r <= 0) return !r ; + while (!buffer_isempty(&b) && (count < n)) + { + siovec_t v[2] ; + unsigned int i ; + buffer_rpeek(&b, v) ; + i = siovec_bytechr(v, 2, '\n') ; + if (i < buffer_len(&b)) + { + count++ ; i++ ; + } + buffer_rseek(&b, i) ; + } + } + b.op = &buffer_write ; + b.fd = 1 ; + if (!buffer_flush(&b)) return 0 ; + } + return (fd_cat(fd, 1) >= 0) ; +} + +static int pluschars (int fd, unsigned int n) +{ + if (n-- > 1) + { + int nil = open_write("/dev/null") ; + if (nil < 0) return 0 ; + if (!fd_catn(fd, nil, n)) + { + register int e = errno ; + fd_close(nil) ; + errno = e ; + return 0 ; + } + fd_close(nil) ; + } + return (fd_cat(fd, 1) >= 0) ; +} + +static int minuslines (int fd, unsigned int n) +{ + char buf[BUFFER_INSIZE] ; + buffer b = BUFFER_INIT(&buffer_read, fd, buf, BUFFER_INSIZE) ; + unsigned int head = 0, tail = 0 ; + stralloc tab[n+1] ; + for (; head <= n ; head++) tab[head] = stralloc_zero ; + head = 0 ; + for (;;) + { + register int r ; + r = skagetln(&b, tab + tail, '\n') ; + if (!r) break ; + if (r < 0) + { + if (errno == EPIPE) break ; + else goto err ; + } + tail = (tail + 1) % (n+1) ; + if (tail == head) + { + tab[head].len = 0 ; + head = (head + 1) % (n+1) ; + } + } + buffer_init(&b, &buffer_write, 1, buf, BUFFER_INSIZE) ; + for (; head != tail ; head = (head + 1) % (n+1)) + { + if (buffer_put(&b, tab[head].s, tab[head].len) < tab[head].len) + goto err ; + } + for (head = 0 ; head <= n ; head++) stralloc_free(tab + head) ; + return buffer_flush(&b) ; + err: + for (head = 0 ; head <= n ; head++) stralloc_free(tab + head) ; + return 0 ; +} + +static int minuschars (int fd, unsigned int n) +{ + char buf[BUFFER_INSIZE + n] ; + buffer b = BUFFER_INIT(&buffer_read, fd, buf, BUFFER_INSIZE + n) ; + for (;;) + { + register int r = buffer_fill(&b) ; + if (!r) break ; + if (r < 0) return 0 ; + buffer_rseek(&b, buffer_len(&b)) ; + buffer_unget(&b, n) ; + } + b.op = &buffer_write ; + b.fd = 1 ; + return buffer_flush(&b) ; +} + +int main (int argc, char const *const *argv) +{ + tailfunc_t_ref f = &minuslines ; + unsigned int n = 10 ; + int gotit = 0 ; + PROG = "s6-tail" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "123456789n:c:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case '1' : + case '2' : + case '3' : + case '4' : + case '5' : + case '6' : + case '7' : + case '8' : + case '9' : + { + if (gotit) strerr_dieusage(100, USAGE) ; + gotit = 1 ; + f = &minuslines ; + n = opt - '0' ; + break ; + } + case 'n': + { + if (gotit) strerr_dieusage(100, USAGE) ; + gotit = 1 ; + f = &minuslines ; + if (*l.arg == '-') l.arg++ ; + else if (*l.arg == '+') + { + f = &pluslines ; + l.arg++ ; + } + if (!uint0_scan(l.arg, &n)) strerr_dieusage(100, USAGE) ; + break ; + } + case 'c': + { + if (gotit) strerr_dieusage(100, USAGE) ; + gotit = 1 ; + f = &minuschars ; + if (*l.arg == '-') l.arg++ ; + else if (*l.arg == '+') + { + f = &pluschars ; + l.arg++ ; + } + if (!uint0_scan(l.arg, &n)) strerr_dieusage(100, USAGE) ; + break ; + } + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (!argc) + { + if (!(*f)(0, n)) + strerr_diefu1sys(111, "tail stdin") ; + } + else + { + int fd = open_readb(argv[0]) ; + if (fd == -1) strerr_diefu3sys(111, "open ", argv[0], " for reading") ; + if (!(*f)(fd, n)) + strerr_diefu2sys(111, "tail ", argv[0]) ; + fd_close(fd) ; + } + return 0 ; +} diff --git a/src/skaembutils/s6-test.c b/src/skaembutils/s6-test.c new file mode 100644 index 0000000..3dda0b7 --- /dev/null +++ b/src/skaembutils/s6-test.c @@ -0,0 +1,515 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <skalibs/uint.h> +#include <skalibs/bytestr.h> +#include <skalibs/fmtscan.h> +#include <skalibs/strerr2.h> +#include <skalibs/djbunix.h> + +#define USAGE "s6-test expression or [ expression ]" + +enum opnum +{ + T_NOT, + T_AND, + T_OR, + T_LEFTP, + T_RIGHTP, + T_BLOCK, + T_CHAR, + T_DIR, + T_EXIST, + T_REGULAR, + T_SGID, + T_SYMLINK, + T_STICKY, + T_NONZERO, + T_FIFO, + T_READABLE, + T_NONZEROFILE, + T_TERM, + T_SUID, + T_WRITABLE, + T_EXECUTABLE, + T_ZERO, + T_EUID, + T_EGID, + T_SOCKET, + T_MODIFIED, + T_NEWER, + T_OLDER, + T_DEVINO, + T_STREQUAL, + T_STRNEQUAL, + T_STRLESSER, + T_STRLESSERE, + T_STRGREATER, + T_STRGREATERE, + T_NUMEQUAL, + T_NUMNEQUAL, + T_NUMGREATER, + T_NUMGREATERE, + T_NUMLESSER, + T_NUMLESSERE +} ; + +struct token +{ + char const *string ; + enum opnum op ; + unsigned int type ; +} ; + +struct node +{ + enum opnum op ; + unsigned int type ; + unsigned int arg1 ; + unsigned int arg2 ; + char const *data ; +} ; + +static unsigned int lex (struct node *tree, char const *const *argv) +{ + static struct token const tokens[44] = + { + { "-n", T_NONZERO, 2 }, + { "-z", T_ZERO, 2 }, + { "=", T_STREQUAL, 3 }, + { "!=", T_STRNEQUAL, 3 }, + { "-eq", T_NUMEQUAL, 3 }, + { "-ne", T_NUMNEQUAL, 3 }, + { "-gt", T_NUMGREATER, 3 }, + { "-ge", T_NUMGREATERE, 3 }, + { "-lt", T_NUMLESSER, 3 }, + { "-le", T_NUMLESSERE, 3 }, + { "-f", T_REGULAR, 2 }, + { "-h", T_SYMLINK, 2 }, + { "-L", T_SYMLINK, 2 }, + { "-e", T_EXIST, 2 }, + { "-k", T_STICKY, 2 }, + { "-a", T_AND, 7 }, + { "-o", T_OR, 8 }, + { "!", T_NOT, 6 }, + { "(", T_LEFTP, 4 }, + { ")", T_RIGHTP, 5 }, + { "-b", T_BLOCK, 2 }, + { "-c", T_CHAR, 2 }, + { "-d", T_DIR, 2 }, + { "-g", T_SGID, 2 }, + { "-p", T_FIFO, 2 }, + { "-r", T_READABLE, 2 }, + { "-s", T_NONZEROFILE, 2 }, + { "-t", T_TERM, 2 }, + { "-u", T_SUID, 2 }, + { "-w", T_WRITABLE, 2 }, + { "-x", T_EXECUTABLE, 2 }, + { "-O", T_EUID, 2 }, + { "-U", T_EUID, 2 }, + { "-G", T_EGID, 2 }, + { "-S", T_SOCKET, 2 }, + { "-N", T_MODIFIED, 2 }, + { "-nt", T_NEWER, 3 }, + { "-ot", T_OLDER, 3 }, + { "-ef", T_DEVINO, 3 }, + { "<", T_STRLESSER, 3 }, + { "<=", T_STRLESSERE, 3 }, + { ">", T_STRGREATER, 3 }, + { ">=", T_STRGREATERE, 3 }, + { 0, 0, 0 } + } ; + register unsigned int pos = 0 ; + + for (; argv[pos] ; pos++) + { + unsigned int i = 0 ; + tree[pos].data = argv[pos] ; + for (i = 0 ; tokens[i].string ; i++) + if (!str_diff(argv[pos], tokens[i].string)) + { + tree[pos].op = tokens[i].op ; + tree[pos].type = tokens[i].type ; + break ; + } + if (!tokens[i].string) + { + tree[pos].op = T_NONZERO ; + tree[pos].type = 0 ; + tree[pos].arg1 = pos ; + if (*(argv[pos]) == '\\') tree[pos].data++ ; /* better than SUSv3 */ + } + } + return pos ; +} + +static unsigned int parse (struct node *tree, unsigned int n) +{ + static char const table[9][13] = + { + "xssssxsssxxxx", + "xxxxxaxxxxxxx", + "xsxxsxsssxxxx", + "sxxxxxxxxxxxx", + "xsxxsxsssxxxx", + "nxxxxNxxxAOEs", + "xsxxsxsssxxxx", + "nxxxxNxxxAsxx", + "nxxxxNxxxAOsx" + } ; + + unsigned int stack[n+2] ; + unsigned int sp = 0, pos = 0 ; + int cont = 1 ; + + stack[0] = n+1 ; + tree[n].type = 5 ; /* add ) for the final reduce */ + tree[n+1].type = 1 ; /* add EOF */ + + while (cont) + { + switch (table[tree[pos].type][tree[stack[sp]].type]) + { + case 'x' : /* error */ + { + char fmt[UINT_FMT] ; + fmt[uint_fmt(fmt, pos)] = 0 ; + strerr_dief2x(100, "parse error at argument ", fmt) ; + break ; + } + case 'a' : /* accept */ + { + cont = 0 ; + break ; + } + case 's' : /* shift */ + { + stack[++sp] = pos++ ; + break ; + } + case 'n' : /* reduce -> expr without nots, from atom */ + { + switch (tree[stack[sp-1]].type) + { + case 2 : + { + tree[stack[sp-1]].arg1 = stack[sp] ; + sp-- ; + break ; + } + case 3 : + { + tree[stack[sp-1]].arg1 = stack[sp-2] ; + tree[stack[sp-1]].arg2 = stack[sp] ; + stack[sp-2] = stack[sp-1] ; + sp -= 2 ; + break ; + } + /* default : assert: its a zero */ + } + tree[stack[sp]].type = 9 ; + while (tree[stack[sp-1]].type == 6) + { + tree[stack[sp-1]].type = 9 ; + tree[stack[sp-1]].arg1 = stack[sp] ; + sp-- ; + } + break ; + } + case 'N' : /* reduce -> expr without nots, from expr */ + { + if (tree[stack[sp-2]].type != 4) + { + char fmt[UINT_FMT] ; + fmt[uint_fmt(fmt, pos)] = 0 ; + strerr_dief2x(100, "parse error: bad right parenthesis at argument ", fmt) ; + } + stack[sp-2] = stack[sp-1] ; + sp -= 2 ; + tree[stack[sp]].type = 9 ; + while (tree[stack[sp-1]].type == 6) + { + tree[stack[sp-1]].type = 9 ; + tree[stack[sp-1]].arg1 = stack[sp] ; + sp-- ; + } + break ; + } + case 'A' : /* reduce -> exprs without ands */ + { + if (tree[stack[sp-1]].type == 7) + { + tree[stack[sp-1]].arg1 = stack[sp-2] ; + tree[stack[sp-1]].arg2 = stack[sp] ; + stack[sp-2] = stack[sp-1] ; + sp -= 2 ; + } + tree[stack[sp]].type = 10 ; + break ; + } + case 'O' : /* reduce -> expr without ors */ + { + if (tree[stack[sp-1]].type == 8) + { + tree[stack[sp-1]].arg1 = stack[sp-2] ; + tree[stack[sp-1]].arg2 = stack[sp] ; + stack[sp-2] = stack[sp-1] ; + sp -= 2 ; + } + tree[stack[sp]].type = 11 ; + break ; + } + case 'E' : /* reduce -> expr */ + { + tree[stack[sp]].type = 12 ; + break ; + } + default : /* can't happen */ + strerr_dief1x(101, "internal error, please submit a bug-report.") ; + } + } + if (sp != 2) strerr_dief1x(100, "parse error: too many left parentheses") ; + return stack[1] ; +} + +static int run (struct node const *tree, unsigned int root) +{ + switch (tree[root].op) + { + case T_NOT : + return !run(tree, tree[root].arg1) ; + case T_AND : + return run(tree, tree[root].arg1) && run(tree, tree[root].arg2) ; + case T_OR : + return run(tree, tree[root].arg1) || run(tree, tree[root].arg2) ; + case T_EXIST : + { + struct stat st ; + return !stat(tree[tree[root].arg1].data, &st) ; + } + case T_BLOCK : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + return S_ISBLK(st.st_mode) ; + } + case T_CHAR : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + return S_ISCHR(st.st_mode) ; + } + case T_DIR : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + return S_ISDIR(st.st_mode) ; + } + case T_REGULAR : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + return S_ISREG(st.st_mode) ; + } + case T_FIFO : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + return S_ISFIFO(st.st_mode) ; + } + case T_SOCKET : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + return S_ISSOCK(st.st_mode) ; + } + case T_SYMLINK : + { + struct stat st ; + if (lstat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + return S_ISLNK(st.st_mode) ; + } + case T_SGID : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + return (st.st_mode & S_ISGID) ; + } + case T_SUID : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + return (st.st_mode & S_ISUID) ; + } + case T_STICKY : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + return (st.st_mode & S_ISVTX) ; + } + case T_NONZEROFILE : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + return (st.st_size > 0) ; + } + case T_MODIFIED : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + return (st.st_mtime > st.st_atime) ; + } + case T_EUID : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + return st.st_uid == geteuid() ; + } + case T_EGID : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + return st.st_gid == getegid() ; + } + case T_READABLE : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + if (st.st_uid == geteuid()) return st.st_mode & S_IRUSR ; + else if (st.st_gid == getegid()) return st.st_mode & S_IRGRP ; + else return st.st_mode & S_IROTH ; + } + case T_WRITABLE : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + if (st.st_uid == geteuid()) return st.st_mode & S_IWUSR ; + else if (st.st_gid == getegid()) return st.st_mode & S_IWGRP ; + else return st.st_mode & S_IWOTH ; + } + case T_EXECUTABLE : + { + struct stat st ; + if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; + if (st.st_uid == geteuid()) return st.st_mode & S_IXUSR ; + else if (st.st_gid == getegid()) return st.st_mode & S_IXGRP ; + else return st.st_mode & S_IXOTH ; + } + case T_NEWER : + { + struct stat st1, st2 ; + if (stat(tree[tree[root].arg1].data, &st1) == -1) return 0 ; + if (stat(tree[tree[root].arg2].data, &st2) == -1) return 1 ; + return st1.st_mtime > st2.st_mtime ; + } + case T_OLDER : + { + struct stat st1, st2 ; + if (stat(tree[tree[root].arg1].data, &st1) == -1) return 1 ; + if (stat(tree[tree[root].arg2].data, &st2) == -1) return 0 ; + return st1.st_mtime < st2.st_mtime ; + } + case T_DEVINO : + { + struct stat st1, st2 ; + if (stat(tree[tree[root].arg1].data, &st1) == -1) return 0 ; + if (stat(tree[tree[root].arg2].data, &st2) == -1) return 1 ; + return (st1.st_dev == st2.st_dev) && (st1.st_ino == st2.st_ino) ; + } + case T_TERM : + { + unsigned int fd ; + if (!uint0_scan(tree[tree[root].arg1].data, &fd)) + strerr_dief2x(100, tree[root].data, " requires an integer argument") ; + return isatty((int)fd) ; + } + case T_NONZERO : + return tree[tree[root].arg1].data[0] ; + case T_ZERO : + return !tree[tree[root].arg1].data[0] ; + case T_STREQUAL : + return !str_diff(tree[tree[root].arg1].data, tree[tree[root].arg2].data) ; + case T_STRNEQUAL : + return !!str_diff(tree[tree[root].arg1].data, tree[tree[root].arg2].data) ; + case T_STRLESSER : + return str_diff(tree[tree[root].arg1].data, tree[tree[root].arg2].data) < 0 ; + case T_STRLESSERE : + return str_diff(tree[tree[root].arg1].data, tree[tree[root].arg2].data) <= 0 ; + case T_STRGREATER : + return str_diff(tree[tree[root].arg1].data, tree[tree[root].arg2].data) > 0 ; + case T_STRGREATERE : + return str_diff(tree[tree[root].arg1].data, tree[tree[root].arg2].data) >= 0 ; + case T_NUMEQUAL : + { + int n1, n2 ; + if (!int_scan(tree[tree[root].arg1].data, &n1) + || !int_scan(tree[tree[root].arg2].data, &n2)) + goto errorint ; + return n1 == n2 ; + } + case T_NUMNEQUAL : + { + int n1, n2 ; + if (!int_scan(tree[tree[root].arg1].data, &n1) + || !int_scan(tree[tree[root].arg2].data, &n2)) + goto errorint ; + return n1 != n2 ; + } + case T_NUMGREATER : + { + int n1, n2 ; + if (!int_scan(tree[tree[root].arg1].data, &n1) + || !int_scan(tree[tree[root].arg2].data, &n2)) + goto errorint ; + return n1 > n2 ; + } + case T_NUMGREATERE : + { + int n1, n2 ; + if (!int_scan(tree[tree[root].arg1].data, &n1) + || !int_scan(tree[tree[root].arg2].data, &n2)) + goto errorint ; + return n1 >= n2 ; + } + case T_NUMLESSER : + { + int n1, n2 ; + if (!int_scan(tree[tree[root].arg1].data, &n1) + || !int_scan(tree[tree[root].arg2].data, &n2)) + goto errorint ; + return n1 < n2 ; + } + case T_NUMLESSERE : + { + int n1, n2 ; + if (!int_scan(tree[tree[root].arg1].data, &n1) + || !int_scan(tree[tree[root].arg2].data, &n2)) + goto errorint ; + return n1 <= n2 ; + } + default: + strerr_dief1x(111, "operation not implemented") ; + } + +errorint: + strerr_dief2x(100, tree[root].data, " requires integer arguments") ; +} + +int main (int argc, char const *const *argv) +{ + PROG = "s6-test" ; + if (argc <= 1) return 1 ; + { + struct node tree[argc + 2] ; + unsigned int n = lex(tree, argv+1) ; + if ((argv[0][0] == '[') && !argv[0][1]) + { + if (n && (!tree[n-1].type) && (tree[n-1].data[0] == ']') && !tree[n-1].data[1]) + n-- ; + else strerr_dief1x(100, "parse error: missing closing bracket") ; + } + return !run(tree, parse(tree, n)) ; + } +} diff --git a/src/skaembutils/s6-touch.c b/src/skaembutils/s6-touch.c new file mode 100644 index 0000000..b149835 --- /dev/null +++ b/src/skaembutils/s6-touch.c @@ -0,0 +1,20 @@ +/* ISC license. */ + +#include <skalibs/strerr2.h> +#include <skalibs/djbunix.h> + +#define USAGE "s6-touch file ..." + +int main (int argc, char const *const *argv) +{ + char const *const *p = argv + 1 ; + PROG = "s6-touch" ; + if (argc < 2) strerr_dieusage(100, USAGE) ; + for (; *p ; p++) + { + register int fd = open_append(*p) ; + if (fd < 0) strerr_diefu2sys(111, "open_append ", *p) ; + fd_close(fd) ; + } + return 0 ; +} diff --git a/src/skaembutils/s6-true.c b/src/skaembutils/s6-true.c new file mode 100644 index 0000000..65c3af4 --- /dev/null +++ b/src/skaembutils/s6-true.c @@ -0,0 +1,6 @@ +/* ISC license. */ + +int main () +{ + return 0 ; +} diff --git a/src/skaembutils/s6-uniquename.c b/src/skaembutils/s6-uniquename.c new file mode 100644 index 0000000..06418e5 --- /dev/null +++ b/src/skaembutils/s6-uniquename.c @@ -0,0 +1,40 @@ +/* ISC license. */ + +#include <skalibs/allreadwrite.h> +#include <skalibs/sgetopt.h> +#include <skalibs/uint.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/skamisc.h> +#include <skalibs/random.h> + +#define USAGE "s6-uniquename [ -n randomlen ] prefix" +#define usage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv) +{ + stralloc sa = STRALLOC_ZERO ; + unsigned int n = 8 ; + PROG = "s6-uniquename" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "n:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'n' : if (!uint0_scan(l.arg, &n)) usage() ; break ; + default : usage() ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (argc < 1) usage() ; + if (!stralloc_cats(&sa, argv[0])) strerr_diefu1sys(111, "stralloc_cats") ; + if ((n ? random_sauniquename(&sa, n) : sauniquename(&sa)) < 0) + strerr_diefu1sys(111, "make unique name") ; + if (!stralloc_catb(&sa, "\n", 1)) strerr_diefu1sys(111, "stralloc_cats") ; + if (allwrite(1, sa.s, sa.len) < sa.len) strerr_diefu1sys(111, "write to stdout") ; + return 0 ; +} diff --git a/src/skaembutils/s6-unquote-filter.c b/src/skaembutils/s6-unquote-filter.c new file mode 100644 index 0000000..08477ef --- /dev/null +++ b/src/skaembutils/s6-unquote-filter.c @@ -0,0 +1,198 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/sgetopt.h> +#include <skalibs/bytestr.h> +#include <skalibs/uint.h> +#include <skalibs/strerr2.h> +#include <skalibs/buffer.h> +#include <skalibs/stralloc.h> +#include <skalibs/skamisc.h> + +#define USAGE "s6-unquote-filter [ -q | -Q | -v | -w ] [ -d delim ]" + +static unsigned int strictness = 1 ; +static char const *delim = "\"" ; +static unsigned int delimlen = 1 ; + +static void fillfmt (char *fmt, char const *s, unsigned int len) +{ + register unsigned int n = len < 39 ? len+1 : 36 ; + byte_copy(fmt, n, s) ; + if (len >= 39) + { + byte_copy(fmt+n, 3, "...") ; + n += 3 ; + } + fmt[n] = 0 ; +} + +static int doit (char const *s, unsigned int len) +{ + if (delimlen) + { + if (!len) + { + switch (strictness) + { + case 1 : + case 2 : + strerr_warnw1x("empty line") ; + break ; + case 3 : + buffer_flush(buffer_1) ; + strerr_dief1x(100, "empty line") ; + default : break ; + } + return 1 ; + } + if (byte_chr(delim, delimlen, *s) >= delimlen) + { + switch (strictness) + { + case 0 : return 0 ; + case 1 : + { + strerr_warnw1x("invalid starting quote character") ; + return 0 ; + } + case 2 : + { + char fmt[40] ; + fillfmt(fmt, s, len) ; + strerr_warnw3x("invalid starting quote character", " in line: ", fmt) ; + return 0 ; + } + case 3 : + { + buffer_flush(buffer_1) ; + strerr_dief1x(100, "invalid starting quote character") ; + } + default : strerr_dief1x(101, "can't happen: unknown strictness") ; + } + } + } + { + unsigned int r, w ; + char d[len] ; + if (!string_unquote_withdelim(d, &w, s + !!delimlen, len - !!delimlen, &r, delim, delimlen)) + { + switch (strictness) + { + case 0 : return 0 ; + case 1 : + { + strerr_warnwu1sys("unquote") ; + return 0 ; + } + case 2 : + { + char fmt[40] ; + fillfmt(fmt, s, len) ; + strerr_warnwu3sys("unquote", " line: ", fmt) ; + return 0 ; + } + case 3 : + { + int e = errno ; + buffer_flush(buffer_1) ; + errno = e ; + strerr_diefu1sys(100, "unquote") ; + } + default : strerr_dief1x(101, "can't happen: unknown strictness") ; + } + } + if (delimlen) + { + if (r+1 == len) + { + switch (strictness) + { + case 0 : return 0 ; + case 1 : + { + strerr_warnwu2x("unquote", ": no ending quote character") ; + return 0 ; + } + case 2 : + { + char fmt[40] ; + fillfmt(fmt, s, len) ; + strerr_warnwu5x("unquote", ": no ending quote character", " in ", "line: ", fmt) ; + return 0 ; + } + case 3 : + { + int e = errno ; + buffer_flush(buffer_1) ; + errno = e ; + strerr_diefu2x(100, "unquote", ": no ending quote character") ; + } + default : strerr_dief1x(101, "can't happen: unknown strictness") ; + } + } + else if ((r+2 < len) && (strictness >= 2)) + { + char fmtnum[UINT_FMT] ; + char fmtden[UINT_FMT] ; + char fmt[40] ; + fillfmt(fmt, s, len) ; + fmtnum[uint_fmt(fmtnum, r+1)] = 0 ; + fmtden[uint_fmt(fmtden, len-1)] = 0 ; + strerr_warnw7x("found ending quote character at position ", fmtnum, "/", fmtden, ", ignoring remainder of ", "line: ", fmt) ; + } + } + if (buffer_put(buffer_1, d, w) < (int)w) + strerr_diefu1sys(111, "write to stdout") ; + } + return 1 ; +} + + +int main (int argc, char const *const *argv) +{ + stralloc src = STRALLOC_ZERO ; + PROG = "s6-unquote-filter" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "qQvwd:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'q': strictness = 0 ; break ; + case 'Q': strictness = 1 ; break ; + case 'v': strictness = 2 ; break ; + case 'w': strictness = 3 ; break ; + case 'd': delim = l.arg ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + delimlen = str_len(delim) ; + for (;;) + { + int r ; + src.len = 0 ; + r = skagetln(buffer_0f1, &src, '\n') ; + if (!r) break ; + if (r < 0) + { + if (errno != EPIPE) strerr_diefu1sys(111, "read from stdin") ; + } + else src.len-- ; + if (!doit(src.s, src.len)) + { + if (buffer_put(buffer_1, src.s, src.len) < (int)src.len) + strerr_diefu1sys(111, "write to stdout") ; + } + if (r > 0) + { + if (buffer_put(buffer_1, "\n", 1) < 1) + strerr_diefu1sys(111, "write to stdout") ; + } + } + return 0 ; +} diff --git a/src/skaembutils/s6-unquote.c b/src/skaembutils/s6-unquote.c new file mode 100644 index 0000000..37c3dfb --- /dev/null +++ b/src/skaembutils/s6-unquote.c @@ -0,0 +1,70 @@ +/* ISC license. */ + +#include <skalibs/sgetopt.h> +#include <skalibs/bytestr.h> +#include <skalibs/uint.h> +#include <skalibs/strerr2.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/skamisc.h> + +#define USAGE "s6-unquote [ -n ] [ -d delim ] string" + +int main (int argc, char const *const *argv) +{ + char const *delim = "\"" ; + unsigned int len, delimlen ; + int nl = 1 ; + char const *string ; + PROG = "s6-unquote" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "nd:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'n' : nl = 0 ; break ; + case 'd': delim = l.arg ; break ; + default : strerr_dieusage(100, USAGE) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (!argc) strerr_dieusage(100, USAGE) ; + string = *argv ; + len = str_len(string) ; + delimlen = str_len(delim) ; + if (delimlen) + { + if (!len--) strerr_dief1x(100, "the empty string isn't a quoted string") ; + if (byte_chr(delim, delimlen, *string++) >= delimlen) + strerr_dief1x(100, "invalid starting quote character") ; + } + { + unsigned int r = 0, w = 0 ; + char buf[len+1] ; + if (!string_unquote_withdelim(buf, &w, string, len, &r, delim, delimlen)) + { + char fmt[UINT_FMT] ; + fmt[uint_fmt(fmt, r + !!delimlen)] = 0 ; + strerr_diefu2sys(100, "unquote at character ", fmt) ; + } + if (delimlen) + { + if (r == len) strerr_dief1x(100, "no ending quote character") ; + else if (r < len - 1) + { + char fmtnum[UINT_FMT] ; + char fmtden[UINT_FMT] ; + fmtnum[uint_fmt(fmtnum, r+1)] = 0 ; + fmtden[uint_fmt(fmtden, len)] = 0 ; + strerr_warnw5x("found ending quote character at position ", fmtnum, "/", fmtden, "; ignoring remainder") ; + } + } + if (nl) buf[w++] = '\n' ; + if (allwrite(1, buf, w) < w) + strerr_diefu1sys(111, "write to stdout") ; + } + return 0 ; +} diff --git a/src/skaembutils/s6-update-symlinks.c b/src/skaembutils/s6-update-symlinks.c new file mode 100644 index 0000000..ba89b06 --- /dev/null +++ b/src/skaembutils/s6-update-symlinks.c @@ -0,0 +1,367 @@ +/* ISC license. */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <skalibs/bytestr.h> +#include <skalibs/direntry.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/djbunix.h> +#include <skalibs/random.h> + +#define USAGE "s6-update-symlinks /destdir /srcdir [ /srcdir ... ]" + +#define MAGICNEW ":s6-update-symlinks-new" +#define MAGICOLD ":s6-update-symlinks-old" + +#define CONFLICT -2 +#define ERROR -1 +#define MODIFIED 0 +#define OVERRIDEN 1 + +static stralloc errdst = STRALLOC_ZERO ; +static stralloc errsrc = STRALLOC_ZERO ; + + +typedef struct stralloc3 stralloc3, *stralloc3_ref ; +struct stralloc3 +{ + stralloc dst ; + stralloc src ; + stralloc tmp ; +} ; + +#define STRALLOC3_ZERO { STRALLOC_ZERO, STRALLOC_ZERO, STRALLOC_ZERO } + + +static void cleanup (stralloc *sa, unsigned int pos) +{ + register int e = errno ; + rm_rf_in_tmp(sa, pos) ; + errno = e ; +} + + +static int makeuniquename (stralloc *sa, char const *path, char const *magic) +{ + unsigned int base = sa->len ; + int wasnull = !sa->s ; + if (!stralloc_cats(sa, path)) return 0 ; + if (!stralloc_cats(sa, magic)) goto err ; + if (random_sauniquename(sa, 8) == -1) goto err ; + if (!stralloc_0(sa)) goto err ; + return 1 ; + +err: + if (wasnull) stralloc_free(sa) ; else sa->len = base ; + return 0 ; +} + + +static int addlink (stralloc3 *blah, unsigned int dstpos, unsigned int srcpos) +{ + if (symlink(blah->src.s + srcpos, blah->dst.s + dstpos) >= 0) return MODIFIED ; + if (errno != EEXIST) return ERROR ; + + { + unsigned int dstbase = blah->dst.len ; + unsigned int srcbase = blah->src.len ; + unsigned int tmpbase = blah->tmp.len ; + unsigned int dststop ; + unsigned int srcstop ; + signed int diffsize = 0 ; + int collect = 1 ; + + { + register unsigned int n = str_len(blah->dst.s + dstpos) ; + if (!stralloc_readyplus(&blah->dst, n+1)) return ERROR ; + stralloc_catb(&blah->dst, blah->dst.s + dstpos, n) ; + } + stralloc_catb(&blah->dst, "/", 1) ; + dststop = blah->dst.len ; + + { + int r ; + DIR *dir = opendir(blah->dst.s + dstpos) ; + if (!dir) + { + blah->dst.len = dstbase ; + if (errno != ENOTDIR) return ERROR ; + if ((unlink(blah->dst.s + dstpos) == -1) + || (symlink(blah->src.s + srcpos, blah->dst.s + dstpos) == -1)) + return ERROR ; + return OVERRIDEN ; /* replaced a link to a normal file */ + } + r = sareadlink(&blah->src, blah->dst.s + dstpos) ; + if ((r == -1) && (errno != EINVAL)) + { + register int e = errno ; + blah->dst.len = dstbase ; + dir_close(dir) ; + errno = e ; + return ERROR ; + } + if (r < 0) + { + for (;;) + { + register direntry *d ; + errno = 0 ; + d = readdir(dir) ; + if (!d) break ; + if ((d->d_name[0] == '.') && (!d->d_name[1] || ((d->d_name[1] == '.') && !d->d_name[2]))) + continue ; + diffsize-- ; /* need to know the size for collect */ + } + if (errno) + { + register int e = errno ; + blah->src.len = srcbase ; + blah->dst.len = dstbase ; + dir_close(dir) ; + errno = e ; + return ERROR ; + } + } + else if ((unlink(blah->dst.s + dstpos) == -1) + || (mkdir(blah->dst.s + dstpos, 0777) == -1) + || !stralloc_catb(&blah->src, "/", 1)) + { + register int e = errno ; + blah->src.len = srcbase ; + blah->dst.len = dstbase ; + dir_close(dir) ; + errno = e ; + return ERROR ; + } + else /* expand */ + { + srcstop = blah->src.len ; + for (;;) + { + register direntry *d ; + errno = 0 ; + d = readdir(dir) ; + if (!d) break ; + if ((d->d_name[0] == '.') && (!d->d_name[1] || ((d->d_name[1] == '.') && !d->d_name[2]))) + continue ; + diffsize-- ; + blah->dst.len = dststop ; + blah->src.len = srcstop ; + if (!stralloc_cats(&blah->dst, d->d_name) || !stralloc_0(&blah->dst) + || !stralloc_cats(&blah->src, d->d_name) || !stralloc_0(&blah->src) + || (symlink(blah->src.s + srcbase, blah->dst.s + dstbase) == -1)) + { + register int e = errno ; + blah->src.len = srcbase ; + blah->dst.len = dstbase ; + dir_close(dir) ; + errno = e ; + return ERROR ; + } + } + if (errno) + { + register int e = errno ; + blah->src.len = srcbase ; + blah->dst.len = dstbase ; + dir_close(dir) ; + errno = e ; + return ERROR ; + } + } + dir_close(dir) ; + } + + blah->src.len = srcbase ; + { + register unsigned int n = str_len(blah->src.s + srcpos) ; + if (!stralloc_readyplus(&blah->src, n+1)) + { + blah->dst.len = dstbase ; + return ERROR ; + } + stralloc_catb(&blah->src, blah->src.s + srcpos, n) ; + } + stralloc_catb(&blah->src, "/", 1) ; + srcstop = blah->src.len ; + + + /* prepare tmp for recursion */ + + { + DIR *dir = opendir(blah->src.s + srcpos) ; + if (!dir) + { + blah->src.len = srcbase ; + blah->dst.len = dstbase ; + if (errno != ENOTDIR) return ERROR ; + errdst.len = errsrc.len = 0 ; + if (!stralloc_cats(&errdst, blah->dst.s + dstpos) || !stralloc_0(&errdst) + || !stralloc_cats(&errsrc, blah->src.s + srcpos) || !stralloc_0(&errsrc)) + return ERROR ; + return CONFLICT ; /* dst is a dir but src is not */ + } + for (;;) + { + register direntry *d ; + errno = 0 ; + d = readdir(dir) ; + if (!d) break ; + if ((d->d_name[0] == '.') && (!d->d_name[1] || ((d->d_name[1] == '.') && !d->d_name[2]))) + continue ; + if (!stralloc_cats(&blah->tmp, d->d_name) || !stralloc_0(&blah->tmp)) + { + register int e = errno ; + blah->tmp.len = tmpbase ; + blah->src.len = srcbase ; + blah->dst.len = dstbase ; + dir_close(dir) ; + errno = e ; + return ERROR ; + } + } + if (errno) + { + register int e = errno ; + blah->tmp.len = tmpbase ; + blah->src.len = srcbase ; + blah->dst.len = dstbase ; + dir_close(dir) ; + errno = e ; + return ERROR ; + } + dir_close(dir) ; + } + + + /* recurse */ + + { + unsigned int i = tmpbase ; + while (i < blah->tmp.len) + { + diffsize++ ; + blah->dst.len = dststop ; + blah->src.len = srcstop ; + { + register unsigned int n = str_len(blah->tmp.s + i) + 1 ; + if (!stralloc_catb(&blah->dst, blah->tmp.s + i, n) + || !stralloc_catb(&blah->src, blah->tmp.s + i, n)) + { + blah->tmp.len = tmpbase ; + blah->src.len = srcbase ; + blah->dst.len = dstbase ; + return ERROR ; + } + i += n ; + } + switch (addlink(blah, dstbase, srcbase)) + { + case ERROR : + blah->tmp.len = tmpbase ; + blah->src.len = srcbase ; + blah->dst.len = dstbase ; + return ERROR ; + case CONFLICT : + blah->tmp.len = tmpbase ; + blah->src.len = srcbase ; + blah->dst.len = dstbase ; + return CONFLICT ; + case MODIFIED : + collect = 0 ; + } + } + } + blah->tmp.len = tmpbase ; + blah->src.len = srcbase ; + blah->dst.len = dstbase ; + + + /* collect */ + + if (collect && !diffsize) + { + if (rm_rf_in_tmp(&blah->dst, dstpos) == -1) return ERROR ; + if (symlink(blah->src.s + srcpos, blah->dst.s + dstpos) == -1) return ERROR ; + return OVERRIDEN ; + } + } + return MODIFIED ; +} + +int main (int argc, char *const *argv) +{ + stralloc3 blah = STRALLOC3_ZERO ; + PROG = "s6-update-symlinks" ; + if (argc < 3) strerr_dieusage(100, USAGE) ; + { + register char *const *p = argv + 1 ; + for (; *p ; p++) if (**p != '/') strerr_dieusage(100, USAGE) ; + } + { + register unsigned int i = str_len(argv[1]) ; + while (i && (argv[1][i-1] == '/')) argv[1][--i] = 0 ; + if (!i) strerr_diefu1x(100, "replace root directory") ; + } + if (!makeuniquename(&blah.dst, argv[1], MAGICNEW)) + strerr_diefu2sys(111, "make random unique name based on ", argv[1]) ; + if ((unlink(blah.dst.s) == -1) && (errno != ENOENT)) + strerr_diefu2sys(111, "unlink ", blah.dst.s) ; + + { + char *const *p = argv + 2 ; + for (; *p ; p++) + { + register int r ; + blah.src.len = 0 ; + if (!stralloc_cats(&blah.src, *p) || !stralloc_0(&blah.src)) + strerr_diefu1sys(111, "make stralloc") ; + r = addlink(&blah, 0, 0) ; + if (r < 0) + { + stralloc_free(&blah.tmp) ; + stralloc_free(&blah.src) ; + cleanup(&blah.dst, 0) ; + stralloc_free(&blah.dst) ; + if (r == CONFLICT) + strerr_dief4x(100, "destination ", errdst.s, " conflicts with source ", errsrc.s) ; + else + strerr_dief2sys(111, "error processing ", *p) ; + } + } + } + stralloc_free(&blah.tmp) ; + + if (rename(blah.dst.s, argv[1]) == -1) /* be atomic if possible */ + { + blah.src.len = 0 ; + if (!makeuniquename(&blah.src, argv[1], MAGICOLD)) + { + cleanup(&blah.dst, 0) ; + strerr_diefu2sys(111, "make random unique name based on ", argv[1]) ; + } + + if (rename(argv[1], blah.src.s) == -1) + { + cleanup(&blah.dst, 0) ; + strerr_diefu4sys(111, "rename ", argv[1], " to ", blah.src.s) ; + } + /* XXX: unavoidable race condition here: argv[1] does not exist */ + if (rename(blah.dst.s, argv[1]) == -1) + { + rename(blah.src.s, argv[1]) ; + cleanup(&blah.dst, 0) ; + strerr_diefu4sys(111, "rename ", blah.dst.s, " to ", argv[1]) ; + } + stralloc_free(&blah.dst) ; + if (rm_rf_in_tmp(&blah.src, 0) == -1) + strerr_warnwu2sys("remove old directory ", blah.src.s) ; + stralloc_free(&blah.src) ; + } + + return 0 ; +} |