Reorganised the source tree. We now have src/ with a couple of subdirs:

* daemon/ - Contains the files specific to the polypaudio daemon.
 * modules/ - All loadable modules.
 * polyp/ - Files that are part of the public, application interface or
   are only used in libpolyp.
 * polypcore/ - All other shared files.
 * tests/ - Test programs.
 * utils/ - Utility programs.


git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@487 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Pierre Ossman 2006-02-16 19:19:58 +00:00
parent 5b881e6228
commit e205b25d65
246 changed files with 724 additions and 689 deletions

131
src/daemon/caps.c Normal file
View file

@ -0,0 +1,131 @@
/* $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 <assert.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#ifdef HAVE_SYS_CAPABILITY_H
#include <sys/capability.h>
#endif
#include <polypcore/log.h>
#include "caps.h"
#ifdef HAVE_GETUID
/* Drop root rights when called SUID root */
void pa_drop_root(void) {
uid_t uid = getuid();
if (uid == 0 || geteuid() != 0)
return;
pa_log_info(__FILE__": dropping root rights.\n");
#if defined(HAVE_SETRESUID)
setresuid(uid, uid, uid);
#elif defined(HAVE_SETREUID)
setreuid(uid, uid);
#else
setuid(uid);
seteuid(uid);
#endif
}
#else
void pa_drop_root(void) {
}
#endif
#ifdef HAVE_SYS_CAPABILITY_H
/* Limit capabilities set to CAPSYS_NICE */
int pa_limit_caps(void) {
int r = -1;
cap_t caps;
cap_value_t nice_cap = CAP_SYS_NICE;
caps = cap_init();
assert(caps);
cap_clear(caps);
cap_set_flag(caps, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET);
cap_set_flag(caps, CAP_PERMITTED, 1, &nice_cap, CAP_SET);
if (cap_set_proc(caps) < 0)
goto fail;
pa_log_info(__FILE__": dropped capabilities successfully.\n");
r = 0;
fail:
cap_free (caps);
return r;
}
/* Drop all capabilities, effectively becoming a normal user */
int pa_drop_caps(void) {
cap_t caps;
int r = -1;
caps = cap_init();
assert(caps);
cap_clear(caps);
if (cap_set_proc(caps) < 0) {
pa_log(__FILE__": failed to drop capabilities: %s\n", strerror(errno));
goto fail;
}
r = 0;
fail:
cap_free (caps);
return r;
}
#else
/* NOOPs in case capabilities are not available. */
int pa_limit_caps(void) {
return 0;
}
int pa_drop_caps(void) {
pa_drop_root();
return 0;
}
#endif

29
src/daemon/caps.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef foocapshfoo
#define foocapshfoo
/* $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.
***/
void pa_drop_root(void);
int pa_limit_caps(void);
int pa_drop_caps(void);
#endif

300
src/daemon/cmdline.c Normal file
View file

