diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/execline/wait.c | 54 | ||||
-rw-r--r-- | src/posix/deps-exe/posix-cd | 1 | ||||
-rw-r--r-- | src/posix/posix-cd.c | 155 |
3 files changed, 195 insertions, 15 deletions
diff --git a/src/execline/wait.c b/src/execline/wait.c index 2fdbe80..2a2ead2 100644 --- a/src/execline/wait.c +++ b/src/execline/wait.c @@ -14,36 +14,50 @@ #define USAGE "wait [ -I | -i ] [ -r | -t timeout ] { pids... }" #define dieusage() strerr_dieusage(100, USAGE) -typedef int actfunc_t (pid_t *, unsigned int *) ; +typedef int actfunc_t (pid_t *, unsigned int *, int *) ; typedef actfunc_t *actfunc_t_ref ; -static inline void waitall (void) +static inline int waitall (void) { + int wstat = 0 ; pid_t r = 1 ; - while (r > 0) r = wait(0) ; - if (r < 0 && errno != ECHILD) strerr_diefu1sys(111, "wait") ; + while (r > 0) r = wait(&wstat) ; + if (r < 0) + { + if (errno != ECHILD) strerr_diefu1sys(111, "wait") ; + else return 127 ; + } + return wait_estatus(wstat) ; } -static int waitany (pid_t *dummytab, unsigned int *dummyn) +static int waitany (pid_t *dummytab, unsigned int *dummyn, int *res) { + int wstat ; pid_t r = 1 ; - while (r > 0) r = wait_nohang(0) ; - if (!r) return 1 ; + while (r > 0) r = wait_nohang(&wstat) ; + if (!r) return (*res = wait_estatus(wstat), 1) ; if (errno != ECHILD) strerr_diefu1sys(111, "wait") ; + *res = 127 ; (void)dummytab ; (void)dummyn ; return 0 ; } -static int waitintab (pid_t *tab, unsigned int *n) +static int waitintab (pid_t *tab, unsigned int *n, int *res) { unsigned int i = 0 ; for (; i < *n ; i++) { - pid_t r = waitpid(tab[i], 0, WNOHANG) ; + int wstat ; + pid_t r = waitpid(tab[i], &wstat, WNOHANG) ; if (r) { - if (r < 0 && errno != ECHILD) strerr_diefu1sys(111, "waitpid") ; + if (r < 0) + { + if (errno == ECHILD) *res = 127 ; + else strerr_diefu1sys(111, "waitpid") ; + } + else *res = wait_estatus(wstat) ; tab[i--] = tab[--(*n)] ; } } @@ -61,15 +75,16 @@ static inline void handle_signals (void) } } -static inline void mainloop (tain_t *deadline, int insist, actfunc_t_ref f, pid_t *tab, unsigned int *n) +static inline int mainloop (tain_t *deadline, int insist, actfunc_t_ref f, pid_t *tab, unsigned int *n) { iopause_fd x = { .events = IOPAUSE_READ } ; + int res = 0 ; x.fd = selfpipe_init() ; if (x.fd < 0) strerr_diefu1sys(111, "create selfpipe") ; if (selfpipe_trap(SIGCHLD) < 0) strerr_diefu1sys(111, "trap SIGCHLD") ; tain_now_set_stopwatch_g() ; tain_add_g(deadline, deadline) ; - while ((*f)(tab, n)) + while ((*f)(tab, n, &res)) { int r = iopause_g(&x, 1, deadline) ; if (r < 0) strerr_diefu1sys(111, "iopause") ; @@ -82,6 +97,7 @@ static inline void mainloop (tain_t *deadline, int insist, actfunc_t_ref f, pid_ else handle_signals() ; } selfpipe_finish() ; + return res ; } int main (int argc, char const **argv, char const *const *envp) @@ -90,6 +106,8 @@ int main (int argc, char const **argv, char const *const *envp) int argc1 ; int hastimeout = 0 ; int insist = 0 ; + int r ; + int hasblock ; PROG = "wait" ; { subgetopt_t l = SUBGETOPT_ZERO ; @@ -112,8 +130,13 @@ int main (int argc, char const **argv, char const *const *envp) else tto = tain_infinite_relative ; } argc1 = el_semicolon(argv) ; - if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ; - if (!argc1 && !hastimeout) waitall() ; + if (argc1 >= argc) + { + hasblock = 0 ; + argc1 = argc ; + } + else hasblock = 1 ; + if (!argc1 && !hastimeout) r = waitall() ; else { actfunc_t_ref f = argc1 ? &waitintab : &waitany ; @@ -125,8 +148,9 @@ int main (int argc, char const **argv, char const *const *envp) for (; i < n ; i++) if (!pid0_scan(argv[i], tab+i)) strerr_dieusage(100, USAGE) ; } - mainloop(&tto, insist, f, tab, &n) ; + r = mainloop(&tto, insist, f, tab, &n) ; } + if (!hasblock) return r ; xpathexec0_run(argv + argc1 + 1, envp) ; } diff --git a/src/posix/deps-exe/posix-cd b/src/posix/deps-exe/posix-cd new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/posix/deps-exe/posix-cd @@ -0,0 +1 @@ +-lskarnet diff --git a/src/posix/posix-cd.c b/src/posix/posix-cd.c new file mode 100644 index 0000000..8a98981 --- /dev/null +++ b/src/posix/posix-cd.c @@ -0,0 +1,155 @@ +/* ISC license. */ + +#include <sys/stat.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <limits.h> +#include <locale.h> + +#include <skalibs/bytestr.h> +#include <skalibs/sgetopt.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/djbunix.h> + +#define USAGE "posix-cd [ -L | -P ] [ - | path ] [ prog... ]" +#define dieusage() strerr_dieusage(100, USAGE) +#define dienomem() strerr_diefu1sys(100, "stralloc_catb") + +int main (int argc, char const **argv, char const *const *envp) +{ + int phy = 0 ; + int dopwd = 0 ; + char const *where ; + int got = 0 ; + stralloc sa = STRALLOC_ZERO ; + PROG = "posix-cd" ; + setlocale(LC_ALL, "") ; /* yeah, as if */ + + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + int opt = subgetopt_r(argc, argv, "LP", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'L' : phy = 0 ; break ; + case 'P' : phy = 1 ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (!argc) where = getenv("HOME") ; + else + { + where = *argv++ ; + if (!strcmp(where, "-")) + { + where = getenv("OLDPWD") ; + dopwd = 1 ; + } + } + if (!where || !where[0]) dieusage() ; + + if ((where[0] != '/' && (where[0] != '.')) || (where[1] && where[1] != '.')) + { + char const *cdpath = getenv("CDPATH") ; + if (cdpath) + { + size_t pos = 0 ; + size_t len = strlen(cdpath) ; + while (pos < len) + { + struct stat st ; + size_t m = byte_chr(cdpath + pos, len - pos, ':') ; + sa.len = 0 ; + if (m) + { + if (!stralloc_catb(&sa, cdpath + pos, m)) dienomem() ; + if (cdpath[pos + m - 1] != '/' && !stralloc_catb(&sa, "/", 1)) dienomem() ; + } + else if (!stralloc_catb(&sa, "./", 2)) dienomem() ; + if (!stralloc_cats(&sa, where) || !stralloc_0(&sa)) dienomem() ; + if (!stat(sa.s, &st) && S_ISDIR(st.st_mode)) + { + got = 1 ; + dopwd = 1 ; + break ; + } + pos += m+1 ; + } + } + } + + if (!got && (!stralloc_cats(&sa, where) || !stralloc_0(&sa))) dienomem() ; + + { + size_t sabase = sa.len ; + if (sagetcwd(&sa) < 0) strerr_diefu1sys(111, "getcwd") ; + if (!stralloc_0(&sa)) dienomem() ; + if (!pathexec_env("OLDPWD", sa.s + sabase)) dienomem() ; + sa.len = sabase ; + } + + if (!phy) + { + char const *x = getenv("PWD") ; + if (x && sa.s[0] != '/') + { + size_t len = strlen(x) ; + int doslash = len && x[len-1] != '/' ; + if (!stralloc_insertb(&sa, 0, x, len + doslash)) dienomem() ; + if (doslash) sa.s[len] = '/' ; + } + { + stralloc tmp = STRALLOC_ZERO ; + if (!stralloc_ready(&tmp, sa.len + 2)) dienomem() ; + if (!path_canonicalize(tmp.s, sa.s, 1)) + strerr_diefu4sys(111, "canonicalize ", sa.s, ": problem with ", tmp.s) ; + stralloc_free(&sa) ; + sa = tmp ; + } + if (!pathexec_env("PWD", sa.s)) dienomem() ; + if (sa.len > PATH_MAX && strlen(where) < PATH_MAX && x && *x) + { + size_t len = strlen(x) ; + int hasslash = x[len-1] == '/' ; + if (!strncmp(sa.s, x, len)) + { + if (hasslash || (sa.len > len && sa.s[len] == '/')) + { + sa.len -= len + !hasslash ; + memmove(sa.s, sa.s + len + !hasslash, sa.len) ; + } + } + } + } + + /* fking finally */ + + if (chdir(sa.s) < 0) + strerr_diefu2sys(111, "chdir to ", where) ; + + /* and there's still more nonsense to do afterwards! */ + + if (phy) + { + sa.len = 0 ; + if (sagetcwd(&sa) < 0) strerr_diefu1sys(111, "getcwd") ; + if (!stralloc_0(&sa)) dienomem() ; + if (!pathexec_env("PWD", sa.s)) dienomem() ; + } + + if (dopwd) + { + sa.s[sa.len - 1] = '\n' ; + if (allwrite(1, sa.s, sa.len) < sa.len) + strerr_diefu1sys(111, "write to stdout") ; + } + + xpathexec0(argv) ; +} |