tests: verify live daemon cleanup
This commit is contained in:
@@ -51,7 +51,8 @@ struct Siglog
|
||||
int invalid;
|
||||
int npreedit;
|
||||
int ncommit;
|
||||
char path[96];
|
||||
char preeditpath[96];
|
||||
char commitpath[96];
|
||||
char preedit[256];
|
||||
char commit[256];
|
||||
dbus_uint32_t cursor;
|
||||
@@ -279,12 +280,15 @@ startdaemon(Daemon *d, char *program, char *mapdir)
|
||||
dup2(errpipe[1], STDERR_FILENO) < 0)
|
||||
_exit(126);
|
||||
close(errpipe[1]);
|
||||
setenv("XDG_RUNTIME_DIR", d->runtime, 1);
|
||||
setenv("XDG_CONFIG_HOME", d->config, 1);
|
||||
setenv("HOME", d->home, 1);
|
||||
unsetenv("DISPLAY");
|
||||
unsetenv("DBUS_SESSION_BUS_ADDRESS");
|
||||
unsetenv("IBUS_ADDRESS");
|
||||
if(setenv("XDG_RUNTIME_DIR", d->runtime, 1) < 0 ||
|
||||
setenv("XDG_CONFIG_HOME", d->config, 1) < 0 ||
|
||||
setenv("HOME", d->home, 1) < 0 || unsetenv("DISPLAY") < 0 ||
|
||||
unsetenv("DBUS_SESSION_BUS_ADDRESS") < 0 ||
|
||||
unsetenv("IBUS_ADDRESS") < 0){
|
||||
dprintf(STDERR_FILENO, "set daemon environment: %s\n",
|
||||
strerror(errno));
|
||||
_exit(126);
|
||||
}
|
||||
execl(program, program, mapdir, missing, (char*)0);
|
||||
dprintf(STDERR_FILENO, "exec %s: %s\n", program, strerror(errno));
|
||||
_exit(127);
|
||||
@@ -350,36 +354,82 @@ rmdirknown(char *path)
|
||||
return fail("rmdir %s: %s", path, strerror(errno));
|
||||
}
|
||||
|
||||
static int
|
||||
killdaemon(Daemon *d, int *status)
|
||||
{
|
||||
int n, ok;
|
||||
|
||||
ok = 1;
|
||||
if(kill(d->pid, SIGKILL) < 0 && errno != ESRCH){
|
||||
fail("kill -9 %ld: %s", (long)d->pid, strerror(errno));
|
||||
ok = 0;
|
||||
}
|
||||
do
|
||||
n = waitpid(d->pid, status, 0);
|
||||
while(n < 0 && errno == EINTR);
|
||||
if(n != d->pid){
|
||||
fail("reap %ld after SIGKILL: %s", (long)d->pid,
|
||||
n < 0 ? strerror(errno) : "wrong child");
|
||||
ok = 0;
|
||||
}else
|
||||
d->pid = -1;
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int
|
||||
stopdaemon(Daemon *d)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
int ok, status, n;
|
||||
int ok, status, n, reaped;
|
||||
int64_t deadline;
|
||||
|
||||
ok = 1;
|
||||
if(d->pid > 0){
|
||||
if(kill(d->pid, SIGTERM) < 0 && errno != ESRCH){
|
||||
do
|
||||
n = waitpid(d->pid, &status, WNOHANG);
|
||||
while(n < 0 && errno == EINTR);
|
||||
if(n == d->pid){
|
||||
fail("daemon exited before test termination with wait status %#x",
|
||||
status);
|
||||
d->pid = -1;
|
||||
ok = 0;
|
||||
}else if(n < 0){
|
||||
fail("check daemon %ld before termination: %s",
|
||||
(long)d->pid, strerror(errno));
|
||||
if(errno == ECHILD)
|
||||
d->pid = -1;
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
if(d->pid > 0){
|
||||
if(kill(d->pid, SIGTERM) < 0){
|
||||
fail("kill %ld: %s", (long)d->pid, strerror(errno));
|
||||
ok = 0;
|
||||
}
|
||||
reaped = 0;
|
||||
deadline = nowms() + Stoptimeout;
|
||||
for(;;){
|
||||
n = waitpid(d->pid, &status, WNOHANG);
|
||||
if(n == d->pid)
|
||||
if(n == d->pid){
|
||||
reaped = 1;
|
||||
d->pid = -1;
|
||||
break;
|
||||
if(n < 0 && errno != EINTR){
|
||||
}
|
||||
if(n < 0 && errno == EINTR)
|
||||
continue;
|
||||
if(n < 0){
|
||||
fail("waitpid %ld: %s", (long)d->pid, strerror(errno));
|
||||
ok = 0;
|
||||
if(errno == ECHILD)
|
||||
d->pid = -1;
|
||||
break;
|
||||
}
|
||||
n = leftms(deadline);
|
||||
if(n == 0){
|
||||
fail("daemon %ld did not stop after SIGTERM", (long)d->pid);
|
||||
ok = 0;
|
||||
kill(d->pid, SIGKILL);
|
||||
while(waitpid(d->pid, &status, 0) < 0 && errno == EINTR)
|
||||
;
|
||||
if(!killdaemon(d, &status))
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
pfd.fd = d->errfd;
|
||||
@@ -388,14 +438,19 @@ stopdaemon(Daemon *d)
|
||||
if(poll(&pfd, 1, n) < 0 && errno != EINTR){
|
||||
fail("poll daemon %ld: %s", (long)d->pid, strerror(errno));
|
||||
ok = 0;
|
||||
kill(d->pid, SIGKILL);
|
||||
while(waitpid(d->pid, &status, 0) < 0 && errno == EINTR)
|
||||
;
|
||||
if(!killdaemon(d, &status))
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
readerrors(d);
|
||||
}
|
||||
d->pid = -1;
|
||||
/* plan9port turns a caught termination note into exit status 1. */
|
||||
if(reaped &&
|
||||
!((WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM) ||
|
||||
(WIFEXITED(status) && WEXITSTATUS(status) == 1))){
|
||||
fail("daemon exited with unexpected wait status %#x", status);
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
readerrors(d);
|
||||
if(d->errfd >= 0){
|
||||
@@ -490,15 +545,13 @@ onsignal(DBusConnection *conn, DBusMessage *m, void *arg)
|
||||
if(dbus_message_get_type(m) != DBUS_MESSAGE_TYPE_SIGNAL ||
|
||||
!dbus_message_has_interface(m, "org.freedesktop.IBus.InputContext"))
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
path = dbus_message_get_path(m);
|
||||
if(path == NULL || snprintf(log->path, sizeof log->path, "%s", path)
|
||||
>= (int)sizeof log->path){
|
||||
log->invalid = 1;
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
if(dbus_message_has_member(m, "UpdatePreeditText")){
|
||||
log->npreedit++;
|
||||
if(!dbus_message_has_signature(m, "vub") ||
|
||||
path = dbus_message_get_path(m);
|
||||
if(path == NULL || snprintf(log->preeditpath,
|
||||
sizeof log->preeditpath, "%s", path) >=
|
||||
(int)sizeof log->preeditpath ||
|
||||
!dbus_message_has_signature(m, "vub") ||
|
||||
!dbus_message_iter_init(m, &it) ||
|
||||
!ibustext(&it, log->preedit, sizeof log->preedit) ||
|
||||
!dbus_message_iter_next(&it) ||
|
||||
@@ -519,7 +572,11 @@ onsignal(DBusConnection *conn, DBusMessage *m, void *arg)
|
||||
}
|
||||
if(dbus_message_has_member(m, "CommitText")){
|
||||
log->ncommit++;
|
||||
if(!dbus_message_has_signature(m, "v") ||
|
||||
path = dbus_message_get_path(m);
|
||||
if(path == NULL || snprintf(log->commitpath,
|
||||
sizeof log->commitpath, "%s", path) >=
|
||||
(int)sizeof log->commitpath ||
|
||||
!dbus_message_has_signature(m, "v") ||
|
||||
!dbus_message_iter_init(m, &it) ||
|
||||
!ibustext(&it, log->commit, sizeof log->commit) ||
|
||||
dbus_message_iter_next(&it))
|
||||
@@ -834,10 +891,11 @@ preedit(Siglog *log, char *path, char *text, unsigned int cursor, int visible,
|
||||
char *where)
|
||||
{
|
||||
if(log->invalid || log->npreedit != 1 || log->ncommit != 0 ||
|
||||
strcmp(log->path, path) != 0 || strcmp(log->preedit, text) != 0 ||
|
||||
strcmp(log->preeditpath, path) != 0 ||
|
||||
strcmp(log->preedit, text) != 0 ||
|
||||
log->cursor != cursor || (log->visible != FALSE) != (visible != 0))
|
||||
return fail("%s preedit: count=%d commit=%d path=%s text=%s cursor=%u visible=%d",
|
||||
where, log->npreedit, log->ncommit, log->path, log->preedit,
|
||||
where, log->npreedit, log->ncommit, log->preeditpath, log->preedit,
|
||||
(unsigned)log->cursor, log->visible != FALSE);
|
||||
return 1;
|
||||
}
|
||||
@@ -846,7 +904,9 @@ static int
|
||||
committed(Siglog *log, char *path, char *text, char *where)
|
||||
{
|
||||
if(log->invalid || log->npreedit != 1 || log->ncommit != 1 ||
|
||||
strcmp(log->path, path) != 0 || strcmp(log->commit, text) != 0 ||
|
||||
strcmp(log->preeditpath, path) != 0 ||
|
||||
strcmp(log->commitpath, path) != 0 ||
|
||||
strcmp(log->commit, text) != 0 ||
|
||||
strcmp(log->preedit, "") != 0 || log->cursor != 0 ||
|
||||
log->visible != FALSE)
|
||||
return fail("%s signals: preedit=%d commit=%d text=%s/%s",
|
||||
|
||||
@@ -228,12 +228,15 @@ startdaemon(Daemon *d, char *program, char *mapdir)
|
||||
dup2(errpipe[1], STDERR_FILENO) < 0)
|
||||
_exit(126);
|
||||
close(errpipe[1]);
|
||||
setenv("XDG_RUNTIME_DIR", d->runtime, 1);
|
||||
setenv("XDG_CONFIG_HOME", d->config, 1);
|
||||
setenv("HOME", d->home, 1);
|
||||
unsetenv("DISPLAY");
|
||||
unsetenv("DBUS_SESSION_BUS_ADDRESS");
|
||||
unsetenv("IBUS_ADDRESS");
|
||||
if(setenv("XDG_RUNTIME_DIR", d->runtime, 1) < 0 ||
|
||||
setenv("XDG_CONFIG_HOME", d->config, 1) < 0 ||
|
||||
setenv("HOME", d->home, 1) < 0 || unsetenv("DISPLAY") < 0 ||
|
||||
unsetenv("DBUS_SESSION_BUS_ADDRESS") < 0 ||
|
||||
unsetenv("IBUS_ADDRESS") < 0){
|
||||
dprintf(STDERR_FILENO, "set daemon environment: %s\n",
|
||||
strerror(errno));
|
||||
_exit(126);
|
||||
}
|
||||
execl(program, program, mapdir, missing, (char*)0);
|
||||
dprintf(STDERR_FILENO, "exec %s: %s\n", program, strerror(errno));
|
||||
_exit(127);
|
||||
@@ -297,36 +300,82 @@ rmdirknown(char *path)
|
||||
return fail("rmdir %s: %s", path, strerror(errno));
|
||||
}
|
||||
|
||||
static int
|
||||
killdaemon(Daemon *d, int *status)
|
||||
{
|
||||
int n, ok;
|
||||
|
||||
ok = 1;
|
||||
if(kill(d->pid, SIGKILL) < 0 && errno != ESRCH){
|
||||
fail("kill -9 %ld: %s", (long)d->pid, strerror(errno));
|
||||
ok = 0;
|
||||
}
|
||||
do
|
||||
n = waitpid(d->pid, status, 0);
|
||||
while(n < 0 && errno == EINTR);
|
||||
if(n != d->pid){
|
||||
fail("reap %ld after SIGKILL: %s", (long)d->pid,
|
||||
n < 0 ? strerror(errno) : "wrong child");
|
||||
ok = 0;
|
||||
}else
|
||||
d->pid = -1;
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int
|
||||
stopdaemon(Daemon *d)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
int ok, status, n;
|
||||
int ok, status, n, reaped;
|
||||
int64_t deadline;
|
||||
|
||||
ok = 1;
|
||||
if(d->pid > 0){
|
||||
if(kill(d->pid, SIGTERM) < 0 && errno != ESRCH){
|
||||
do
|
||||
n = waitpid(d->pid, &status, WNOHANG);
|
||||
while(n < 0 && errno == EINTR);
|
||||
if(n == d->pid){
|
||||
fail("daemon exited before test termination with wait status %#x",
|
||||
status);
|
||||
d->pid = -1;
|
||||
ok = 0;
|
||||
}else if(n < 0){
|
||||
fail("check daemon %ld before termination: %s",
|
||||
(long)d->pid, strerror(errno));
|
||||
if(errno == ECHILD)
|
||||
d->pid = -1;
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
if(d->pid > 0){
|
||||
if(kill(d->pid, SIGTERM) < 0){
|
||||
fail("kill %ld: %s", (long)d->pid, strerror(errno));
|
||||
ok = 0;
|
||||
}
|
||||
reaped = 0;
|
||||
deadline = nowms() + Stoptimeout;
|
||||
for(;;){
|
||||
n = waitpid(d->pid, &status, WNOHANG);
|
||||
if(n == d->pid)
|
||||
if(n == d->pid){
|
||||
reaped = 1;
|
||||
d->pid = -1;
|
||||
break;
|
||||
if(n < 0 && errno != EINTR){
|
||||
}
|
||||
if(n < 0 && errno == EINTR)
|
||||
continue;
|
||||
if(n < 0){
|
||||
fail("waitpid %ld: %s", (long)d->pid, strerror(errno));
|
||||
ok = 0;
|
||||
if(errno == ECHILD)
|
||||
d->pid = -1;
|
||||
break;
|
||||
}
|
||||
n = leftms(deadline);
|
||||
if(n == 0){
|
||||
fail("daemon %ld did not stop after SIGTERM", (long)d->pid);
|
||||
ok = 0;
|
||||
kill(d->pid, SIGKILL);
|
||||
while(waitpid(d->pid, &status, 0) < 0 && errno == EINTR)
|
||||
;
|
||||
if(!killdaemon(d, &status))
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
pfd.fd = d->errfd;
|
||||
@@ -335,14 +384,19 @@ stopdaemon(Daemon *d)
|
||||
if(poll(&pfd, 1, n) < 0 && errno != EINTR){
|
||||
fail("poll daemon %ld: %s", (long)d->pid, strerror(errno));
|
||||
ok = 0;
|
||||
kill(d->pid, SIGKILL);
|
||||
while(waitpid(d->pid, &status, 0) < 0 && errno == EINTR)
|
||||
;
|
||||
if(!killdaemon(d, &status))
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
readerrors(d);
|
||||
}
|
||||
d->pid = -1;
|
||||
/* plan9port turns a caught termination note into exit status 1. */
|
||||
if(reaped &&
|
||||
!((WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM) ||
|
||||
(WIFEXITED(status) && WEXITSTATUS(status) == 1))){
|
||||
fail("daemon exited with unexpected wait status %#x", status);
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
readerrors(d);
|
||||
if(d->errfd >= 0){
|
||||
|
||||
Reference in New Issue
Block a user