On Fri, 25 Oct 2019, Thorsten Glaser wrote:
> Using qemu-user-static in an m68k chroot:
>
> # ./mksh -c '/bin/echo foo; echo bar'
> foo
> ^C^\
>
> (it just hangs here, with qemu-user-static:i386; on the
This is really hard to debug, as neither strace nor gdb work under
qemu-user-static, and the broken FPU emulation means I also cannot
attach gdb-multiarch to qemu-user-static (FPU size 96 not supported,
gdbserver packet size mismatches).
I _believe_ SIGCHLD is never delivered. write(2)-to-stderr debugging
shows that it loops “forever” in jobs.c:j_waitj() in this loop:
while (j->state == PRUNNING ||
((flags & JW_STOPPEDWAIT) && j->state == PSTOPPED)) {
sigsuspend(&sm_default);
if (fatal_trap) // no, else is taken
if ((flags & JW_INTERRUPT) && (rv = trap_pending())) // no,
else is taken
}
j->state is supposed to be changed by the SIGCHLD handler,
namely j_sigchld() in jobs.c, but it is never called.
I was not able to reproduce this in an MWE: all attempts still work
(I’m attaching it, in case someone else can make more sense out of it);
compiling it exactly the same as mksh with (the -D* are ignored, but
this is literally taking the mksh compile command line and changing
the filenames):
klcc -O2 -fno-lto -Wno-deprecated-declarations
-fno-asynchronous-unwind-tables -fno-strict-aliasing -Wall -fwrapv -I.
-I'../mksh' -DMKSH_BUILDSH -D_GNU_SOURCE -DSETUID_CAN_FAIL_WITH_EAGAIN
-DMKSH_NO_LIMITS -DHAVE_STRING_POOLING=2 -DHAVE_ATTRIBUTE_BOUNDED=0
-DHAVE_ATTRIBUTE_FORMAT=1 -DHAVE_ATTRIBUTE_NORETURN=1 -DHAVE_ATTRIBUTE_PURE=1
-DHAVE_ATTRIBUTE_UNUSED=1 -DHAVE_ATTRIBUTE_USED=1 -DHAVE_SYS_TIME_H=1
-DHAVE_TIME_H=1 -DHAVE_BOTH_TIME_H=0 -DHAVE_SYS_BSDTYPES_H=0
-DHAVE_SYS_FILE_H=1 -DHAVE_SYS_MKDEV_H=0 -DHAVE_SYS_MMAN_H=1
-DHAVE_SYS_PARAM_H=1 -DHAVE_SYS_RESOURCE_H=1 -DHAVE_SYS_SELECT_H=1
-DHAVE_SYS_SYSMACROS_H=1 -DHAVE_BSTRING_H=0 -DHAVE_GRP_H=1 -DHAVE_IO_H=0
-DHAVE_LIBGEN_H=0 -DHAVE_LIBUTIL_H=0 -DHAVE_PATHS_H=1 -DHAVE_STDINT_H=1
-DHAVE_STRINGS_H=0 -DHAVE_TERMIOS_H=1 -DHAVE_ULIMIT_H=0 -DHAVE_VALUES_H=0
-DHAVE_CAN_INTTYPES=1 -DHAVE_CAN_UCBINTS=1 -DHAVE_CAN_INT8TYPE=1
-DHAVE_CAN_UCBINT8=1 -DHAVE_RLIM_T=0 -Dsig_t=__sighandler_t -DHAVE_SIG_T=1
-DHAVE_SYS_ERRLIST=1 -DHAVE_SYS_SIGNAME=0 -DHAVE_SYS_SIGLIST=1 -DHAVE_FLOCK=1
-DHAVE_LOCK_FCNTL=1 -DHAVE_GETRUSAGE=1 -DHAVE_GETSID=1 -DHAVE_GETTIMEOFDAY=1
-DHAVE_KILLPG=0 -DHAVE_MEMMOVE=1 -DHAVE_MKNOD=0 -DHAVE_MMAP=1
-DHAVE_FTRUNCATE=1 -DHAVE_NICE=1 -DHAVE_REVOKE=0 -DHAVE_SETLOCALE_CTYPE=0
-DHAVE_LANGINFO_CODESET=0 -DHAVE_SELECT=1 -DHAVE_SETRESUGID=0
-DHAVE_SETGROUPS=0 -DHAVE_STRERROR=0 -DHAVE_STRSIGNAL=0 -DHAVE_STRLCPY=1
-DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 -DHAVE_SYS_ERRLIST_DECL=0
-DHAVE_SYS_SIGLIST_DECL=1 -DHAVE_PERSISTENT_HISTORY=1 -DMKSH_BUILD_R=571 -c t.c
klcc -O2 -fno-lto -Wno-deprecated-declarations
-fno-asynchronous-unwind-tables -fno-strict-aliasing -Wall -fwrapv -static
-fno-lto -o t t.o
bye,
//mirabilos
--
tarent solutions GmbH
Rochusstraße 2-4, D-53123 Bonn • http://www.tarent.de/
Tel: +49 228 54881-393 • Fax: +49 228 54881-235
HRB 5168 (AG Bonn) • USt-ID (VAT): DE122264941
Geschäftsführer: Dr. Stefan Barth, Kai Ebenrett, Boris Esser, Alexander Steeg
**********
Mit der tarent Academy bieten wir auch Trainings und Schulungen in den
Bereichen Softwareentwicklung, Agiles Arbeiten und Zukunftstechnologien an.
Besuchen Sie uns auf www.tarent.de/academy. Wir freuen uns auf Ihren Kontakt.
**********
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
static void handler(int);
static sigset_t sm_sigchld;
static sigset_t sm_default;
static volatile sig_atomic_t found = 0;
#define STKBUFSZ 80
static const char *stkbuf;
#define w(s) write(2, (s), strlen(s))
static void
handler(int signo)
{
int save_errno = errno;
struct rusage ru0;
sigset_t omask;
w("beg signal: <");
write(2, stkbuf, STKBUFSZ);
w(">\n");
sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
getrusage(RUSAGE_CHILDREN, &ru0);
found = 1;
sigprocmask(SIG_SETMASK, &omask, NULL);
w("end signal: <");
write(2, stkbuf, STKBUFSZ);
w(">\n");
errno = save_errno;
}
static struct sigaction sa;
static pid_t pid;
static char newarg0[] = "/bin/sleep";
static char newarg1[] = "1";
static char *newarg[] = { newarg0, newarg1, NULL };
int
main(int argc, char *argv[], char *envp[])
{
char buffer[STKBUFSZ];
memset(buffer, 'b', STKBUFSZ);
buffer[0] = 'a';
buffer[STKBUFSZ - 1] = 'c';
stkbuf = buffer;
(void)sigemptyset(&sm_default);
sigprocmask(SIG_SETMASK, &sm_default, NULL);
(void)sigemptyset(&sm_sigchld);
(void)sigaddset(&sm_sigchld, SIGCHLD);
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
w("before cld: <");
write(2, stkbuf, STKBUFSZ);
w(">\n");
if ((pid = fork()) == -1) {
fprintf(stderr, "cannot fork: %s\n", strerror(errno));
return (1);
} else if (!pid) {
buffer[1] = 'd';
w("inside cld: {");
write(2, stkbuf, STKBUFSZ);
w("}\n");
execve(newarg0, newarg, envp);
fprintf(stderr, "cannot exec: %s\n", strerror(errno));
return (1);
}
w("before sig: <");
write(2, stkbuf, STKBUFSZ);
w(">\n");
if (sigaction(SIGCHLD, &sa, NULL)) {
fprintf(stderr, "cannot sigaction: %s\n", strerror(errno));
return (1);
}
while (!found) {
w("before sus: <");
write(2, stkbuf, STKBUFSZ);
w(">\n");
sigsuspend(&sm_default);
}
w(" after sus: <");
write(2, stkbuf, STKBUFSZ);
w(">\n");
errno = 0;
if ((pid = waitpid(-1, NULL, WUNTRACED)) == 0) {
fprintf(stderr, "wait would block: %s\n", strerror(errno));
return (1);
} else if (pid < 0) {
fprintf(stderr, "wait no children or interrupted: %s\n", strerror(errno));
return (1);
}
w("after wait: <");
write(2, stkbuf, STKBUFSZ);
w(">\n");
return (0);
}