diff options
-rw-r--r-- | polyp/Makefile.am | 3 | ||||
-rw-r--r-- | polyp/cmdline.c | 33 | ||||
-rw-r--r-- | polyp/daemon-conf.c | 6 | ||||
-rw-r--r-- | polyp/daemon-conf.h | 7 | ||||
-rw-r--r-- | polyp/main.c | 45 | ||||
-rw-r--r-- | polyp/mainloop.c | 6 | ||||
-rw-r--r-- | polyp/pid.c | 197 | ||||
-rw-r--r-- | polyp/pid.h | 30 | ||||
-rw-r--r-- | polyp/polyplib-context.c | 5 | ||||
-rw-r--r-- | polyp/util.c | 39 | ||||
-rw-r--r-- | polyp/util.h | 2 |
11 files changed, 342 insertions, 31 deletions
diff --git a/polyp/Makefile.am b/polyp/Makefile.am index dd7fb8b4..13ef893c 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -211,7 +211,8 @@ polypaudio_SOURCES = idxset.c idxset.h \ caps.h caps.c \ props.h props.c \ mcalign.c mcalign.h \ - g711.c g711.h + g711.c g711.h \ + pid.c pid.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) diff --git a/polyp/cmdline.c b/polyp/cmdline.c index 0c381f8c..cdf25638 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -52,7 +52,10 @@ enum { ARG_LOAD, ARG_FILE, ARG_DL_SEARCH_PATH, - ARG_RESAMPLE_METHOD + ARG_RESAMPLE_METHOD, + ARG_KILL, + ARG_USE_PID_FILE, + ARG_CHECK }; static struct option long_options[] = { @@ -73,6 +76,9 @@ static struct option long_options[] = { {"file", 1, 0, ARG_FILE}, {"dl-search-path", 1, 0, ARG_DL_SEARCH_PATH}, {"resample-method", 1, 0, ARG_RESAMPLE_METHOD}, + {"kill", 0, 0, ARG_KILL}, + {"use-pid-file", 2, 0, ARG_USE_PID_FILE}, + {"check", 0, 0, ARG_CHECK}, {NULL, 0, 0, 0} }; @@ -88,7 +94,9 @@ void pa_cmdline_help(const char *argv0) { " -h, --help Show this help\n" " --version Show version\n" " --dump-conf Dump default configuration\n" - " --dump-modules Dump list of available modules\n\n" + " --dump-modules Dump list of available modules\n" + " -k --kill Kill a running daemon\n" + " --check Check for a running daemon\n\n" " -D, --daemonize[=BOOL] Daemonize after startup\n" " --fail[=BOOL] Quit when startup fails\n" @@ -100,7 +108,8 @@ void pa_cmdline_help(const char *argv0) { " --scache-idle-time=SECS Unload autoloaded samples when idle and this time passed\n" " --log-target={auto,syslog,stderr} Specify the log target\n" " -p, --dl-search-path=PATH Set the search path for dynamic shared objects (plugins)\n" - " --resample-method=[METHOD] Use the specified resampling method\n\n" + " --resample-method=[METHOD] Use the specified resampling method\n" + " --use-pid-file[=BOOL] Create a PID file\n\n" " -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with the specified argument\n" " -F, --file=FILENAME Run the specified script\n" @@ -119,7 +128,7 @@ int pa_cmdline_parse(struct pa_daemon_conf *conf, int argc, char *const argv [], if (conf->script_commands) pa_strbuf_puts(buf, conf->script_commands); - while ((c = getopt_long(argc, argv, "L:F:ChDnp:", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "L:F:ChDnp:k", long_options, NULL)) != -1) { switch (c) { case ARG_HELP: case 'h': @@ -137,6 +146,15 @@ int pa_cmdline_parse(struct pa_daemon_conf *conf, int argc, char *const argv [], case ARG_DUMP_MODULES: conf->cmd = PA_CMD_DUMP_MODULES; break; + + case 'k': + case ARG_KILL: + conf->cmd = PA_CMD_KILL; + break; + + case ARG_CHECK: + conf->cmd = PA_CMD_CHECK; + break; case ARG_LOAD: case 'L': @@ -188,6 +206,13 @@ int pa_cmdline_parse(struct pa_daemon_conf *conf, int argc, char *const argv [], } break; + case ARG_USE_PID_FILE: + if ((conf->use_pid_file = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(__FILE__": --use-pid-file expects boolean argument\n"); + goto fail; + } + break; + case 'p': case ARG_DL_SEARCH_PATH: pa_xfree(conf->dl_search_path); diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index 191e8d81..9728019d 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -66,6 +66,7 @@ static const struct pa_daemon_conf default_conf = { .log_target = PA_LOG_SYSLOG, .resample_method = PA_RESAMPLER_SRC_SINC_FASTEST, .config_file = NULL, + .use_pid_file = 1 }; struct pa_daemon_conf* pa_daemon_conf_new(void) { @@ -159,6 +160,7 @@ int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename) { { "default-script-file", pa_config_parse_string, NULL }, { "log-target", parse_log_target, NULL }, { "resample-method", parse_resample_method, NULL }, + { "use-pid-file", pa_config_parse_bool, NULL }, { NULL, NULL, NULL }, }; @@ -174,6 +176,7 @@ int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename) { table[9].data = &c->default_script_file; table[10].data = c; table[11].data = c; + table[12].data = &c->use_pid_file; pa_xfree(c->config_file); c->config_file = NULL; @@ -228,9 +231,8 @@ char *pa_daemon_conf_dump(struct pa_daemon_conf *c) { pa_strbuf_printf(s, "dl-search-path = %s\n", c->dl_search_path ? c->dl_search_path : ""); pa_strbuf_printf(s, "default-script-file = %s\n", c->default_script_file); pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); - - assert(c->resample_method <= 4 && c->resample_method >= 0); pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); + pa_strbuf_printf(s, "use-pid-file = %i\n", c->use_pid_file); return pa_strbuf_tostring_free(s); } diff --git a/polyp/daemon-conf.h b/polyp/daemon-conf.h index 9c278485..8a574272 100644 --- a/polyp/daemon-conf.h +++ b/polyp/daemon-conf.h @@ -29,7 +29,9 @@ enum pa_daemon_conf_cmd { PA_CMD_HELP, PA_CMD_VERSION, PA_CMD_DUMP_CONF, - PA_CMD_DUMP_MODULES + PA_CMD_DUMP_MODULES, + PA_CMD_KILL, + PA_CMD_CHECK }; struct pa_daemon_conf { @@ -42,7 +44,8 @@ struct pa_daemon_conf { exit_idle_time, module_idle_time, scache_idle_time, - auto_log_target; + auto_log_target, + use_pid_file; char *script_commands, *dl_search_path, *default_script_file; enum pa_log_target log_target; int resample_method; diff --git a/polyp/main.c b/polyp/main.c index 941bf923..0ba28e5a 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -33,6 +33,7 @@ #include <assert.h> #include <ltdl.h> #include <memblock.h> +#include <limits.h> #ifdef HAVE_LIBWRAP #include <syslog.h> @@ -54,6 +55,7 @@ #include "dumpmodules.h" #include "caps.h" #include "cli-text.h" +#include "pid.h" #ifdef HAVE_LIBWRAP /* Only one instance of these variables */ @@ -122,8 +124,7 @@ static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, } } - - static void close_pipe(int p[2]) { +static void close_pipe(int p[2]) { if (p[0] != -1) close(p[0]); if (p[1] != -1) @@ -142,6 +143,7 @@ int main(int argc, char *argv[]) { int daemon_pipe[2] = { -1, -1 }; gid_t gid = (gid_t) -1; int suid_root; + int valid_pid_file = 0; pa_limit_caps(); @@ -209,6 +211,30 @@ int main(int argc, char *argv[]) { retval = 0; goto finish; + case PA_CMD_CHECK: { + pid_t pid; + + if (pa_pid_file_check_running(&pid) < 0) { + if (conf->verbose) + pa_log(__FILE__": daemon not running\n"); + } else { + if (conf->verbose) + pa_log(__FILE__": daemon running as PID %u\n", pid); + retval = 0; + } + + goto finish; + + } + case PA_CMD_KILL: + + if (pa_pid_file_kill(SIGINT, NULL) < 0) + pa_log(__FILE__": failed to kill daemon.\n"); + else + retval = 0; + + goto finish; + default: assert(conf->cmd == PA_CMD_DAEMON); } @@ -260,11 +286,16 @@ int main(int argc, char *argv[]) { close(0); close(1); } - - chdir("/"); - pa_log(__FILE__": sizeof(pa_usec_t) = %u\n", sizeof(pa_usec_t)); + chdir("/"); + if (conf->use_pid_file) { + if (pa_pid_file_create() < 0) + goto finish; + + valid_pid_file = 1; + } + mainloop = pa_mainloop_new(); assert(mainloop); @@ -303,6 +334,7 @@ int main(int argc, char *argv[]) { if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); } else { + retval = 0; if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); @@ -332,6 +364,9 @@ finish: if (conf) pa_daemon_conf_free(conf); + if (valid_pid_file) + pa_pid_file_remove(); + close_pipe(daemon_pipe); lt_dlexit(); diff --git a/polyp/mainloop.c b/polyp/mainloop.c index f56614ce..d530419e 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -614,7 +614,7 @@ void pa_mainloop_dump(struct pa_mainloop *m) { if (e->dead) continue; - pa_log(__FILE__": kind=io fd=%i events=%i callback=%p userdata=%p\n", e->fd, (int) e->events, e->callback, e->userdata); + pa_log(__FILE__": kind=io fd=%i events=%i callback=%p userdata=%p\n", e->fd, (int) e->events, (void*) e->callback, (void*) e->userdata); } } { @@ -624,7 +624,7 @@ void pa_mainloop_dump(struct pa_mainloop *m) { if (e->dead) continue; - pa_log(__FILE__": kind=defer enabled=%i callback=%p userdata=%p\n", e->enabled, e->callback, e->userdata); + pa_log(__FILE__": kind=defer enabled=%i callback=%p userdata=%p\n", e->enabled, (void*) e->callback, (void*) e->userdata); } } { @@ -634,7 +634,7 @@ void pa_mainloop_dump(struct pa_mainloop *m) { if (e->dead) continue; - pa_log(__FILE__": kind=time enabled=%i time=%u.%u callback=%p userdata=%p\n", e->enabled, e->timeval.tv_sec, e->timeval.tv_usec, e->callback, e->userdata); + pa_log(__FILE__": kind=time enabled=%i time=%lu.%lu callback=%p userdata=%p\n", e->enabled, (unsigned long) e->timeval.tv_sec, (unsigned long) e->timeval.tv_usec, (void*) e->callback, (void*) e->userdata); } } diff --git a/polyp/pid.c b/polyp/pid.c new file mode 100644 index 00000000..142c4f6d --- /dev/null +++ b/polyp/pid.c @@ -0,0 +1,197 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <string.h> +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <limits.h> +#include <signal.h> + +#include "pid.h" +#include "util.h" +#include "log.h" + +static pid_t read_pid(const char *fn, int fd) { + ssize_t r; + char t[20], *e = NULL; + long int pid; + + assert(fn && fd >= 0); + + if ((r = pa_loop_read(fd, t, sizeof(t)-1)) < 0) { + pa_log(__FILE__": WARNING: failed to read PID file '%s': %s\n", fn, strerror(errno)); + return (pid_t) -1; + } + + if (r == 0) + return (pid_t) 0; + + t[r] = 0; + + if (!t[0] || (pid = strtol(t, &e, 0)) == 0 || (*e != 0 && *e != '\n')) { + pa_log(__FILE__": WARNING: failed to parse PID file '%s'\n", fn); + return (pid_t) -1; + } + + return (pid_t) pid; +} + +int pa_pid_file_create(void) { + int fd = -1, lock = -1; + int ret = -1; + char fn[PATH_MAX]; + char t[20]; + pid_t pid; + size_t l; + + pa_runtime_path("pid", fn, sizeof(fn)); + if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { + pa_log(__FILE__": WARNING: failed to open PID file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + lock = pa_lock_fd(fd, 1); + + if ((pid = read_pid(fn, fd)) == (pid_t) -1) + pa_log(__FILE__": corrupt PID file, overwriting.\n"); + else if (pid > 0) { + if (kill(pid, 0) >= 0 || errno != ESRCH) { + pa_log(__FILE__": valid PID file.\n"); + goto fail; + } + + pa_log(__FILE__": stale PID file, overwriting.\n"); + } + + lseek(fd, 0, SEEK_SET); + + snprintf(t, sizeof(t), "%lu", (unsigned long) getpid()); + l = strlen(t); + + if (pa_loop_write(fd, t, l) != (ssize_t) l) { + pa_log(__FILE__": failed to write PID file.\n"); + goto fail; + } + + ret = 0; + +fail: + if (fd >= 0) { + if (lock >= 0) + pa_lock_fd(fd, 0); + + close(fd); + } + + return ret; +} + +int pa_pid_file_remove(void) { + int fd = -1, lock = -1; + char fn[PATH_MAX]; + int ret = -1; + pid_t pid; + + pa_runtime_path("pid", fn, sizeof(fn)); + if ((fd = open(fn, O_RDWR)) < 0) { + pa_log(__FILE__": WARNING: failed to open PID file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + lock = pa_lock_fd(fd, 1); + + if ((pid = read_pid(fn, fd)) == (pid_t) -1) + goto fail; + + if (pid != getpid()) { + pa_log(__FILE__": WARNING: PID file '%s' not mine!\n", fn); + goto fail; + } + + if (ftruncate(fd, 0) < 0) { + pa_log(__FILE__": failed to truncate PID file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + if (unlink(fn) < 0) { + pa_log(__FILE__": failed to remove PID file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + ret = 0; + +fail: + + if (fd >= 0) { + if (lock >= 0) + pa_lock_fd(fd, 0); + + close(fd); + } + + return ret; +} + +int pa_pid_file_check_running(pid_t *pid) { + return pa_pid_file_kill(0, pid); +} + +int pa_pid_file_kill(int sig, pid_t *pid) { + int fd = -1, lock = -1; + char fn[PATH_MAX]; + int ret = -1; + pid_t _pid; + + if (!pid) + pid = &_pid; + + pa_runtime_path("pid", fn, sizeof(fn)); + if ((fd = open(fn, O_RDONLY)) < 0) + goto fail; + + lock = pa_lock_fd(fd, 1); + + if ((*pid = read_pid(fn, fd)) == (pid_t) -1) + goto fail; + + ret = kill(*pid, sig); + +fail: + + if (fd >= 0) { + if (lock >= 0) + pa_lock_fd(fd, 0); + + close(fd); + } + + return ret; + +} diff --git a/polyp/pid.h b/polyp/pid.h new file mode 100644 index 00000000..906ab6da --- /dev/null +++ b/polyp/pid.h @@ -0,0 +1,30 @@ +#ifndef foopidhfoo +#define foopidhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +int pa_pid_file_create(void); +int pa_pid_file_remove(void); +int pa_pid_file_check_running(pid_t *pid); +int pa_pid_file_kill(int sig, pid_t *pid); + +#endif diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 70429583..899a8176 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -67,7 +67,10 @@ static void unlock_autospawn_lock_file(struct pa_context *c) { assert(c); if (c->autospawn_lock_fd >= 0) { - pa_unlock_lockfile(c->autospawn_lock_fd); + char lf[PATH_MAX]; + pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); + + pa_unlock_lockfile(lf, c->autospawn_lock_fd); c->autospawn_lock_fd = -1; } } diff --git a/polyp/util.c b/polyp/util.c index 23515f03..2ad26c41 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -612,20 +612,27 @@ finish: /* Lock or unlock a file entirely. (advisory) */ int pa_lock_fd(int fd, int b) { - struct flock flock; + /* Try a R/W lock first */ + flock.l_type = b ? F_WRLCK : F_UNLCK; flock.l_whence = SEEK_SET; flock.l_start = 0; flock.l_len = 0; - if (fcntl(fd, F_SETLKW, &flock) < 0) { - pa_log(__FILE__": %slock failed: %s\n", !b ? "un" : "", strerror(errno)); - return -1; - } + if (fcntl(fd, F_SETLKW, &flock) >= 0) + return 0; - return 0; + /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */ + if (b && errno == EBADF) { + flock.l_type = F_RDLCK; + if (fcntl(fd, F_SETLKW, &flock) >= 0) + return 0; + } + + pa_log(__FILE__": %slock failed: %s\n", !b ? "un" : "", strerror(errno)); + return -1; } /* Remove trailing newlines from a string */ @@ -642,35 +649,43 @@ int pa_lock_lockfile(const char *fn) { assert(fn); if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": failed to create lock file '%s'\n", fn); + pa_log(__FILE__": failed to create lock file '%s': %s\n", fn, strerror(errno)); goto fail; } if (pa_lock_fd(fd, 1) < 0) + pa_log(__FILE__": failed to lock file '%s'.\n", fn); goto fail; return fd; fail: - if (fd >= 0) + if (fd >= 0) { + unlink(fn); close(fd); + } return -1; } /* Unlock a temporary lcok file */ -int pa_unlock_lockfile(int fd) { +int pa_unlock_lockfile(const char *fn, int fd) { int r = 0; - assert(fd >= 0); + assert(fn && fd >= 0); + if (unlink(fn) < 0) { + pa_log(__FILE__": WARNING: unable to remove lock file '%s': %s\n", fn, strerror(errno)); + r = -1; + } + if (pa_lock_fd(fd, 0) < 0) { - pa_log(__FILE__": WARNING: failed to unlock file.\n"); + pa_log(__FILE__": WARNING: failed to unlock file '%s'.\n", fn); r = -1; } if (close(fd) < 0) { - pa_log(__FILE__": WARNING: failed to close lock file.\n"); + pa_log(__FILE__": WARNING: failed to close lock file '%s': %s\n", fn, strerror(errno)); r = -1; } diff --git a/polyp/util.h b/polyp/util.h index f86c30cc..ef7e4d96 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -77,7 +77,7 @@ int pa_uid_in_group(const char *name, gid_t *gid); int pa_lock_fd(int fd, int b); int pa_lock_lockfile(const char *fn); -int pa_unlock_lockfile(int fd); +int pa_unlock_lockfile(const char *fn, int fd); FILE *pa_open_config_file(const char *env, const char *global, const char *local, char **result); |