diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/execline/deps-exe/dollarsharp | 1 | ||||
| -rw-r--r-- | src/execline/dollarsharp.c | 23 | ||||
| -rw-r--r-- | src/execline/wait.c | 257 |
3 files changed, 151 insertions, 130 deletions
diff --git a/src/execline/deps-exe/dollarsharp b/src/execline/deps-exe/dollarsharp new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/execline/deps-exe/dollarsharp @@ -0,0 +1 @@ +-lskarnet diff --git a/src/execline/dollarsharp.c b/src/execline/dollarsharp.c new file mode 100644 index 0000000..b382061 --- /dev/null +++ b/src/execline/dollarsharp.c @@ -0,0 +1,23 @@ +/* ISC license. */ + +#include <unistd.h> + +#include <skalibs/types.h> +#include <skalibs/buffer.h> +#include <skalibs/prog.h> +#include <skalibs/strerr.h> + +#define USAGE "dollarsharp [ args ]" + +int main (int argc, char const *const *argv) +{ + size_t len ; + char fmt[UINT_FMT] ; + PROG = "dollarsharp" ; + if (argc-- <= 0) strerr_dieusage(100, USAGE) ; + len = uint_fmt(fmt, argc) ; + fmt[len++] = '\n' ; + if (buffer_putflush(buffer_1small, fmt, len) == -1) + strerr_diefu1sys(111, "write to stdout") ; + _exit(0) ; +} diff --git a/src/execline/wait.c b/src/execline/wait.c index d320d54..2715344 100644 --- a/src/execline/wait.c +++ b/src/execline/wait.c @@ -1,10 +1,10 @@ /* ISC license. */ #include <unistd.h> - #include <sys/wait.h> #include <errno.h> +#include <skalibs/uint64.h> #include <skalibs/types.h> #include <skalibs/envexec.h> #include <skalibs/tai.h> @@ -12,167 +12,167 @@ #include <skalibs/selfpipe.h> #include <skalibs/iopause.h> -#include <execline/config.h> #include <execline/execline.h> -#define USAGE "wait [ -I | -i ] [ -a | -o ] [ -r | -t timeout ] { pids... } [ prog... ]" +#define USAGE "wait [ -u ] [ -a | -o ] [ -t timeout ] { [ pids... ] } [ prog... ]" #define dieusage() strerr_dieusage(100, USAGE) -typedef int ac_func (pid_t *, unsigned int *, int *) ; -typedef ac_func *ac_func_ref ; +typedef pid_t wait_ac_func (void *, int *) ; +typedef wait_ac_func *wait_ac_func_ref ; -static int wait_all (void) +enum wait_golb_e { - errno = 0 ; - while (wait_nointr(0) > 0) ; - if (errno != ECHILD) strerr_diefu1sys(111, "wait") ; - return 0 ; -} + WAIT_GOLB_JUSTONE = 0x01, + WAIT_GOLB_NOEXPORT = 0x02, +} ; -static int wait_from_list (pid_t *pids, unsigned int n) +enum wait_gola_e { - int wstat = -1 ; - if (!waitn_posix(pids, n, &wstat) && errno != ECHILD) - strerr_diefu1sys(111, "wait") ; - return wstat == -1 ? -1 : wait_estatus(wstat) ; -} + WAIT_GOLA_TIMEOUT, + WAIT_GOLA_N +} ; -static int wait_one (pid_t *pid) +struct wait_pidlist_s { - int wstat = 0 ; - *pid = wait(&wstat) ; - if (*pid == -1) - { - if (errno != ECHILD) strerr_diefu1sys(111, "wait") ; - else return -1 ; - } - return wait_estatus(wstat) ; -} + pid_t *pids ; + size_t n ; + pid_t last ; + int lastwstat ; +} ; -static int wait_one_from_list (pid_t *pids, unsigned int n, pid_t *pid) +static inline pid_t wait_hang_nolist_all (int *wstat) { + pid_t pid = -1 ; + int w ; for (;;) { - int wstat ; - pid_t r = wait(&wstat) ; - unsigned int i = 0 ; - if (r == -1) - { - if (errno != ECHILD) strerr_diefu1sys(111, "wait") ; - else return -1 ; - } - for (; i < n ; i++) if (r == pids[i]) break ; - if (i < n) - { - *pid = r ; - pids[i] = pids[n-1] ; - return wait_estatus(wstat) ; - } + pid_t r = wait_nointr(&w) ; + if (r == -1) break ; + pid = r ; } + if (errno != ECHILD) strerr_diefusys(111, "wait") ; + if (pid > 0) *wstat = w ; + return pid ; } -static int wait_one_nohang (pid_t *pids, unsigned int *n, int *wstat) +static pid_t wait_nohang_nolist_one (void *data, int *wstat) { pid_t r = wait_nohang(wstat) ; - if (r == -1 && errno != ECHILD) strerr_diefu1sys(111, "wait") ; - (void)pids ; - (void)n ; + if (r == -1 && errno != ECHILD) + strerr_diefusys(111, "wait_nohang") ; + (void)data ; return r ; } -static int wait_one_from_list_nohang (pid_t *pids, unsigned int *n, int *wstat) +static pid_t wait_nohang_nolist_all (void *data, int *wstat) { + pid_t *last = data ; for (;;) { pid_t r = wait_nohang(wstat) ; - unsigned int i = 0 ; - if (r <= 0) + if (r == -1) break ; + else if (!r) return 0 ; + else *last = r ; + } + if (errno != ECHILD) strerr_diefusys(111, "wait_nohang") ; + return *last ; +} + +static pid_t wait_nohang_list_one (void *data, int *wstat) +{ + struct wait_pidlist_s *p = data ; + while (p->n) + { + size_t i ; + int r = waitpids_nohang(p->pids, p->n, wstat, &i) ; + if (!r) return 0 ; + else if (r == -1) + { + char fmt[PID_FMT] ; + fmt[pid_fmt(fmt, p->pids[i])] = 0 ; + if (errno != ECHILD) strerr_diefusys(111, "wait for pid", fmt) ; + strerr_warnwusys("wait for pid ", fmt) ; + p->pids[i] = p->pids[--p->n] ; + } + else return p->pids[i] ; + } + return -1 ; +} + +static pid_t wait_nohang_list_all (void *data, int *wstat) +{ + struct wait_pidlist_s *p = data ; + while (p->n) + { + size_t i ; + int w ; + int r = waitpids_nohang(p->pids, p->n, &w, &i) ; + if (!r) return 0 ; + else if (r == -1) { - if (r == -1 && errno != ECHILD) strerr_diefu1sys(111, "wait") ; - else return r ; + char fmt[PID_FMT] ; + fmt[pid_fmt(fmt, p->pids[i])] = 0 ; + if (errno != ECHILD) strerr_diefusys(111, "wait for pid ", fmt) ; + else strerr_warnwusys("wait for pid ", fmt) ; } - for (; i < *n ; i++) if (r == pids[i]) break ; - if (i < *n) + if (p->pids[i] == p->last) { - pids[i] = pids[--*n] ; - return r ; + if (r == -1) p->last = 0 ; + else p->lastwstat = w ; } + p->pids[i] = p->pids[--p->n] ; } + *wstat = p->lastwstat ; + return p->last ; } -static inline void empty_selfpipe (void) +static inline void wait_empty_selfpipe (void) { for (;;) switch (selfpipe_read()) { case -1 : strerr_diefu1sys(111, "read selfpipe") ; case 0 : return ; case SIGCHLD : break ; - default: strerr_dief1x(101, "internal inconsistency. Please submit a bug-report.") ; + default: strerr_dief(101, "internal inconsistency. Please submit a bug-report.") ; } } -static int wait_with_timeout (pid_t *pids, unsigned int n, pid_t *returned, ac_func_ref f, tain *tto, int justone, int strict) +static pid_t wait_with_timeout (wait_ac_func_ref f, void *data, int *wstat, tain *tto) { + pid_t pid ; iopause_fd x = { .fd = selfpipe_init(), .events = IOPAUSE_READ } ; - pid_t special = pids[n-1] ; - int e = special ? -1 : 0 ; - if (x.fd == -1) strerr_diefu1sys(111, "create selfpipe") ; - if (!selfpipe_trap(SIGCHLD)) strerr_diefu1sys(111, "trap SIGCHLD") ; + if (x.fd == -1) strerr_diefusys(111, "create selfpipe") ; + if (!selfpipe_trap(SIGCHLD)) strerr_diefusys(111, "trap SIGCHLD") ; tain_now_set_stopwatch_g() ; tain_add_g(tto, tto) ; + for (;;) { int r ; - for (;;) - { - int wstat ; - pid_t pid = (*f)(pids, &n, &wstat) ; - if (!pid) break ; - if (pid < 0) goto endloop ; - if (justone || pid == special) - { - *returned = pid ; - e = wait_estatus(wstat) ; - } - if (justone || !n) goto endloop ; - } + pid = (*f)(data, wstat) ; + if (pid) break ; r = iopause_g(&x, 1, tto) ; - if (r == -1) strerr_diefu1sys(111, "iopause") ; + if (r == -1) strerr_diefusys(111, "iopause") ; else if (!r) { - if (!strict) { e = -1 ; break ; } - errno = ETIMEDOUT ; - strerr_diefu1sys(99, "wait") ; + pid = -1 ; + break ; } - else empty_selfpipe() ; + else wait_empty_selfpipe() ; } - endloop: + selfpipe_finish() ; - return e ; + return pid ; } -enum wait_golb_e -{ - WAIT_GOLB_INSIST = 0x01, - WAIT_GOLB_JUSTONE = 0x02, - WAIT_GOLB_REAP = 0x04, -} ; - -enum wait_gola_e -{ - WAIT_GOLA_TIMEOUT, - WAIT_GOLA_N -} ; - int main (int argc, char const **argv) { static gol_bool const rgolb[] = { - { .so = 'I', .lo = "no-insist", .clear = WAIT_GOLB_INSIST, .set = 0 }, - { .so = 'i', .lo = "insist", .clear = 0, .set = WAIT_GOLB_INSIST }, { .so = 'a', .lo = "all", .clear = WAIT_GOLB_JUSTONE, .set = 0 }, { .so = 'o', .lo = "one", .clear = 0, .set = WAIT_GOLB_JUSTONE }, - { .so = 'r', .lo = "reap", .clear = 0, .set = WAIT_GOLB_REAP }, + { .so = 0, .lo = "export", .clear = WAIT_GOLB_NOEXPORT, .set = 0 }, + { .so = 'u', .lo = "no-export", .clear = 0, .set = WAIT_GOLB_NOEXPORT }, } ; static gol_arg const rgola[] = { @@ -180,17 +180,18 @@ int main (int argc, char const **argv) } ; tain tto = TAIN_INFINITE_RELATIVE ; int argc1 ; - int hasblock = 1 ; - int e ; + int posixcompat = 0 ; + pid_t pid ; + int wstat ; uint64_t wgolb = 0 ; char const *wgola[WAIT_GOLA_N] = { 0 } ; - unsigned int golc ; - pid_t pid = -1 ; PROG = "wait" ; - golc = GOL_main(argc, argv, rgolb, rgola, &wgolb, wgola) ; - argc -= golc ; argv += golc ; - if (wgolb & WAIT_GOLB_REAP) wgola[WAIT_GOLA_TIMEOUT] = "0" ; + { + unsigned int golc = GOL_main(argc, argv, rgolb, rgola, &wgolb, wgola) ; + argc -= golc ; argv += golc ; + } + if (wgola[WAIT_GOLA_TIMEOUT]) { unsigned int t = 0 ; @@ -201,41 +202,37 @@ int main (int argc, char const **argv) argc1 = el_semicolon_nostrict(argv) ; if (argc1 > argc) { - hasblock = 0 ; + posixcompat = 1 ; argc1 = argc ; } + if (argc1) { - unsigned int n = argc1 ? argc1 : 1 ; - pid_t pids[n] ; - if (argc1) - { - unsigned int i = 0 ; - for (; i < n ; i++) - if (!pid0_scan(argv[i], pids + i)) strerr_dieusage(100, USAGE) ; - } - else pids[0] = 0 ; - - e = wgola[WAIT_GOLA_TIMEOUT] ? /* wait -t30000 whatever */ - wait_with_timeout(pids, n, &pid, argc1 ? &wait_one_from_list_nohang : &wait_one_nohang, &tto, !!(wgolb & WAIT_GOLB_JUSTONE), !!(wgolb & WAIT_GOLB_INSIST)) : - wgolb & WAIT_GOLB_JUSTONE ? - argc1 ? - wait_one_from_list(pids, n, &pid) : /* wait -o -- 2 3 4 / wait -o -- { 2 3 4 } */ - wait_one(&pid) : /* wait -o / wait -o { } */ - argc1 ? - wait_from_list(pids, n) : /* wait 2 3 4 / wait { 2 3 4 }*/ - wait_all() ; /* wait / wait { } */ + pid_t pids[argc1] ; + struct wait_pidlist_s info = { .pids = pids, .n = argc1 } ; + for (unsigned int i = 0 ; i < argc1 ; i++) + if (!pid0_scan(argv[i], pids + i)) + strerr_dief(100, "pids must be numerical") ; + info.last = pids[argc1 - 1] ; + pid = wait_with_timeout(wgolb & WAIT_GOLB_JUSTONE ? &wait_nohang_list_one : &wait_nohang_list_all, &info, &wstat, &tto) ; } - if (!hasblock) _exit(e >= 0 ? e : 127) ; - if (!(wgolb & WAIT_GOLB_JUSTONE)) xexec0(argv + argc1 + 1) ; - if (e == -1) xmexec0_n(argv + argc1 + 1, "?\0!", 4, 2) ; + else if (wgola[WAIT_GOLA_TIMEOUT]) + { + pid_t saved = -1 ; + pid = wait_with_timeout(wgolb & WAIT_GOLB_JUSTONE ? &wait_nohang_nolist_one : &wait_nohang_nolist_all, &saved, &wstat, &tto) ; + } + else pid = wgolb & WAIT_GOLB_JUSTONE ? wait_nointr(&wstat) : wait_hang_nolist_all(&wstat) ; + + if (posixcompat) _exit(pid == -1 ? 1 : argc1 ? wait_estatus(wstat) : 0) ; + if (pid > 0 && !(wgolb & WAIT_GOLB_NOEXPORT)) { char fmt[4 + UINT_FMT + PID_FMT] = "?=" ; size_t m = 2 ; - m += uint_fmt(fmt + m, (unsigned int)e) ; fmt[m++] = 0 ; + m += uint_fmt(fmt + m, wait_estatus(wstat)) ; fmt[m++] = 0 ; fmt[m++] = '!' ; fmt[m++] = '=' ; m += pid_fmt(fmt + m, pid) ; fmt[m++] = 0 ; xmexec0_n(argv + argc1 + 1, fmt, m, 2) ; } + else xmexec0_n(argv + argc1 + 1, "?\0!", 4, 2) ; } |
