summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--polyp/Makefile.am3
-rw-r--r--polyp/cmdline.c33
-rw-r--r--polyp/daemon-conf.c6
-rw-r--r--polyp/daemon-conf.h7
-rw-r--r--polyp/main.c45
-rw-r--r--polyp/mainloop.c6
-rw-r--r--polyp/pid.c197
-rw-r--r--polyp/pid.h30
-rw-r--r--polyp/polyplib-context.c5
-rw-r--r--polyp/util.c39
-rw-r--r--polyp/util.h2
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);