summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2004-09-15 13:03:25 +0000
committerLennart Poettering <lennart@poettering.net>2004-09-15 13:03:25 +0000
commit8c110d904ddf30ce35c9a0c18449436af18a5095 (patch)
treec5749b5e13d0ace36a7cf089af077b6588b7bb76
parent935826f4f318a89a0a570f766deb54808a4f9683 (diff)
correct autospawning
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@202 fefdeb5f-60dc-0310-8127-8f9354f1896f
-rw-r--r--polyp/Makefile.am3
-rw-r--r--polyp/conf.c30
-rw-r--r--polyp/core.c3
-rw-r--r--polyp/main.c14
-rw-r--r--polyp/pacat.c2
-rw-r--r--polyp/pactl.c2
-rw-r--r--polyp/polyplib-context.c199
-rw-r--r--polyp/polyplib-context.h21
-rw-r--r--polyp/polyplib-def.h19
-rw-r--r--polyp/polyplib-internal.h2
-rw-r--r--polyp/polyplib-simple.c2
-rw-r--r--polyp/util.c22
-rw-r--r--polyp/util.h4
13 files changed, 187 insertions, 136 deletions
diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index 9c672a3b..fc3fb18d 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -25,7 +25,8 @@ modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@
AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS)
AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\"
AM_CFLAGS+=-DDEFAULT_SCRIPT_FILE=\"$(polypconfdir)/default.pa\"
-AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/config\"
+AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/default.conf\"
+AM_CFLAGS+=-DAUTOSPAWN_CONFIG_FILE=\"$(polypconfdir)/autospawn.conf\"
AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\"
AM_LDADD=$(PTHREAD_LIBS) -lm
diff --git a/polyp/conf.c b/polyp/conf.c
index 3a894a9b..b74a5ede 100644
--- a/polyp/conf.c
+++ b/polyp/conf.c
@@ -53,17 +53,23 @@ static const struct pa_conf default_conf = {
#define ENV_SCRIPT_FILE "POLYP_SCRIPT"
#define ENV_CONFIG_FILE "POLYP_CONFIG"
+#define ENV_AUTOSPAWNED "POLYP_AUTOSPAWNED"
#ifndef DEFAULT_SCRIPT_FILE
#define DEFAULT_SCRIPT_FILE "/etc/polypaudio/default.pa"
#endif
#ifndef DEFAULT_CONFIG_FILE
-#define DEFAULT_CONFIG_FILE "/etc/polypaudio/config"
+#define DEFAULT_CONFIG_FILE "/etc/polypaudio/default.conf"
+#endif
+
+#ifndef AUTOSPAWN_CONFIG_FILE
+#define AUTOSPAWN_CONFIG_FILE "/etc/polypaudio/autospawn.conf"
#endif
#define DEFAULT_SCRIPT_FILE_LOCAL ".polypaudio.pa"
#define DEFAULT_CONFIG_FILE_LOCAL ".polypaudio.conf"
+#define AUTOSPAWN_CONFIG_FILE_LOCAL ".polypaudio-autospawn.conf"
char* default_file(const char *envvar, const char *global, const char *local) {
char *p, *h;
@@ -85,10 +91,26 @@ char* default_file(const char *envvar, const char *global, const char *local) {
return pa_xstrdup(global);
}
+char *default_config_file(void) {
+ char *b;
+ int autospawned = 0;
+
+ if ((b = getenv(ENV_AUTOSPAWNED)))
+ autospawned = pa_parse_boolean(b) > 0;
+
+ return default_file(ENV_CONFIG_FILE,
+ autospawned ? AUTOSPAWN_CONFIG_FILE : DEFAULT_CONFIG_FILE,
+ autospawned ? AUTOSPAWN_CONFIG_FILE_LOCAL : DEFAULT_CONFIG_FILE_LOCAL);
+
+}
+
+char *default_script_file(void) {
+ return default_file(ENV_SCRIPT_FILE, DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_LOCAL);
+}
struct pa_conf* pa_conf_new(void) {
struct pa_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf));
- c->default_script_file = default_file(ENV_SCRIPT_FILE, DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_LOCAL);
+ c->default_script_file = default_script_file();
return c;
}
@@ -223,7 +245,7 @@ int pa_conf_load(struct pa_conf *c, const char *filename) {
assert(c);
if (!filename)
- filename = def = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_LOCAL);
+ filename = def = default_config_file();
if (!(f = fopen(filename, "r"))) {
if (errno != ENOENT)
@@ -259,7 +281,7 @@ char *pa_conf_dump(struct pa_conf *c) {
struct pa_strbuf *s = pa_strbuf_new();
char *d;
- d = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_LOCAL);
+ d = default_config_file();
pa_strbuf_printf(s, "### Default configuration file: %s ###\n", d);
pa_strbuf_printf(s, "verbose = %i\n", !!c->verbose);
diff --git a/polyp/core.c b/polyp/core.c
index 80abe9fe..58035087 100644
--- a/polyp/core.c
+++ b/polyp/core.c
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
+#include <signal.h>
#include "core.h"
#include "module.h"
@@ -79,7 +80,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
c->module_idle_time = 20;
c->scache_idle_time = 20;
- pa_check_for_sigpipe();
+ pa_check_signal_is_blocked(SIGPIPE);
return c;
}
diff --git a/polyp/main.c b/polyp/main.c
index 04bcceef..e44fc013 100644
--- a/polyp/main.c
+++ b/polyp/main.c
@@ -58,20 +58,8 @@ static void drop_root(void) {
}
}
-static const char* signal_name(int s) {
- switch(s) {
- case SIGINT: return "SIGINT";
- case SIGTERM: return "SIGTERM";
- case SIGUSR1: return "SIGUSR1";
- case SIGUSR2: return "SIGUSR2";
- case SIGXCPU: return "SIGXCPU";
- case SIGPIPE: return "SIGPIPE";
- default: return "UNKNOWN SIGNAL";
- }
-}
-
static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) {
- pa_log(__FILE__": Got signal %s.\n", signal_name(sig));
+ pa_log(__FILE__": Got signal %s.\n", pa_strsignal(sig));
switch (sig) {
case SIGUSR1:
diff --git a/polyp/pacat.c b/polyp/pacat.c
index b499f71a..f4597714 100644
--- a/polyp/pacat.c
+++ b/polyp/pacat.c
@@ -360,7 +360,7 @@ int main(int argc, char *argv[]) {
pa_context_set_state_callback(context, context_state_callback, NULL);
/* Connect the context */
- pa_context_connect_spawn(context, NULL, NULL, NULL);
+ pa_context_connect(context, NULL, 1, NULL);
/* Run the main loop */
if (pa_mainloop_run(m, &ret) < 0) {
diff --git a/polyp/pactl.c b/polyp/pactl.c
index dfa11b70..c93fd235 100644
--- a/polyp/pactl.c
+++ b/polyp/pactl.c
@@ -292,7 +292,7 @@ int main(int argc, char *argv[]) {
}
pa_context_set_state_callback(context, context_state_callback, NULL);
- pa_context_connect(context, NULL);
+ pa_context_connect(context, NULL, 1, NULL);
if (pa_mainloop_run(m, &ret) < 0) {
fprintf(stderr, "pa_mainloop_run() failed.\n");
diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c
index 63b42eb3..7fef6b12 100644
--- a/polyp/polyplib-context.c
+++ b/polyp/polyplib-context.c
@@ -85,7 +85,7 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *
c->memblock_stat = pa_memblock_stat_new();
- pa_check_for_sigpipe();
+ pa_check_signal_is_blocked(SIGPIPE);
return c;
}
@@ -365,15 +365,116 @@ static struct sockaddr *resolve_server(const char *server, size_t *len) {
return sa;
}
-int pa_context_connect(struct pa_context *c, const char *server) {
+static int is_running(void) {
+ struct stat st;
+
+ if (DEFAULT_SERVER[0] != '/')
+ return 1;
+
+ if (stat(DEFAULT_SERVER, &st) < 0)
+ return 0;
+
+ return 1;
+}
+
+static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api *api) {
+ pid_t pid;
+ int status, r;
+ int fds[2] = { -1, -1} ;
+ struct pa_iochannel *io;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
+ pa_log(__FILE__": socketpair() failed: %s\n", strerror(errno));
+ pa_context_fail(c, PA_ERROR_INTERNAL);
+ goto fail;
+ }
+
+ if (api && api->prefork)
+ api->prefork();
+
+ if ((pid = fork()) < 0) {
+ pa_log(__FILE__": fork() failed: %s\n", strerror(errno));
+ pa_context_fail(c, PA_ERROR_INTERNAL);
+
+ if (api && api->postfork)
+ api->postfork();
+
+ goto fail;
+ } else if (!pid) {
+ char t[128];
+ char *p;
+ /* Child */
+
+ close(fds[0]);
+
+ if (api && api->atfork)
+ api->atfork();
+
+ if (!(p = getenv(ENV_DEFAULT_BINARY)))
+ p = POLYPAUDIO_BINARY;
+
+ snprintf(t, sizeof(t), "%s=1", ENV_AUTOSPAWNED);
+ putenv(t);
+
+ snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]);
+ execl(p, p, t, NULL);
+
+ exit(1);
+ }
+
+ /* Parent */
+
+ r = waitpid(pid, &status, 0);
+
+ if (api && api->postfork)
+ api->postfork();
+
+ if (r < 0) {
+ pa_log(__FILE__": waitpid() failed: %s\n", strerror(errno));
+ pa_context_fail(c, PA_ERROR_INTERNAL);
+ goto fail;
+ } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
+ goto fail;
+ }
+
+ close(fds[1]);
+
+ io = pa_iochannel_new(c->mainloop, fds[0], fds[0]);
+ setup_context(c, io);
+ return 0;
+
+fail:
+ if (fds[0] != -1)
+ close(fds[0]);
+ if (fds[1] != -1)
+ close(fds[1]);
+
+ return -1;
+}
+
+
+
+int pa_context_connect(struct pa_context *c, const char *server, int spawn, const struct pa_spawn_api *api) {
int r = -1;
assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED);
- pa_context_ref(c);
-
if (!server)
- if (!(server = getenv(ENV_DEFAULT_SERVER)))
+ if (!(server = getenv(ENV_DEFAULT_SERVER))) {
+ if (spawn && !is_running()) {
+ char *b;
+
+ if ((b = getenv(ENV_DISABLE_AUTOSPAWN)))
+ if (pa_parse_boolean(b) > 1)
+ return -1;
+
+ return context_connect_spawn(c, api);
+ }
+
server = DEFAULT_SERVER;
+ }
+
+ pa_context_ref(c);
assert(!c->client);
@@ -562,94 +663,6 @@ const char* pa_get_library_version(void) {
return PACKAGE_VERSION;
}
-static int is_running(void) {
- struct stat st;
-
- if (DEFAULT_SERVER[0] != '/')
- return 1;
-
- if (stat(DEFAULT_SERVER, &st) < 0)
- return 0;
-
- return 1;
-}
-
-int pa_context_connect_spawn(struct pa_context *c, void (*atfork)(void), void (*prefork)(void), void (*postfork)(void)) {
- pid_t pid;
- int status, r;
- int fds[2] = { -1, -1} ;
- struct pa_iochannel *io;
-
- if (getenv(ENV_DEFAULT_SERVER) || is_running())
- return pa_context_connect(c, NULL);
-
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
- pa_log(__FILE__": socketpair() failed: %s\n", strerror(errno));
- pa_context_fail(c, PA_ERROR_INTERNAL);
- goto fail;
- }
-
- if (prefork)
- prefork();
-
- if ((pid = fork()) < 0) {
- pa_log(__FILE__": fork() failed: %s\n", strerror(errno));
- pa_context_fail(c, PA_ERROR_INTERNAL);
-
- if (postfork)
- postfork();
-
- goto fail;
- } else if (!pid) {
- char t[64];
- char *p;
- /* Child */
-
- close(fds[0]);
-
- if (atfork)
- atfork();
-
- if (!(p = getenv(ENV_DEFAULT_BINARY)))
- p = POLYPAUDIO_BINARY;
-
- snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]);
- execl(p, p, "-r", "-D", "-lsyslog", "-X 5", t, NULL);
-
- exit(1);
- }
-
- /* Parent */
-
- r = waitpid(pid, &status, 0);
-
- if (postfork)
- postfork();
-
- if (r < 0) {
- pa_log(__FILE__": waitpid() failed: %s\n", strerror(errno));
- pa_context_fail(c, PA_ERROR_INTERNAL);
- goto fail;
- } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
- pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
- goto fail;
- }
-
- close(fds[1]);
-
- io = pa_iochannel_new(c->mainloop, fds[0], fds[0]);
- setup_context(c, io);
- return 0;
-
-fail:
- if (fds[0] != -1)
- close(fds[0]);
- if (fds[1] != -1)
- close(fds[1]);
-
- return -1;
-}
-
struct pa_operation* pa_context_set_default_sink(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata) {
struct pa_tagstruct *t;
struct pa_operation *o;
diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h
index 4b199751..84e47b64 100644
--- a/polyp/polyplib-context.h
+++ b/polyp/polyplib-context.h
@@ -76,22 +76,11 @@ enum pa_context_state pa_context_get_state(struct pa_context *c);
/** Connect the context to the specified server. If server is NULL,
connect to the default server. This routine may but will not always
return synchronously on error. Use pa_context_set_state_callback() to
-be notified when the connection is established */
-int pa_context_connect(struct pa_context *c, const char *server);
-
-/** Connect the context to a server. If the default server is local
- * but not accessible, spawn a new daemon. If atfork is not NULL it is
- * run after the fork() in the child process. It may be used to close
- * file descriptors or to do any other cleanups. (It is not safe to
- * close all file descriptors unconditionally, since a UNIX socket is
- * passed to the new process.) if prefork is not NULL it is run just
- * before forking in the parent process. Use this to block SIGCHLD
- * handling if required. If postfork is not NULL it is run just after
- * forking in the parent process. Use this to unblock SIGCHLD if
- * required. The function will waitpid() on the daemon's PID, but
- * will not block or ignore SIGCHLD signals, since this cannot be done
- * in a thread compatible way. \since 0.4 */
-int pa_context_connect_spawn(struct pa_context *c, void (*atfork)(void), void (*prefork)(void), void (*postfork)(void));
+be notified when the connection is established. If spawn is non-zero
+and no specific server is specified or accessible a new daemon is
+spawned. If api is non-NULL, the functions specified in the structure
+are used when forking a new child process. */
+int pa_context_connect(struct pa_context *c, const char *server, int spawn, const struct pa_spawn_api *api);
/** Terminate the context connection immediately */
void pa_context_disconnect(struct pa_context *c);
diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h
index 4a49a1f8..2aa33338 100644
--- a/polyp/polyplib-def.h
+++ b/polyp/polyplib-def.h
@@ -156,6 +156,25 @@ struct pa_latency_info {
struct timeval timestamp; /**< The time when this latency info was current */
};
+/** A structure for the spawn api. This may be used to integrate auto
+ * spawned daemons into your application. For more information see
+ * pa_context_connect(). When spawning a new child process the
+ * waitpid() is used on the child's PID. The spawn routine will not
+ * block or ignore SIGCHLD signals, since this cannot be done in a
+ * thread compatible way. You might have to do this in
+ * prefork/postfork. \since 0.4 */
+struct pa_spawn_api {
+ void (*prefork)(void); /**< Is called just before the fork in the parent process. May be NULL. */
+ void (*postfork)(void); /**< Is called immediately after the fork in the parent process. May be NULL.*/
+ void (*atfork)(void); /**< Is called immediately after the
+ * fork in the child process. May be
+ * NULL. It is not safe to close all
+ * file descriptors in this function
+ * unconditionally, since a UNIX socket
+ * (created using socketpair()) is
+ * passed to the new process. */
+};
+
PA_C_DECL_END
#endif
diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h
index de63b1ba..98fd7924 100644
--- a/polyp/polyplib-internal.h
+++ b/polyp/polyplib-internal.h
@@ -48,6 +48,8 @@
#define ENV_DEFAULT_SOURCE "POLYP_SOURCE"
#define ENV_DEFAULT_SERVER "POLYP_SERVER"
#define ENV_DEFAULT_BINARY "POLYP_BINARY"
+#define ENV_DISABLE_AUTOSPAWN "POLYP_NOAUTOSPAWN"
+#define ENV_AUTOSPAWNED "POLYP_AUTOSPAWNED"
struct pa_context {
int ref;
diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c
index 1ac08869..36e6e757 100644
--- a/polyp/polyplib-simple.c
+++ b/polyp/polyplib-simple.c
@@ -130,7 +130,7 @@ struct pa_simple* pa_simple_new(
if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name)))
goto fail;
- pa_context_connect(p->context, server);
+ pa_context_connect(p->context, server, 1, NULL);
/* Wait until the context is ready */
while (pa_context_get_state(p->context) != PA_CONTEXT_READY) {
diff --git a/polyp/util.c b/polyp/util.c
index 3ab6d51a..bb71bbf9 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -115,7 +115,7 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size) {
return ret;
}
-void pa_check_for_sigpipe(void) {
+void pa_check_signal_is_blocked(int sig) {
struct sigaction sa;
sigset_t set;
@@ -130,10 +130,10 @@ void pa_check_for_sigpipe(void) {
}
#endif
- if (sigismember(&set, SIGPIPE))
+ if (sigismember(&set, sig))
return;
- if (sigaction(SIGPIPE, NULL, &sa) < 0) {
+ if (sigaction(sig, NULL, &sa) < 0) {
pa_log(__FILE__": sigaction() failed: %s\n", strerror(errno));
return;
}
@@ -141,7 +141,7 @@ void pa_check_for_sigpipe(void) {
if (sa.sa_handler != SIG_DFL)
return;
- pa_log(__FILE__": WARNING: SIGPIPE is not trapped. This might cause malfunction!\n");
+ pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!\n", pa_strsignal(sig));
}
/* The following is based on an example from the GNU libc documentation */
@@ -389,3 +389,17 @@ char *pa_split(const char *c, const char *delimiter, const char**state) {
return pa_xstrndup(current, l);
}
+
+const char *pa_strsignal(int sig) {
+ switch(sig) {
+ case SIGINT: return "SIGINT";
+ case SIGTERM: return "SIGTERM";
+ case SIGUSR1: return "SIGUSR1";
+ case SIGUSR2: return "SIGUSR2";
+ case SIGXCPU: return "SIGXCPU";
+ case SIGPIPE: return "SIGPIPE";
+ case SIGCHLD: return "SIGCHLD";
+ default: return "UNKNOWN SIGNAL";
+ }
+}
+
diff --git a/polyp/util.h b/polyp/util.h
index eae98e6e..f5cda200 100644
--- a/polyp/util.h
+++ b/polyp/util.h
@@ -36,7 +36,7 @@ int pa_make_secure_dir(const char* dir);
ssize_t pa_loop_read(int fd, void*data, size_t size);
ssize_t pa_loop_write(int fd, const void*data, size_t size);
-void pa_check_for_sigpipe(void);
+void pa_check_signal_is_blocked(int sig);
char *pa_sprintf_malloc(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2);
char *pa_vsprintf_malloc(const char *format, va_list ap);
@@ -61,4 +61,6 @@ int pa_parse_boolean(const char *s);
char *pa_split(const char *c, const char*delimiters, const char **state);
+const char *pa_strsignal(int sig);
+
#endif