@ -0,0 +1,300 @@
/* $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 <string.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/stat.h>
#include "cmdline.h"
#include <polypcore/util.h>
#include <polypcore/strbuf.h>
#include <polypcore/xmalloc.h>
/* Argument codes for getopt_long() */
enum {
ARG_HELP = 256,
ARG_VERSION,
ARG_DUMP_CONF,
ARG_DUMP_MODULES,
ARG_DAEMONIZE,
ARG_FAIL,
ARG_LOG_LEVEL,
ARG_HIGH_PRIORITY,
ARG_DISALLOW_MODULE_LOADING,
ARG_EXIT_IDLE_TIME,
ARG_MODULE_IDLE_TIME,
ARG_SCACHE_IDLE_TIME,
ARG_LOG_TARGET,
ARG_LOAD,
ARG_FILE,
ARG_DL_SEARCH_PATH,
ARG_RESAMPLE_METHOD,
ARG_KILL,
ARG_USE_PID_FILE,
ARG_CHECK
};
/* Tabel for getopt_long() */
static struct option long_options[] = {
{"help", 0, 0, ARG_HELP},
{"version", 0, 0, ARG_VERSION},
{"dump-conf", 0, 0, ARG_DUMP_CONF},
{"dump-modules", 0, 0, ARG_DUMP_MODULES},
{"daemonize", 2, 0, ARG_DAEMONIZE},
{"fail", 2, 0, ARG_FAIL},
{"verbose", 2, 0, ARG_LOG_LEVEL},
{"log-level", 2, 0, ARG_LOG_LEVEL},
{"high-priority", 2, 0, ARG_HIGH_PRIORITY},
{"disallow-module-loading", 2, 0, ARG_DISALLOW_MODULE_LOADING},
{"exit-idle-time", 2, 0, ARG_EXIT_IDLE_TIME},
{"module-idle-time", 2, 0, ARG_MODULE_IDLE_TIME},
{"scache-idle-time", 2, 0, ARG_SCACHE_IDLE_TIME},
{"log-target", 1, 0, ARG_LOG_TARGET},
{"load", 1, 0, ARG_LOAD},
{"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}
};
void pa_cmdline_help(const char *argv0) {
const char *e;
if ((e = strrchr(argv0, '/')))
e++;
else
e = argv0;
printf("%s [options]\n\n"
"COMMANDS:\n"
" -h, --help Show this help\n"
" --version Show version\n"
" --dump-conf Dump default configuration\n"
" --dump-modules Dump list of available modules\n"
" -k --kill Kill a running daemon\n"
" --check Check for a running daemon\n\n"
"OPTIONS:\n"
" -D, --daemonize[=BOOL] Daemonize after startup\n"
" --fail[=BOOL] Quit when startup fails\n"
" --high-priority[=BOOL] Try to set high process priority\n"
" (only available as root)\n"
" --disallow-module-loading[=BOOL] Disallow module loading after startup\n"
" --exit-idle-time=SECS Terminate the daemon when idle and this\n"
" time passed\n"
" --module-idle-time=SECS Unload autoloaded modules when idle and\n"
" this time passed\n"
" --scache-idle-time=SECS Unload autoloaded samples when idle and\n"
" this time passed\n"
" --log-level[=LEVEL] Increase or set verbosity level\n"
" -v Increase the verbosity level\n"
" --log-target={auto,syslog,stderr} Specify the log target\n"
" -p, --dl-search-path=PATH Set the search path for dynamic shared\n"
" objects (plugins)\n"
" --resample-method=[METHOD] Use the specified resampling method\n"
" (one of src-sinc-medium-quality,\n"
" src-sinc-best-quality,src-sinc-fastest\n"
" src-zero-order-hold,src-linear,trivial)\n"
" --use-pid-file[=BOOL] Create a PID file\n\n"
"STARTUP SCRIPT:\n"
" -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with\n"
" the specified argument\n"
" -F, --file=FILENAME Run the specified script\n"
" -C Open a command line on the running TTY\n"
" after startup\n\n"
" -n Don't load default script file\n", e);
}
int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d) {
pa_strbuf *buf = NULL;
int c;
assert(conf && argc && argv);
buf = pa_strbuf_new();
if (conf->script_commands)
pa_strbuf_puts(buf, conf->script_commands);
while ((c = getopt_long(argc, argv, "L:F:ChDnp:kv", long_options, NULL)) != -1) {
switch (c) {
case ARG_HELP:
case 'h':
conf->cmd = PA_CMD_HELP;
break;
case ARG_VERSION:
conf->cmd = PA_CMD_VERSION;
break;
case ARG_DUMP_CONF:
conf->cmd = PA_CMD_DUMP_CONF;
break;
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':
pa_strbuf_printf(buf, "load-module %s\n", optarg);
break;
case ARG_FILE:
case 'F':
pa_strbuf_printf(buf, ".include %s\n", optarg);
break;
case 'C':
pa_strbuf_puts(buf, "load-module module-cli\n");
break;
case ARG_DAEMONIZE:
case 'D':
if ((conf->daemonize = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
pa_log(__FILE__": --daemonize expects boolean argument\n");
goto fail;
}
break;
case ARG_FAIL:
if ((conf->fail = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
pa_log(__FILE__": --fail expects boolean argument\n");
goto fail;
}
break;
case 'v':
case ARG_LOG_LEVEL:
if (optarg) {
if (pa_daemon_conf_set_log_level(conf, optarg) < 0) {
pa_log(__FILE__": --log-level expects log level argument (either numeric in range 0..4 or one of debug, info, notice, warn, error).\n");
goto fail;
}
} else {
if (conf->log_level < PA_LOG_LEVEL_MAX-1)
conf->log_level++;
}
break;
case ARG_HIGH_PRIORITY:
if ((conf->high_priority = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
pa_log(__FILE__": --high-priority expects boolean argument\n");
goto fail;
}
break;
case ARG_DISALLOW_MODULE_LOADING:
if ((conf->disallow_module_loading = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
pa_log(__FILE__": --disallow-module-loading expects boolean argument\n");
goto fail;
}
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);
conf->dl_search_path = *optarg ? pa_xstrdup(optarg) : NULL;
break;
case 'n':
pa_xfree(conf->default_script_file);
conf->default_script_file = NULL;
break;
case ARG_LOG_TARGET:
if (pa_daemon_conf_set_log_target(conf, optarg) < 0) {
pa_log(__FILE__": Invalid log target: use either 'syslog', 'stderr' or 'auto'.\n");
goto fail;
}
break;
case ARG_EXIT_IDLE_TIME:
conf->exit_idle_time = atoi(optarg);
break;
case ARG_MODULE_IDLE_TIME:
conf->module_idle_time = atoi(optarg);
break;
case ARG_SCACHE_IDLE_TIME:
conf->scache_idle_time = atoi(optarg);
break;
case ARG_RESAMPLE_METHOD:
if (pa_daemon_conf_set_resample_method(conf, optarg) < 0) {
pa_log(__FILE__": Invalid resample method '%s'.\n", optarg);
goto fail;
}
break;
default:
goto fail;
}
}
pa_xfree(conf->script_commands);
conf->script_commands = pa_strbuf_tostring_free(buf);
if (!conf->script_commands) {
pa_xfree(conf->script_commands);
conf->script_commands = NULL;
}
*d = optind;
return 0;
fail:
if (buf)
pa_strbuf_free(buf);
return -1;
}

35
src/daemon/cmdline.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef foocmdlinehfoo
#define foocmdlinehfoo
/* $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.
***/
#include "daemon-conf.h"
/* Parese the command line and store its data in *c. Return the index
* of the first unparsed argument in *d. */
int pa_cmdline_parse(pa_daemon_conf*c, int argc, char *const argv [], int *d);
/* Show the command line help. The command name is extracted from
* argv[0] which should be passed in argv0. */
void pa_cmdline_help(const char *argv0);
#endif

236
src/daemon/cpulimit.c Normal file
View file

@ -0,0 +1,236 @@
/* $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 "cpulimit.h"
#include <polypcore/util.h>
#include <polypcore/log.h>
#ifdef HAVE_SIGXCPU
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/time.h>
#include <unistd.h>
#include <signal.h>
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
/* This module implements a watchdog that makes sure that the current
* process doesn't consume more than 70% CPU time for 10 seconds. This
* is very useful when using SCHED_FIFO scheduling which effectively
* disables multitasking. */
/* Method of operation: Using SIGXCPU a signal handler is called every
* 10s process CPU time. That function checks if less than 14s system
* time have passed. In that case, it tries to contact the main event
* loop through a pipe. After two additional seconds it is checked
* whether the main event loop contact was successful. If not, the
* program is terminated forcibly. */
/* Utilize this much CPU time at maximum */
#define CPUTIME_PERCENT 70
/* Check every 10s */
#define CPUTIME_INTERVAL_SOFT (10)
/* Recheck after 2s */
#define CPUTIME_INTERVAL_HARD (2)
/* Time of the last CPU load check */
static time_t last_time = 0;
/* Pipe for communicating with the main loop */
static int the_pipe[2] = {-1, -1};
/* Main event loop and IO event for the FIFO */
static pa_mainloop_api *api = NULL;
static pa_io_event *io_event = NULL;
/* Saved sigaction struct for SIGXCPU */
static struct sigaction sigaction_prev;
/* Nonzero after pa_cpu_limit_init() */
static int installed = 0;
/* The current state of operation */
static enum {
PHASE_IDLE, /* Normal state */
PHASE_SOFT /* After CPU overload has been detected */
} phase = PHASE_IDLE;
/* Reset the SIGXCPU timer to the next t seconds */
static void reset_cpu_time(int t) {
int r;
long n;
struct rlimit rl;
struct rusage ru;
/* Get the current CPU time of the current process */
r = getrusage(RUSAGE_SELF, &ru);
assert(r >= 0);
n = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec + t;
r = getrlimit(RLIMIT_CPU, &rl);
assert(r >= 0);
rl.rlim_cur = n;
r = setrlimit(RLIMIT_CPU, &rl);
assert(r >= 0);
}
/* A simple, thread-safe puts() work-alike */
static void write_err(const char *p) {
pa_loop_write(2, p, strlen(p));
}
/* The signal handler, called on every SIGXCPU */
static void signal_handler(int sig) {
assert(sig == SIGXCPU);
if (phase == PHASE_IDLE) {
time_t now;
#ifdef PRINT_CPU_LOAD
char t[256];
#endif
time(&now);
#ifdef PRINT_CPU_LOAD
snprintf(t, sizeof(t), "Using %0.1f%% CPU\n", (double)CPUTIME_INTERVAL_SOFT/(now-last_time)*100);
write_err(t);
#endif
if (CPUTIME_INTERVAL_SOFT >= ((now-last_time)*(double)CPUTIME_PERCENT/100)) {
static const char c = 'X';
write_err("Soft CPU time limit exhausted, terminating.\n");
/* Try a soft cleanup */
write(the_pipe[1], &c, sizeof(c));
phase = PHASE_SOFT;
reset_cpu_time(CPUTIME_INTERVAL_HARD);
} else {
/* Everything's fine */
reset_cpu_time(CPUTIME_INTERVAL_SOFT);
last_time = now;
}
} else if (phase == PHASE_SOFT) {
write_err("Hard CPU time limit exhausted, terminating forcibly.\n");
_exit(1); /* Forced exit */
}
}
/* Callback for IO events on the FIFO */
static void callback(pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags f, void *userdata) {
char c;
assert(m && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == the_pipe[0]);
read(the_pipe[0], &c, sizeof(c));
m->quit(m, 1); /* Quit the main loop */
}
/* Initializes CPU load limiter */
int pa_cpu_limit_init(pa_mainloop_api *m) {
struct sigaction sa;
assert(m && !api && !io_event && the_pipe[0] == -1 && the_pipe[1] == -1 && !installed);
time(&last_time);
/* Prepare the main loop pipe */
if (pipe(the_pipe) < 0) {
pa_log(__FILE__": pipe() failed: %s\n", strerror(errno));
return -1;
}
pa_make_nonblock_fd(the_pipe[0]);
pa_make_nonblock_fd(the_pipe[1]);
pa_fd_set_cloexec(the_pipe[0], 1);
pa_fd_set_cloexec(the_pipe[1], 1);
api = m;
io_event = api->io_new(m, the_pipe[0], PA_IO_EVENT_INPUT, callback, NULL);
phase = PHASE_IDLE;
/* Install signal handler for SIGXCPU */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGXCPU, &sa, &sigaction_prev) < 0) {
pa_cpu_limit_done();
return -1;
}
installed = 1;
reset_cpu_time(CPUTIME_INTERVAL_SOFT);
return 0;
}
/* Shutdown CPU load limiter */
void pa_cpu_limit_done(void) {
int r;
if (io_event) {
assert(api);
api->io_free(io_event);
io_event = NULL;
api = NULL;
}
if (the_pipe[0] >= 0)
close(the_pipe[0]);
if (the_pipe[1] >= 0)
close(the_pipe[1]);
the_pipe[0] = the_pipe[1] = -1;
if (installed) {
r = sigaction(SIGXCPU, &sigaction_prev, NULL);
assert(r >= 0);
installed = 0;
}
}
#else /* HAVE_SIGXCPU */
int pa_cpu_limit_init(PA_GCC_UNUSED pa_mainloop_api *m) {
return 0;
}
void pa_cpu_limit_done(void) {
}
#endif

34
src/daemon/cpulimit.h Normal file
View file

@ -0,0 +1,34 @@
#ifndef foocpulimithfoo
#define foocpulimithfoo
/* $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.
***/
#include <polyp/mainloop-api.h>
/* This kills the polypaudio process if it eats more than 70% of the
* CPU time. This is build around setrlimit() and SIGXCPU. It is handy
* in case of using SCHED_FIFO which may freeze the whole machine */
int pa_cpu_limit_init(pa_mainloop_api *m);
void pa_cpu_limit_done(void);
#endif

297
src/daemon/daemon-conf.c Normal file
View file

@ -0,0 +1,297 @@
/* $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 <errno.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include "daemon-conf.h"
#include <polypcore/util.h>
#include <polypcore/xmalloc.h>
#include <polypcore/strbuf.h>
#include <polypcore/conf-parser.h>
#include <polypcore/resampler.h>
#ifndef DEFAULT_CONFIG_DIR
# ifndef OS_IS_WIN32
# define DEFAULT_CONFIG_DIR "/etc/polypaudio"
# else
# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%"
# endif
#endif
#ifndef OS_IS_WIN32
# define PATH_SEP "/"
#else
# define PATH_SEP "\\"
#endif
#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR PATH_SEP "default.pa"
#define DEFAULT_SCRIPT_FILE_USER ".polypaudio" PATH_SEP "default.pa"
#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf"
#define DEFAULT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "daemon.conf"
#define ENV_SCRIPT_FILE "POLYP_SCRIPT"
#define ENV_CONFIG_FILE "POLYP_CONFIG"
#define ENV_DL_SEARCH_PATH "POLYP_DLPATH"
static const pa_daemon_conf default_conf = {
.cmd = PA_CMD_DAEMON,
.daemonize = 0,
.fail = 1,
.high_priority = 0,
.disallow_module_loading = 0,
.exit_idle_time = -1,
.module_idle_time = 20,
.scache_idle_time = 20,
.auto_log_target = 1,
.script_commands = NULL,
.dl_search_path = NULL,
.default_script_file = NULL,
.log_target = PA_LOG_SYSLOG,
.log_level = PA_LOG_NOTICE,
.resample_method = PA_RESAMPLER_SRC_SINC_FASTEST,
.config_file = NULL,
.use_pid_file = 1
};
pa_daemon_conf* pa_daemon_conf_new(void) {
FILE *f;
pa_daemon_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf));
if ((f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file)))
fclose(f);
#ifdef DLSEARCHPATH
c->dl_search_path = pa_xstrdup(DLSEARCHPATH);
#endif
return c;
}
void pa_daemon_conf_free(pa_daemon_conf *c) {
assert(c);
pa_xfree(c->script_commands);
pa_xfree(c->dl_search_path);
pa_xfree(c->default_script_file);
pa_xfree(c->config_file);
pa_xfree(c);
}
int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string) {
assert(c && string);
if (!strcmp(string, "auto"))
c->auto_log_target = 1;
else if (!strcmp(string, "syslog")) {
c->auto_log_target = 0;
c->log_target = PA_LOG_SYSLOG;
} else if (!strcmp(string, "stderr")) {
c->auto_log_target = 0;
c->log_target = PA_LOG_STDERR;
} else
return -1;
return 0;
}
int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string) {
uint32_t u;
assert(c && string);
if (pa_atou(string, &u) >= 0) {
if (u >= PA_LOG_LEVEL_MAX)
return -1;
c->log_level = (pa_log_level_t) u;
} else if (pa_startswith(string, "debug"))
c->log_level = PA_LOG_DEBUG;
else if (pa_startswith(string, "info"))
c->log_level = PA_LOG_INFO;
else if (pa_startswith(string, "notice"))
c->log_level = PA_LOG_NOTICE;
else if (pa_startswith(string, "warn"))
c->log_level = PA_LOG_WARN;
else if (pa_startswith(string, "err"))
c->log_level = PA_LOG_ERROR;
else
return -1;
return 0;
}
int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string) {
int m;
assert(c && string);
if ((m = pa_parse_resample_method(string)) < 0)
return -1;
c->resample_method = m;
return 0;
}
static int parse_log_target(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
pa_daemon_conf *c = data;
assert(filename && lvalue && rvalue && data);
if (pa_daemon_conf_set_log_target(c, rvalue) < 0) {
pa_log(__FILE__": [%s:%u] Invalid log target '%s'.\n", filename, line, rvalue);
return -1;
}
return 0;
}
static int parse_log_level(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
pa_daemon_conf *c = data;
assert(filename && lvalue && rvalue && data);
if (pa_daemon_conf_set_log_level(c, rvalue) < 0) {
pa_log(__FILE__": [%s:%u] Invalid log level '%s'.\n", filename, line, rvalue);
return -1;
}
return 0;
}
static int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
pa_daemon_conf *c = data;
assert(filename && lvalue && rvalue && data);
if (pa_daemon_conf_set_resample_method(c, rvalue) < 0) {
pa_log(__FILE__": [%s:%u] Inavalid resample method '%s'.\n", filename, line, rvalue);
return -1;
}
return 0;
}
int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
int r = -1;
FILE *f = NULL;
pa_config_item table[] = {
{ "daemonize", pa_config_parse_bool, NULL },
{ "fail", pa_config_parse_bool, NULL },
{ "high-priority", pa_config_parse_bool, NULL },
{ "disallow-module-loading", pa_config_parse_bool, NULL },
{ "exit-idle-time", pa_config_parse_int, NULL },
{ "module-idle-time", pa_config_parse_int, NULL },
{ "scache-idle-time", pa_config_parse_int, NULL },
{ "dl-search-path", pa_config_parse_string, NULL },
{ "default-script-file", pa_config_parse_string, NULL },
{ "log-target", parse_log_target, NULL },
{ "log-level", parse_log_level, NULL },
{ "verbose", parse_log_level, NULL },
{ "resample-method", parse_resample_method, NULL },
{ "use-pid-file", pa_config_parse_bool, NULL },
{ NULL, NULL, NULL },
};
table[0].data = &c->daemonize;
table[1].data = &c->fail;
table[2].data = &c->high_priority;
table[3].data = &c->disallow_module_loading;
table[4].data = &c->exit_idle_time;
table[5].data = &c->module_idle_time;
table[6].data = &c->scache_idle_time;
table[7].data = &c->dl_search_path;
table[8].data = &c->default_script_file;
table[9].data = c;
table[10].data = c;
table[11].data = c;
table[12].data = c;
table[13].data = &c->use_pid_file;
pa_xfree(c->config_file);
c->config_file = NULL;
f = filename ?
fopen(c->config_file = pa_xstrdup(filename), "r") :
pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file);
if (!f && errno != ENOENT) {
pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno));
goto finish;
}
r = f ? pa_config_parse(c->config_file, f, table, NULL) : 0;
finish:
if (f)
fclose(f);
return r;
}
int pa_daemon_conf_env(pa_daemon_conf *c) {
char *e;
if ((e = getenv(ENV_DL_SEARCH_PATH))) {
pa_xfree(c->dl_search_path);
c->dl_search_path = pa_xstrdup(e);
}
if ((e = getenv(ENV_SCRIPT_FILE))) {
pa_xfree(c->default_script_file);
c->default_script_file = pa_xstrdup(e);
}
return 0;
}
static const char* const log_level_to_string[] = {
[PA_LOG_DEBUG] = "debug",
[PA_LOG_INFO] = "info",
[PA_LOG_NOTICE] = "notice",
[PA_LOG_WARN] = "warning",
[PA_LOG_ERROR] = "error"
};
char *pa_daemon_conf_dump(pa_daemon_conf *c) {
pa_strbuf *s = pa_strbuf_new();
if (c->config_file)
pa_strbuf_printf(s, "### Read from configuration file: %s ###\n", c->config_file);
assert(c->log_level <= PA_LOG_LEVEL_MAX);
pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize);
pa_strbuf_printf(s, "fail = %i\n", !!c->fail);
pa_strbuf_printf(s, "high-priority = %i\n", !!c->high_priority);
pa_strbuf_printf(s, "disallow-module-loading = %i\n", !!c->disallow_module_loading);
pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time);
pa_strbuf_printf(s, "module-idle-time = %i\n", c->module_idle_time);
pa_strbuf_printf(s, "scache-idle-time = %i\n", c->scache_idle_time);
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"));
pa_strbuf_printf(s, "log-level = %s\n", log_level_to_string[c->log_level]);
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);
}

80
src/daemon/daemon-conf.h Normal file
View file

@ -0,0 +1,80 @@
#ifndef foodaemonconfhfoo
#define foodaemonconfhfoo
/* $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.
***/
#include <polypcore/log.h>
/* The actual command to execute */
typedef enum pa_daemon_conf_cmd {
PA_CMD_DAEMON, /* the default */
PA_CMD_HELP,
PA_CMD_VERSION,
PA_CMD_DUMP_CONF,
PA_CMD_DUMP_MODULES,
PA_CMD_KILL,
PA_CMD_CHECK
} pa_daemon_conf_cmd_t;
/* A structure containing configuration data for the Polypaudio server . */
typedef struct pa_daemon_conf {
pa_daemon_conf_cmd_t cmd;
int daemonize,
fail,
high_priority,
disallow_module_loading,
exit_idle_time,
module_idle_time,
scache_idle_time,
auto_log_target,
use_pid_file;
char *script_commands, *dl_search_path, *default_script_file;
pa_log_target_t log_target;
pa_log_level_t log_level;
int resample_method;
char *config_file;
} pa_daemon_conf;
/* Allocate a new structure and fill it with sane defaults */
pa_daemon_conf* pa_daemon_conf_new(void);
void pa_daemon_conf_free(pa_daemon_conf*c);
/* Load configuration data from the specified file overwriting the
* current settings in *c. If filename is NULL load the default daemon
* configuration file */
int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename);
/* Pretty print the current configuration data of the daemon. The
* returned string has to be freed manually. The output of this
* function may be parsed with pa_daemon_conf_load(). */
char *pa_daemon_conf_dump(pa_daemon_conf *c);
/* Load the configuration data from the process' environment
* overwriting the current settings in *c. */
int pa_daemon_conf_env(pa_daemon_conf *c);
/* Set these configuration variables in the structure by passing a string */
int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string);
int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string);
int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string);
#endif

