]> code.delx.au - pulseaudio/commitdiff
correct autospawning
authorLennart Poettering <lennart@poettering.net>
Wed, 15 Sep 2004 13:03:25 +0000 (13:03 +0000)
committerLennart Poettering <lennart@poettering.net>
Wed, 15 Sep 2004 13:03:25 +0000 (13:03 +0000)
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@202 fefdeb5f-60dc-0310-8127-8f9354f1896f

13 files changed:
polyp/Makefile.am
polyp/conf.c
polyp/core.c
polyp/main.c
polyp/pacat.c
polyp/pactl.c
polyp/polyplib-context.c
polyp/polyplib-context.h
polyp/polyplib-def.h
polyp/polyplib-internal.h
polyp/polyplib-simple.c
polyp/util.c
polyp/util.h

index 9c672a3b7194c9dbe94b6070018dd16b2f46e2af..fc3fb18d26a55a16edd1a76fd6a0552f7a11ce47 100644 (file)
@@ -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
index 3a894a9b7aa23ce07c0640414fd54f5570d9e0d3..b74a5ede2191aa456ae87da975b17f22a2a4d689 100644 (file)
@@ -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);
index 80abe9fe84d8d212bfc1ddd5588ac194ff1df4ad..58035087a4f30a54426505c0cbbdb0cf870cbf69 100644 (file)
@@ -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;
 }
index 04bcceef8e9cde727508771b5a24dcdbaddf7546..e44fc01342ad7bdfc09054a5ae27caa3bfcc105e 100644 (file)
@@ -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:
index b499f71a0bcc03a7bc6691353aaf1bfbb153d290..f4597714dccc0d05e3e293f37e1fd0a3487046ec 100644 (file)
@@ -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) {
index dfa11b70d68b47d58438207a3fd5a68ce6fa8791..c93fd2355342b771ee3f892f63b9c138fc92bcde 100644 (file)
@@ -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");
index 63b42eb3e0022ef69ae68aa3036b2a83eceadec1..7fef6b12c9fdd1faa75654ed8aa2daa8642b85b6 100644 (file)
@@ -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;
index 4b199751b3eb5f029a8ca0c99c93d03f607288e1..84e47b64d3d3f4f6b6f09f6d46cf5c246bbabfb4 100644 (file)
@@ -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);
index 4a49a1f81c38ac112dd53a2173e329f1f69de86b..2aa33338d69e0f824ba835a7d492494ff08c41b5 100644 (file)
@@ -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
index de63b1ba4dba87dd15f26933c02a4c4323773857..98fd792473d02e1575010259e07ecf35053a1414 100644 (file)
@@ -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;
index 1ac0886983380c848b263a8bedd050a2b42faaff..36e6e7572486091b41f4e34f0b8387eb2d10e096 100644 (file)
@@ -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) {
index 3ab6d51acdd2b2d30cab1adf6f547093a4eba619..bb71bbf9569b842465d4abc4808743fbe14a741b 100644 (file)
@@ -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";
+    }
+}
+
index eae98e6e63cc51f628a5702b145972caa6e239a4..f5cda2006b6d79395683df75a1b24ec6705412f8 100644 (file)
@@ -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