aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Seebach <peter.seebach@windriver.com>2016-03-02 14:04:24 -0600
committerPeter Seebach <peter.seebach@windriver.com>2016-03-02 14:07:46 -0600
commit529f667d444a15aabaa80a9412f27559ddc6408b (patch)
treed5af61dda5b5d244d436d62876ecffff57940bb4
parent77ee254a6c974aad9bcab2c58c9ee9e0880c9718 (diff)
downloadpseudo-529f667d444a15aabaa80a9412f27559ddc6408b.tar.gz
pseudo-529f667d444a15aabaa80a9412f27559ddc6408b.tar.bz2
pseudo-529f667d444a15aabaa80a9412f27559ddc6408b.zip
Server launch rework continued, probably finished
Server process now waits for its forked child when daemonizing, allowing us to yield meaningful exit status. Lock is now taken by the child, since it has a way to tell the parent about the exit status. (We send SIGUSR1 to the server to cause the wait loop to stop when the client is ready to go.) This allows us to switch to fcntl locking, which should in theory allow us to run with the pseudo directory NFS-mounted. Woot! Also mark a couple of overly spammy messages as PDBGF_VERBOSE to reduce the volume of uninteresting dup spam when looking at client behaviors. Client now uses execve to spawn server to work around a very strange behavior of unsetenv. Signed-off-by: Peter Seebach <peter.seebach@windriver.com>
-rw-r--r--ChangeLog.txt4
-rw-r--r--enums/exit_status.in4
-rw-r--r--ports/common/guts/execv.c4
-rw-r--r--ports/unix/guts/dup.c2
-rw-r--r--ports/unix/guts/dup2.c2
-rw-r--r--pseudo.c12
-rw-r--r--pseudo_client.c33
-rw-r--r--pseudo_server.c20
-rw-r--r--pseudo_util.c8
9 files changed, 54 insertions, 35 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt
index 6031496..6cd3997 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -1,3 +1,7 @@
+2016-03-02:
+ * (seebs) more server launch rework and updates
+ * (seebs) make dup/dup2 less verbose in client
+
2016-03-01:
* (seebs) server launch reworking
diff --git a/enums/exit_status.in b/enums/exit_status.in
index e02b1bc..6be44d3 100644
--- a/enums/exit_status.in
+++ b/enums/exit_status.in
@@ -14,3 +14,7 @@ socket_path, "path allocation failure for server socket"
socket_unlink, "couldn't unlink existing server socket"
socket_bind, "couldn't bind server socket"
socket_listen, "couldn't listen on server socket"
+listen_fd, "server loop had no valid listen fd"
+pseudo_loaded, "server couldn't get out of pseudo environment"
+pseudo_prefix, "couldn't get valid pseudo prefix"
+pseudo_invocation, "invalid server command arguments"
diff --git a/ports/common/guts/execv.c b/ports/common/guts/execv.c
index ba1ce65..6093e44 100644
--- a/ports/common/guts/execv.c
+++ b/ports/common/guts/execv.c
@@ -18,9 +18,9 @@
}
pseudo_setupenv();
- if (pseudo_has_unload(NULL))
+ if (pseudo_has_unload(NULL)) {
pseudo_dropenv();
-
+ }
/* if exec() fails, we may end up taking signals unexpectedly...
* not much we can do about that.
*/
diff --git a/ports/unix/guts/dup.c b/ports/unix/guts/dup.c
index f03c2ad..927b264 100644
--- a/ports/unix/guts/dup.c
+++ b/ports/unix/guts/dup.c
@@ -10,7 +10,7 @@
rc = real_dup(fd);
save_errno = errno;
- pseudo_debug(PDBGF_CLIENT, "dup: %d->%d\n", fd, rc);
+ pseudo_debug(PDBGF_CLIENT | PDBGF_VERBOSE, "dup: %d->%d\n", fd, rc);
pseudo_client_op(OP_DUP, 0, fd, rc, 0, 0);
errno = save_errno;
diff --git a/ports/unix/guts/dup2.c b/ports/unix/guts/dup2.c
index cd335ac..8180039 100644
--- a/ports/unix/guts/dup2.c
+++ b/ports/unix/guts/dup2.c
@@ -10,7 +10,7 @@
/* close existing one first - this also causes the socket to the
* server to get moved around if someone tries to overwrite it. */
- pseudo_debug(PDBGF_CLIENT, "dup2: %d->%d\n", oldfd, newfd);
+ pseudo_debug(PDBGF_CLIENT | PDBGF_VERBOSE, "dup2: %d->%d\n", oldfd, newfd);
pseudo_client_op(OP_CLOSE, 0, newfd, -1, 0, 0);
rc = real_dup2(oldfd, newfd);
save_errno = errno;
diff --git a/pseudo.c b/pseudo.c
index d1f35c3..2b60fd4 100644
--- a/pseudo.c
+++ b/pseudo.c
@@ -113,12 +113,12 @@ main(int argc, char *argv[]) {
sigprocmask(SIG_UNBLOCK, &blocked, &saved);
if (ld_env && strstr(ld_env, "libpseudo")) {
- pseudo_debug(PDBGF_SERVER, "can't run daemon with libpseudo in %s\n", PRELINK_LIBRARIES);
+ pseudo_debug(PDBGF_SERVER, "[server %d] can't run daemon with libpseudo in %s\n", getpid(), PRELINK_LIBRARIES);
s = pseudo_get_value("PSEUDO_UNLOAD");
if (s) {
pseudo_diag("pseudo: I can't seem to make %s go away. Sorry.\n", PRELINK_LIBRARIES);
pseudo_diag("pseudo: %s: %s\n", PRELINK_LIBRARIES, ld_env);
- exit(EXIT_FAILURE);
+ exit(PSEUDO_EXIT_PSEUDO_LOADED);
}
free(s);
pseudo_set_value("PSEUDO_UNLOAD", "YES");
@@ -126,7 +126,7 @@ main(int argc, char *argv[]) {
pseudo_dropenv(); /* Drop PRELINK_LIBRARIES */
execv(argv[0], argv);
- exit(EXIT_FAILURE);
+ exit(PSEUDO_EXIT_PSEUDO_LOADED);
}
/* Be sure to clean PSEUDO_UNLOAD so if we're asked to run any
@@ -258,7 +258,7 @@ main(int argc, char *argv[]) {
if (!pseudo_get_prefix(argv[0])) {
pseudo_diag("Can't figure out prefix. Set PSEUDO_PREFIX or invoke with full path.\n");
- exit(EXIT_FAILURE);
+ exit(PSEUDO_EXIT_PSEUDO_PREFIX);
}
/* move database */
@@ -339,13 +339,13 @@ main(int argc, char *argv[]) {
if (opt_d && opt_f) {
pseudo_diag("You cannot run a foregrounded daemon.\n");
- exit(EXIT_FAILURE);
+ exit(PSEUDO_EXIT_PSEUDO_INVOCATION);
}
if (opt_f || opt_d) {
if (argc > optind) {
pseudo_diag("pseudo: running program implies spawning background daemon.\n");
- exit(EXIT_FAILURE);
+ exit(PSEUDO_EXIT_PSEUDO_INVOCATION);
}
} else {
char fullpath[pseudo_path_max()];
diff --git a/pseudo_client.c b/pseudo_client.c
index 4d73598..5eca70c 100644
--- a/pseudo_client.c
+++ b/pseudo_client.c
@@ -938,15 +938,8 @@ client_spawn_server(void) {
int status;
FILE *fp;
char * pseudo_pidfile;
- char *old_value = pseudo_get_value("PSEUDO_UNLOAD");
- /* drop pseudo immediately so the fork/exec are lower-load. */
- pseudo_set_value("PSEUDO_UNLOAD", "YES");
if ((server_pid = fork()) != 0) {
- /* restore PSEUDO_UNLOAD in caller */
- pseudo_set_value("PSEUDO_UNLOAD", old_value);
- free(old_value);
-
if (server_pid == -1) {
pseudo_diag("couldn't fork server: %s\n", strerror(errno));
return 1;
@@ -1039,14 +1032,23 @@ client_spawn_server(void) {
close(fd);
}
/* and now, execute the server */
-
- pseudo_set_value("PSEUDO_UNLOAD", "YES");
- pseudo_setupenv();
- pseudo_dropenv(); /* drop PRELINK_LIBRARIES */
-
pseudo_debug(PDBGF_CLIENT | PDBGF_SERVER | PDBGF_INVOKE, "calling execv on %s\n", argv[0]);
- execv(argv[0], argv);
+ /* don't try to log this exec, because it'll cause the process
+ * that is supposed to be spawning the server to try to spawn
+ * a server. Whoops. This is because the exec wrapper doesn't
+ * respect antimagic, which I believe is intentional.
+ */
+ pseudo_client_logging = 0;
+
+ /* execve will call setupenv, then call dropenv if
+ * PSEUDO_UNLOAD is set. We call execve, not execv, due
+ * to unsetenv changing the responses given by getenv,
+ * but not changing the contents of the variable environ,
+ * in some cases.
+ */
+ pseudo_set_value("PSEUDO_UNLOAD", "1");
+ execve(argv[0], argv, environ);
pseudo_diag("critical failure: exec of pseudo daemon failed: %s\n", strerror(errno));
exit(1);
}
@@ -1251,6 +1253,11 @@ pseudo_client_request(pseudo_msg_t *msg, size_t len, const char *path) {
pseudo_msg_t *response = 0;
int tries = 0;
int rc;
+ extern char *program_invocation_short_name;
+ #if 0
+ if (!strcmp(program_invocation_short_name, "pseudo"))
+ abort();
+ #endif
if (!msg)
return 0;
diff --git a/pseudo_server.c b/pseudo_server.c
index f6806f3..12159e7 100644
--- a/pseudo_server.c
+++ b/pseudo_server.c
@@ -133,14 +133,12 @@ static sig_atomic_t got_sigalrm = 0;
static void
handle_sigusr1(int sig) {
(void) sig;
- pseudo_diag("sigusr1\n");
got_sigusr1 = 1;
}
static void
handle_sigalrm(int sig) {
(void) sig;
- pseudo_diag("sigalrm\n");
got_sigalrm = 1;
}
@@ -157,7 +155,6 @@ pseudo_server_start(int daemonize) {
/* parent process will wait for child process, or until it gets
* SIGUSR1, or until too much time has passed. */
- pseudo_diag("server start: daemonize %d.\n", daemonize);
if (daemonize) {
int child;
child = fork();
@@ -170,7 +167,6 @@ pseudo_server_start(int daemonize) {
int status;
int rc;
int save_errno;
- pseudo_diag("parent process, pid %d, doing setup.\n", getpid());
got_sigusr1 = 0;
signal(SIGUSR1, handle_sigusr1);
@@ -181,20 +177,21 @@ pseudo_server_start(int daemonize) {
rc = waitpid(child, &status, WNOHANG);
save_errno = errno;
if (rc != child && !got_sigalrm && !got_sigusr1) {
- struct timespec delay = { .tv_sec = 0, .tv_nsec = 100000000 };
+ struct timespec delay = { .tv_sec = 0, .tv_nsec = 100000 };
nanosleep(&delay, NULL);
++tries;
}
} while (!got_sigalrm && !got_sigusr1 && rc != child);
alarm(0);
- pseudo_diag("pid waited: %d/%d [%d tries], status %d\n", rc, save_errno, tries, status);
- pseudo_diag("usr1: %d alrm: %d\n", got_sigusr1, got_sigalrm);
+ pseudo_debug(PDBGF_SERVER, "pid waited: %d/%d [%d tries], status %d, usr1 %d, alrm %d\n",
+ rc, save_errno, tries, status,
+ got_sigusr1, got_sigalrm);
if (got_sigusr1) {
pseudo_debug(PDBGF_SERVER, "server says it's ready.\n");
exit(0);
}
- if (save_errno == EINTR) {
+ if (got_sigalrm) {
pseudo_diag("Child process timeout after %d seconds.\n",
PSEUDO_CHILD_PROCESS_TIMEOUT);
exit(PSEUDO_EXIT_TIMEOUT);
@@ -217,10 +214,13 @@ pseudo_server_start(int daemonize) {
pseudo_diag("Child process exit status %d: %s\n",
status,
pseudo_exit_status_name(status));
+ if (status == 0) {
+ pseudo_diag("Hang on, server should not have exited 0 without sending us sigusr1?\n");
+ }
exit(status);
}
pseudo_diag("Unknown exit status %d.\n", status);
- exit(1);
+ exit(PSEUDO_EXIT_GENERAL);
} else {
/* detach from parent session */
setsid();
@@ -589,7 +589,7 @@ pseudo_server_loop(void) {
pseudo_debug(PDBGF_SERVER, "server loop started.\n");
if (listen_fd < 0) {
pseudo_diag("got into loop with no valid listen fd.\n");
- exit(1);
+ exit(PSEUDO_EXIT_LISTEN_FD);
}
pdb_log_msg(SEVERITY_INFO, NULL, NULL, NULL, "server started (pid %d)", getpid());
diff --git a/pseudo_util.c b/pseudo_util.c
index 6e6345f..be07951 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -588,9 +588,14 @@ pseudo_evlog_internal(char *fmt, ...) {
/* store pid in text form for prepending to messages */
void
pseudo_new_pid() {
+#if PSEUDO_PORT_LINUX
+ extern char *program_invocation_short_name; /* glibcism */
+#else
+ char *program_invocation_short_name = "unknown";
+#endif
int pid = getpid();
pid_len = snprintf(pid_text, 32, "%d: ", pid);
- pseudo_debug(PDBGF_PID, "new pid: %d\n", pid);
+ pseudo_debug(PDBGF_PID, "new pid: %d [%s]\n", pid, program_invocation_short_name);
}
/* helper function for pseudo_fix_path
@@ -823,7 +828,6 @@ void pseudo_dropenv() {
pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_LIBRARIES);
}
if (ld_preload && strlen(ld_preload)) {
- pseudo_diag("ld_preload without: <%s>\n", ld_preload);
setenv(PRELINK_LIBRARIES, ld_preload, 1);
} else {
unsetenv(PRELINK_LIBRARIES);