99
src/daemon/dumpmodules.c Normal file
View file

@ -0,0 +1,99 @@
/* $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 <string.h>
#include <getopt.h>
#include <assert.h>
#include <stdio.h>
#include <ltdl.h>
#include "dumpmodules.h"
#include <polypcore/modinfo.h>
#include <polypcore/util.h>
#define PREFIX "module-"
static void short_info(const char *name, PA_GCC_UNUSED const char *path, pa_modinfo *i) {
assert(name && i);
printf("%-40s%s\n", name, i->description ? i->description : "n/a");
}
static void long_info(const char *name, const char *path, pa_modinfo *i) {
static int nl = 0;
assert(name && i);
if (nl)
printf("\n");
nl = 1;
printf("Name: %s\n", name);
if (!i->description && !i->version && !i->author && !i->usage)
printf("No module information available\n");
else {
if (i->version)
printf("Version: %s\n", i->version);
if (i->description)
printf("Description: %s\n", i->description);
if (i->author)
printf("Author: %s\n", i->author);
if (i->usage)
printf("Usage: %s\n", i->usage);
}
if (path)
printf("Path: %s\n", path);
}
static void show_info(const char *name, const char *path, void (*info)(const char *name, const char *path, pa_modinfo*i)) {
pa_modinfo *i;
if ((i = pa_modinfo_get_by_name(path ? path : name))) {
info(name, path, i);
pa_modinfo_free(i);
}
}
static int callback(const char *path, lt_ptr data) {
const char *e;
pa_daemon_conf *c = (data);
e = pa_path_get_filename(path);
if (strlen(e) > sizeof(PREFIX)-1 && !strncmp(e, PREFIX, sizeof(PREFIX)-1))
show_info(e, path, c->log_level >= PA_LOG_INFO ? long_info : short_info);
return 0;
}
void pa_dump_modules(pa_daemon_conf *c, int argc, char * const argv[]) {
if (argc > 0) {
int i;
for (i = 0; i < argc; i++)
show_info(argv[i], NULL, long_info);
} else
lt_dlforeachfile(NULL, callback, c);
}

31
src/daemon/dumpmodules.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef foodumpmoduleshfoo
#define foodumpmoduleshfoo
/* $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.
***/
#include "daemon-conf.h"
/* Dump all available modules to STDOUT. If argc > 0 print information
* about the modules specified in argv[] instead. */
void pa_dump_modules(pa_daemon_conf *c, int argc, char * const argv[]);
#endif

