diff --git a/common.c b/common.c index d024c5b1..6bfe63fd 100644 --- a/common.c +++ b/common.c @@ -35,44 +35,44 @@ #include #include #include "common.h" -#include "daemon.h" +#include + shairport_cfg config; int debuglev = 0; void die(char *format, ...) { - fprintf(stderr, "FATAL: "); - + char s[1024]; + s[0]=0; va_list args; va_start(args, format); - - vfprintf(stderr, format, args); - if (config.daemonise) - daemon_fail(format, args); // Send error message to parent - + vsprintf(s,format,args); va_end(args); - - fprintf(stderr, "\n"); + daemon_log(LOG_EMERG,"%s", s); shairport_shutdown(1); } void warn(char *format, ...) { - fprintf(stderr, "WARNING: "); + char s[1024]; + s[0]=0; va_list args; va_start(args, format); - vfprintf(stderr, format, args); + vsprintf(s,format,args); va_end(args); - fprintf(stderr, "\n"); + daemon_log(LOG_WARNING,"%s", s); } void debug(int level, char *format, ...) { if (level > debuglev) return; + char s[1024]; + s[0]=0; va_list args; va_start(args, format); - vfprintf(stderr, format, args); + vsprintf(s,format,args); va_end(args); + daemon_log(LOG_DEBUG,"%s", s); } @@ -182,9 +182,10 @@ uint8_t *rsa_apply(uint8_t *input, int inlen, int *outlen, int mode) { double vol2attn(double vol, long max_db, long min_db) { // We use a little coordinate geometry to build a transfer function from the volume passed in to the device's dynamic range. +// (See the diagram in the documents folder.) // The x axis is the "volume in" which will be from -30 to 0. The y axis will be the "volume out" which will be from the bottom of the range to the top. // We build the transfer function from one or more lines. We characterise each line with two numbers: -// the first is where on x the line starts when y=0 (from 0 to -30); the second is where on y the line stops when when x is -30. +// the first is where on x the line starts when y=0 (x can be fromfrom 0 to -30); the second is where on y the line stops when when x is -30. // thus, if the line was characterised as {0,-30}, it would be an identity transfer. // Assuming, for example, a dynamic range of lv=-60 to hv=0 // Typically we'll use three lines -- a three order transfer function diff --git a/shairport.c b/shairport.c index a9e27c31..dc5884e3 100644 --- a/shairport.c +++ b/shairport.c @@ -25,6 +25,7 @@ */ #include +#include #include #include #include @@ -33,12 +34,15 @@ #include #include #include "common.h" -#include "daemon.h" #include "rtsp.h" #include "mdns.h" -// #include "getopt_long.h" -static void log_setup(); +#include +#include +#include +#include +#include + static int shutting_down = 0; @@ -51,8 +55,6 @@ void shairport_shutdown(int retval) { rtsp_shutdown_stream(); if (config.output) config.output->deinit(); - daemon_exit(); // This does nothing if not in daemon mode - exit(retval); } @@ -72,7 +74,7 @@ static void sig_child(int foo, siginfo_t *bar, void *baz) { } static void sig_logrotate(int foo, siginfo_t *bar, void *baz) { - log_setup(); +// log_setup(); } void usage(char *progname) { @@ -87,18 +89,10 @@ void usage(char *progname) { printf(" -h, --help show this help\n"); printf(" -p, --port=PORT set RTSP listening port\n"); printf(" -a, --name=NAME set advertised name\n"); - printf(" -b FILL set how full the buffer must be before audio output\n"); - printf(" starts. This value is in frames; default %d\n", config.buffer_start_fill); printf(" -L --latency=FRAMES set how many frames between a just-received frame and audio output\n"); printf(" starts. This value is in frames; default %d\n", config.latency); - printf(" -d, --daemon fork (daemonise). The PID of the child process is\n"); - printf(" written to stdout, unless a pidfile is used.\n"); - printf(" -P, --pidfile=FILE write daemon's pid to FILE on startup.\n"); - printf(" Has no effect if -d is not specified\n"); - printf(" -l, --log=FILE redirect shairport's standard output to FILE\n"); - printf(" If --error is not specified, it also redirects\n"); - printf(" error output to FILE\n"); - printf(" -e, --error=FILE redirect shairport's standard error output to FILE\n"); + printf(" -d, --daemon daemonise.\n"); + printf(" -k, --kill kill the existing shairport daemon.\n"); printf(" -B, --on-start=COMMAND run a shell command when playback begins\n"); printf(" -E, --on-stop=COMMAND run a shell command when playback ends\n"); @@ -120,9 +114,7 @@ int parse_options(int argc, char **argv) { static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"daemon", no_argument, NULL, 'd'}, - {"pidfile", required_argument, NULL, 'P'}, - {"log", required_argument, NULL, 'l'}, - {"error", required_argument, NULL, 'e'}, + {"kill", no_argument, NULL, 'k'}, {"port", required_argument, NULL, 'p'}, {"name", required_argument, NULL, 'a'}, {"output", required_argument, NULL, 'o'}, @@ -135,7 +127,7 @@ int parse_options(int argc, char **argv) { int opt; while ((opt = getopt_long(argc, argv, - "+hdvP:l:e:p:a:o:b:B:E:m:L:", + "+hdvkp:a:o:b:B:E:m:L:", long_options, NULL)) > 0) { switch (opt) { default: @@ -157,9 +149,6 @@ int parse_options(int argc, char **argv) { case 'o': config.output_name = optarg; break; - case 'b': - config.buffer_start_fill = atoi(optarg); - break; case 'L': config.latency = atoi(optarg); break; @@ -169,15 +158,6 @@ int parse_options(int argc, char **argv) { case 'E': config.cmd_stop = optarg; break; - case 'P': - config.pidfile = optarg; - break; - case 'l': - config.logfile = optarg; - break; - case 'e': - config.errfile = optarg; - break; case 'm': config.mdns_name = optarg; break; @@ -222,10 +202,11 @@ void signal_setup(void) { // should be called only once! void shairport_startup_complete(void) { if (config.daemonise) { - daemon_ready(); +// daemon_ready(); } } +/* void log_setup() { if (config.logfile) { int log_fd = open(config.logfile, @@ -254,9 +235,47 @@ void log_setup() { setvbuf (stderr, NULL, _IOLBF, BUFSIZ); } } - +*/ int main(int argc, char **argv) { - signal_setup(); + + pid_t pid; + daemon_set_verbosity(LOG_DEBUG); + + /* Reset signal handlers */ + if (daemon_reset_sigs(-1) < 0) { + daemon_log(LOG_ERR, "Failed to reset all signal handlers: %s", strerror(errno)); + return 1; + } + + /* Unblock signals */ + if (daemon_unblock_sigs(-1) < 0) { + daemon_log(LOG_ERR, "Failed to unblock all signals: %s", strerror(errno)); + return 1; + } + + /* Set indentification string for the daemon for both syslog and PID file */ + daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]); + + /* Check if we are called with -k parameter */ + if (argc >= 2 && !strcmp(argv[1], "-k")) { + int ret; + + /* Kill daemon with SIGTERM */ + + /* Check if the new function daemon_pid_file_kill_wait() is available, if it is, use it. */ + if ((ret = daemon_pid_file_kill_wait(SIGTERM, 5)) < 0) + daemon_log(LOG_WARNING, "Failed to kill daemon: %s", strerror(errno)); + else + daemon_pid_file_remove(); // + return ret < 0 ? 1 : 0; + } + + /* Check that the daemon is not running twice at the same time */ + if ((pid = daemon_pid_file_is_running()) >= 0) { + daemon_log(LOG_ERR, "Daemon already running on PID file %u", pid); + return 1; + } + memset(&config, 0, sizeof(config)); // set defaults @@ -266,7 +285,7 @@ int main(int argc, char **argv) { char hostname[100]; gethostname(hostname, 100); config.apname = malloc(20 + 100); - snprintf(config.apname, 20 + 100, "Shairport on %s", hostname); + snprintf(config.apname, 20 + 100, "Shairport Sync on %s", hostname); // parse arguments into config int audio_arg = parse_options(argc, argv); @@ -274,12 +293,62 @@ int main(int argc, char **argv) { // mDNS supports maximum of 63-character names (we append 13). if (strlen(config.apname) > 50) die("Supplied name too long (max 50 characters)"); - + + + /* here, daemonise with libdaemon */ + if (config.daemonise) { - daemon_init(); + /* Prepare for return value passing from the initialization procedure of the daemon process */ + if (daemon_retval_init() < 0) { + daemon_log(LOG_ERR, "Failed to create pipe."); + return 1; + } + + /* Do the fork */ + if ((pid = daemon_fork()) < 0) { + + /* Exit on error */ + daemon_retval_done(); + return 1; + + } else if (pid) { /* The parent */ + int ret; + + /* Wait for 20 seconds for the return value passed from the daemon process */ + if ((ret = daemon_retval_wait(20)) < 0) { + daemon_log(LOG_ERR, "Could not recieve return value from daemon process: %s", strerror(errno)); + return 255; + } + + if (ret != 0) + daemon_log(ret != 0 ? LOG_ERR : LOG_INFO, "Daemon returned %i as return value.", ret); + return ret; + + } else { /* The daemon */ + + /* Close FDs */ + if (daemon_close_all(-1) < 0) { + daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno)); + + /* Send the error condition to the parent process */ + daemon_retval_send(1); + goto finish; + } + + /* Create the PID file */ + if (daemon_pid_file_create() < 0) { + daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno)); + daemon_retval_send(2); + goto finish; + } + + /* Send OK to parent process */ + daemon_retval_send(0); + } + /* end libdaemon stuff */ } - log_setup(); + signal_setup(); config.output = audio_get_output(config.output_name); if (!config.output) { @@ -300,5 +369,11 @@ int main(int argc, char **argv) { // should not. shairport_shutdown(1); - return 1; +finish: + daemon_log(LOG_INFO, "Exiting..."); + daemon_retval_send(255); + daemon_pid_file_remove(); + +// return 1; + }