472
src/daemon/main.c Normal file
View file

@ -0,0 +1,472 @@
/* $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 <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <stddef.h>
#include <assert.h>
#include <ltdl.h>
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <liboil/liboil.h>
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_LIBWRAP
#include <syslog.h>
#include <tcpd.h>
#endif
#include <polypcore/winsock.h>
#include <polypcore/core.h>
#include <polypcore/memblock.h>
#include <polyp/mainloop.h>
#include <polypcore/module.h>
#include <polyp/mainloop-signal.h>
#include "cmdline.h"
#include <polypcore/cli-command.h>
#include <polypcore/util.h>
#include <polypcore/sioman.h>
#include <polypcore/xmalloc.h>
#include "cpulimit.h"
#include <polypcore/log.h>
#include "daemon-conf.h"
#include "dumpmodules.h"
#include "caps.h"
#include <polypcore/cli-text.h>
#include <polypcore/pid.h>
#include <polypcore/namereg.h>
#ifdef HAVE_LIBWRAP
/* Only one instance of these variables */
int allow_severity = LOG_INFO;
int deny_severity = LOG_WARNING;
#endif
#ifdef OS_IS_WIN32
static void message_cb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) {
MSG msg;
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
raise(SIGTERM);
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
#endif
static void signal_callback(pa_mainloop_api*m, PA_GCC_UNUSED pa_signal_event *e, int sig, void *userdata) {
pa_log_info(__FILE__": Got signal %s.\n", pa_strsignal(sig));
switch (sig) {
#ifdef SIGUSR1
case SIGUSR1:
pa_module_load(userdata, "module-cli", NULL);
break;
#endif
#ifdef SIGUSR2
case SIGUSR2:
pa_module_load(userdata, "module-cli-protocol-unix", NULL);
break;
#endif
#ifdef SIGHUP
case SIGHUP: {
char *c = pa_full_status_string(userdata);
pa_log_notice(c);
pa_xfree(c);
return;
}
#endif
case SIGINT:
case SIGTERM:
default:
pa_log_info(__FILE__": Exiting.\n");
m->quit(m, 1);
break;
}
}
static void close_pipe(int p[2]) {
if (p[0] != -1)
close(p[0]);
if (p[1] != -1)
close(p[1]);
p[0] = p[1] = -1;
}
int main(int argc, char *argv[]) {
pa_core *c;
pa_strbuf *buf = NULL;
pa_daemon_conf *conf;
pa_mainloop *mainloop;
char *s;
int r, retval = 1, d = 0;
int daemon_pipe[2] = { -1, -1 };
int suid_root;
int valid_pid_file = 0;
#ifdef HAVE_GETUID
gid_t gid = (gid_t) -1;
#endif
#ifdef OS_IS_WIN32
pa_defer_event *defer;
#endif
pa_limit_caps();
#ifdef HAVE_GETUID
suid_root = getuid() != 0 && geteuid() == 0;
if (suid_root && (pa_uid_in_group("realtime", &gid) <= 0 || gid >= 1000)) {
pa_log_warn(__FILE__": WARNING: called SUID root, but not in group 'realtime'.\n");
pa_drop_root();
}
#else
suid_root = 0;
#endif
LTDL_SET_PRELOADED_SYMBOLS();
r = lt_dlinit();
assert(r == 0);
#ifdef OS_IS_WIN32
{
WSADATA data;
WSAStartup(MAKEWORD(2, 0), &data);
}
#endif
pa_log_set_ident("polypaudio");
conf = pa_daemon_conf_new();
if (pa_daemon_conf_load(conf, NULL) < 0)
goto finish;
if (pa_daemon_conf_env(conf) < 0)
goto finish;
if (pa_cmdline_parse(conf, argc, argv, &d) < 0) {
pa_log(__FILE__": failed to parse command line.\n");
goto finish;
}
pa_log_set_maximal_level(conf->log_level);
pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL);
if (conf->high_priority && conf->cmd == PA_CMD_DAEMON)
pa_raise_priority();
pa_drop_caps();
if (suid_root)
pa_drop_root();
if (conf->dl_search_path)
lt_dlsetsearchpath(conf->dl_search_path);
switch (conf->cmd) {
case PA_CMD_DUMP_MODULES:
pa_dump_modules(conf, argc-d, argv+d);
retval = 0;
goto finish;
case PA_CMD_DUMP_CONF: {
s = pa_daemon_conf_dump(conf);
fputs(s, stdout);
pa_xfree(s);
retval = 0;
goto finish;
}
case PA_CMD_HELP :
pa_cmdline_help(argv[0]);
retval = 0;
goto finish;
case PA_CMD_VERSION :
printf(PACKAGE_NAME" "PACKAGE_VERSION"\n");
retval = 0;
goto finish;
case PA_CMD_CHECK: {
pid_t pid;
if (pa_pid_file_check_running(&pid) < 0) {
pa_log_info(__FILE__": daemon not running\n");
} else {
pa_log_info(__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);
}
if (conf->daemonize) {
pid_t child;
int tty_fd;
if (pa_stdio_acquire() < 0) {
pa_log(__FILE__": failed to acquire stdio.\n");
goto finish;
}
#ifdef HAVE_FORK
if (pipe(daemon_pipe) < 0) {
pa_log(__FILE__": failed to create pipe.\n");
goto finish;
}
if ((child = fork()) < 0) {
pa_log(__FILE__": fork() failed: %s\n", strerror(errno));
goto finish;
}
if (child != 0) {
/* Father */
close(daemon_pipe[1]);
daemon_pipe[1] = -1;
if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval)) != sizeof(retval)) {
pa_log(__FILE__": read() failed: %s\n", strerror(errno));
retval = 1;
}
if (retval)
pa_log(__FILE__": daemon startup failed.\n");
else
pa_log_info(__FILE__": daemon startup successful.\n");
goto finish;
}
close(daemon_pipe[0]);
daemon_pipe[0] = -1;
#endif
if (conf->auto_log_target)
pa_log_set_target(PA_LOG_SYSLOG, NULL);
#ifdef HAVE_SETSID
setsid();
#endif
#ifdef HAVE_SETPGID
setpgid(0,0);
#endif
#ifndef OS_IS_WIN32
close(0);
close(1);
close(2);
open("/dev/null", O_RDONLY);
open("/dev/null", O_WRONLY);
open("/dev/null", O_WRONLY);
#else
FreeConsole();
#endif
#ifdef SIGTTOU
signal(SIGTTOU, SIG_IGN);
#endif
#ifdef SIGTTIN
signal(SIGTTIN, SIG_IGN);
#endif
#ifdef SIGTSTP
signal(SIGTSTP, SIG_IGN);
#endif
#ifdef TIOCNOTTY
if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) {
ioctl(tty_fd, TIOCNOTTY, (char*) 0);
close(tty_fd);
}
#endif
}
chdir("/");
if (conf->use_pid_file) {
if (pa_pid_file_create() < 0) {
pa_log(__FILE__": pa_pid_file_create() failed.\n");
#ifdef HAVE_FORK
if (conf->daemonize)
pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
#endif
goto finish;
}
valid_pid_file = 1;
}
mainloop = pa_mainloop_new();
assert(mainloop);
c = pa_core_new(pa_mainloop_get_api(mainloop));
assert(c);
r = pa_signal_init(pa_mainloop_get_api(mainloop));
assert(r == 0);
pa_signal_new(SIGINT, signal_callback, c);
pa_signal_new(SIGTERM, signal_callback, c);
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
#endif
#ifdef OS_IS_WIN32
defer = pa_mainloop_get_api(mainloop)->defer_new(pa_mainloop_get_api(mainloop), message_cb, NULL);
assert(defer);
#endif
if (conf->daemonize)
c->running_as_daemon = 1;
#ifdef SIGUSR1
pa_signal_new(SIGUSR1, signal_callback, c);
#endif
#ifdef SIGUSR2
pa_signal_new(SIGUSR2, signal_callback, c);
#endif
#ifdef SIGHUP
pa_signal_new(SIGHUP, signal_callback, c);
#endif
oil_init();
r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop));
assert(r == 0);
buf = pa_strbuf_new();
assert(buf);
if (conf->default_script_file)
r = pa_cli_command_execute_file(c, conf->default_script_file, buf, &conf->fail);
if (r >= 0)
r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail);
pa_log(s = pa_strbuf_tostring_free(buf));
pa_xfree(s);
if (r < 0 && conf->fail) {
pa_log(__FILE__": failed to initialize daemon.\n");
#ifdef HAVE_FORK
if (conf->daemonize)
pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
#endif
} else if (!c->modules || pa_idxset_size(c->modules) == 0) {
pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n");
#ifdef HAVE_FORK
if (conf->daemonize)
pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
#endif
} else {
retval = 0;
#ifdef HAVE_FORK
if (conf->daemonize)
pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
#endif
c->disallow_module_loading = conf->disallow_module_loading;
c->exit_idle_time = conf->exit_idle_time;
c->module_idle_time = conf->module_idle_time;
c->scache_idle_time = conf->scache_idle_time;
c->resample_method = conf->resample_method;
if (c->default_sink_name &&
pa_namereg_get(c, c->default_sink_name, PA_NAMEREG_SINK, 1) == NULL) {
pa_log_error("%s : Fatal error. Default sink name (%s) does not exist in name register.\n", __FILE__, c->default_sink_name);
retval = 1;
} else {
pa_log_info(__FILE__": Daemon startup complete.\n");
if (pa_mainloop_run(mainloop, &retval) < 0)
retval = 1;
pa_log_info(__FILE__": Daemon shutdown initiated.\n");
}
}
#ifdef OS_IS_WIN32
pa_mainloop_get_api(mainloop)->defer_free(defer);
#endif
pa_core_free(c);
pa_cpu_limit_done();
pa_signal_done();
pa_mainloop_free(mainloop);
pa_log_info(__FILE__": Daemon terminated.\n");
finish:
if (conf)
pa_daemon_conf_free(conf);
if (valid_pid_file)
pa_pid_file_remove();
close_pipe(daemon_pipe);
#ifdef OS_IS_WIN32
WSACleanup();
#endif
lt_dlexit();
return retval;
}