diff --git a/src/main.c b/src/main.c
index c6994cbd..b3e4900c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -19,67 +19,32 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/**
- * @file main.c
- *
- * Driver for mt-daapd, including the main() function. This
- * is responsible for kicking off the initial mp3 scan, starting
- * up the signal handler, starting up the webserver, and waiting
- * around for external events to happen (like a request to rescan,
- * or a background rescan to take place.)
- *
- * It also contains the daap handling callback for the webserver.
- * This should almost certainly be somewhere else, and is in
- * desparate need of refactoring, but somehow continues to be in
- * this files.
- */
-
-/** @mainpage mt-daapd
- * @section about_section About
- *
- * This is mt-daapd, an attempt to create an iTunes server for
- * linux and other POSIXish systems. Maybe even Windows with cygwin,
- * eventually.
- *
- * You might check these locations for more info:
- * - Home page
- * - Project page on SourceForge
- *
- */
-
#ifdef HAVE_CONFIG_H
-# include "config.h"
+# include
#endif
-#include
-#include
-#include
-#include
-#include
-#include
-#ifdef HAVE_STDINT_H
-#include
-#endif
#include
#include
+#include
#include
-#ifdef HAVE_DIRENT_H
-#include
-#endif
-#ifdef HAVE_UNISTD_H
-# include
-#endif
-
+#include
+#include
#include
#include
-#ifdef HAVE_SYS_WAIT_H
#include
-#endif
-#include
-
+#include
+#include
#include
#include
+#include
+
+#include
+
+#include
+#include
+#include
+
#include "conffile.h"
#include "logger.h"
#include "misc.h"
@@ -88,61 +53,32 @@
#include "db-generic.h"
#include "mdns_avahi.h"
-#ifdef HAVE_GETOPT_H
-# include "getopt.h"
-#endif
-#include
-#include
-
-
-/** Seconds to sleep before checking for a shutdown or reload */
-#define MAIN_SLEEP_INTERVAL 2
-
-/** Let's hope if you have no atoll, you only have 32 bit inodes... */
-#if !HAVE_ATOLL
-# define atoll(a) atol(a)
-#endif
-
-#ifndef PIDFILE
#define PIDFILE "/var/run/mt-daapd.pid"
-#endif
-/*
- * Globals
- */
struct event_base *evbase_main;
static int main_exit;
-/*
- * Forwards
- */
-static void usage(char *program);
-
-/**
- * Print usage information to stdout
- *
- * \param program name of program (argv[0])
- */
-void usage(char *program) {
- printf("Usage: %s [options]\n\n",program);
- printf("Options:\n");
- printf(" -d Log level (0-5)\n");
- printf(" -D Log domains\n");
- printf(" -c Use configfile specified\n");
- printf(" -P Write the PID to specified file\n");
- printf(" -f Run in foreground\n");
- printf(" -y Yes, go ahead and run as non-root user\n");
- printf(" -b ffid to be broadcast\n");
- printf(" -v Display version information\n");
- printf("\n\n");
- printf("Available log domains:\n");
- logger_domains();
- printf("\n\n");
+static void
+usage(char *program)
+{
+ printf("Usage: %s [options]\n\n",program);
+ printf("Options:\n");
+ printf(" -d Log level (0-5)\n");
+ printf(" -D Log domains\n");
+ printf(" -c Use as the configfile\n");
+ printf(" -P Write PID to specified file\n");
+ printf(" -f Run in foreground\n");
+ printf(" -y Start even if user is not root\n");
+ printf(" -b ffid to be broadcast\n");
+ printf(" -v Display version information\n");
+ printf("\n\n");
+ printf("Available log domains:\n");
+ logger_domains();
+ printf("\n\n");
}
-
static int
daemonize(int background, char *runas, char *pidfile)
{
@@ -270,12 +206,12 @@ signal_cb(int fd, short event, void *arg)
struct signalfd_siginfo info;
int status;
- sa_ign.sa_handler=SIG_IGN;
- sa_ign.sa_flags=0;
+ sa_ign.sa_handler = SIG_IGN;
+ sa_ign.sa_flags = 0;
sigemptyset(&sa_ign.sa_mask);
- sa_dfl.sa_handler=SIG_DFL;
- sa_dfl.sa_flags=0;
+ sa_dfl.sa_handler = SIG_DFL;
+ sa_dfl.sa_flags = 0;
sigemptyset(&sa_dfl.sa_mask);
while (read(fd, &info, sizeof(struct signalfd_siginfo)) > 0)
@@ -309,348 +245,339 @@ signal_cb(int fd, short event, void *arg)
event_base_loopbreak(evbase_main);
}
-/**
- * Kick off the daap server and wait for events.
- *
- * This starts the initial db scan, sets up the signal
- * handling, starts the webserver, then sits back and waits
- * for events, as notified by the signal handler and the
- * web interface. These events are communicated via flags
- * in the config structure.
- *
- * \param argc count of command line arguments
- * \param argv command line argument pointers
- * \returns 0 on success, -1 otherwise
- *
- * \todo split out a ws_init and ws_start, so that the
- * web space handlers can be registered before the webserver
- * starts.
- *
- */
-int main(int argc, char *argv[]) {
- int option;
- char *configfile=CONFFILE;
- int reload=0;
- int background;
- int force_non_root=0;
- int skip_initial=1;
- cfg_t *lib;
- char *runas, *tmp;
- int port;
- char *servername;
- char *ffid = NULL;
- char *perr=NULL;
- char *txtrecord[10];
- char *pidfile = PIDFILE;
- sigset_t sigs;
- int sigfd;
- struct event sig_event;
- int ret;
- int i;
- int err;
+int
+main(int argc, char **argv)
+{
+ int option;
+ char *configfile = CONFFILE;
+ int reload = 0;
+ int background;
+ int force_non_root = 0;
+ int skip_initial = 1;
+ cfg_t *lib;
+ char *runas, *tmp;
+ int port;
+ char *servername;
+ char *ffid = NULL;
+ char *perr = NULL;
+ char *txtrecord[10];
+ char *pidfile = PIDFILE;
+ sigset_t sigs;
+ int sigfd;
+ struct event sig_event;
+ int ret;
+ int i;
- int loglevel = -1;
- char *logdomains = NULL;
- char *logfile = NULL;
+ int loglevel = -1;
+ char *logdomains = NULL;
+ char *logfile = NULL;
- background = 1;
+ background = 1;
- while((option=getopt(argc,argv,"D:d:c:P:frysiub:v")) != -1) {
- switch(option) {
- case 'b':
- ffid=optarg;
+ while ((option = getopt(argc, argv, "D:d:c:P:frysiub:v")) != -1)
+ {
+ switch (option)
+ {
+ case 'b':
+ ffid = optarg;
break;
- case 'd':
- loglevel = atoi(optarg);
+ case 'd':
+ ret = safe_atoi(optarg, &i);
+ if (ret < 0)
+ fprintf(stderr, "Error: loglevel must be an integer in '-d %s'\n", optarg);
+ else
+ loglevel = i;
break;
- case 'D':
+ case 'D':
logdomains = optarg;
break;
- case 'f':
+ case 'f':
background = 0;
break;
- case 'c':
- configfile=optarg;
+ case 'c':
+ configfile = optarg;
break;
- case 'P':
+ case 'P':
pidfile = optarg;
break;
- case 'r':
- reload=1;
+ case 'r':
+ reload = 1;
break;
- case 's':
- skip_initial=0;
+ case 's':
+ skip_initial = 0;
break;
- case 'y':
- force_non_root=1;
+ case 'y':
+ force_non_root = 1;
break;
- case 'v':
- fprintf(stderr,"Firefly Media Server: Version %s\n",VERSION);
+ case 'v':
+ fprintf(stdout, "Firefly Media Server: Version %s\n",VERSION);
exit(EXIT_SUCCESS);
break;
- default:
+ default:
usage(argv[0]);
exit(EXIT_FAILURE);
break;
}
}
- if((getuid()) && (!force_non_root)) {
- fprintf(stderr,"You are not root. This is almost certainly wrong. "
- "If you are\nsure you want to do this, use the -y "
- "command-line switch\n");
- exit(EXIT_FAILURE);
+ if ((getuid() != 0) && (!force_non_root))
+ {
+ fprintf(stderr, "You are not root. This is almost certainly wrong. "
+ "If you are\nsure you want to do this, use the -y "
+ "command-line switch\n");
+ exit(EXIT_FAILURE);
}
- ret = logger_init(NULL, NULL, (loglevel < 0) ? E_LOG : loglevel);
- if (ret != 0)
- {
- fprintf(stderr, "Could not initialize log facility\n");
+ ret = logger_init(NULL, NULL, (loglevel < 0) ? E_LOG : loglevel);
+ if (ret != 0)
+ {
+ fprintf(stderr, "Could not initialize log facility\n");
- exit(EXIT_FAILURE);
- }
-
- ret = conffile_load(configfile);
- if (ret != 0)
- {
- DPRINTF(E_FATAL, L_MAIN, "Config file errors; please fix your config\n");
-
- logger_deinit();
- exit(EXIT_FAILURE);
- }
-
- logger_deinit();
-
- /* Reinit log facility with configfile values */
- if (loglevel < 0)
- loglevel = cfg_getint(cfg_getsec(cfg, "general"), "loglevel");
-
- logfile = cfg_getstr(cfg_getsec(cfg, "general"), "logfile");
-
- ret = logger_init(logfile, logdomains, loglevel);
- if (ret != 0)
- {
- fprintf(stderr, "Could not reinitialize log facility with config file settings\n");
-
- conffile_unload();
- exit(EXIT_FAILURE);
- }
-
- /* Set up libevent logging callback */
- event_set_log_callback(logger_libevent);
-
- DPRINTF(E_LOG, L_MAIN, "Firefly Version %s taking off\n", VERSION);
-
- /* initialize ffmpeg */
- av_register_all();
-
- /* Block signals for all threads except the main one */
- sigemptyset(&sigs);
- sigaddset(&sigs, SIGINT);
- sigaddset(&sigs, SIGHUP);
- sigaddset(&sigs, SIGCHLD);
- sigaddset(&sigs, SIGTERM);
- sigaddset(&sigs, SIGPIPE);
- ret = pthread_sigmask(SIG_BLOCK, &sigs, NULL);
- if (ret != 0)
- {
- DPRINTF(E_LOG, L_MAIN, "Error setting signal set\n");
-
- conffile_unload();
- logger_deinit();
- exit(EXIT_FAILURE);
- }
-
- /* Daemonize and drop privileges */
- runas = cfg_getstr(cfg_getsec(cfg, "general"), "uid");
-
- ret = daemonize(background, runas, pidfile);
- if (ret < 0)
- {
- DPRINTF(E_LOG, L_MAIN, "Could not initialize server\n");
-
- conffile_unload();
- logger_deinit();
- exit(EXIT_FAILURE);
- }
-
- /* Initialize libevent (after forking) */
- evbase_main = event_init();
-
- DPRINTF(E_LOG, L_MAIN, "mDNS init\n");
- ret = mdns_init();
- if (ret != 0)
- {
- DPRINTF(E_FATAL, L_MAIN, "mDNS init failed\n");
-
- conffile_unload();
- logger_deinit();
- exit(EXIT_FAILURE);
- }
-
- /* this will require that the db be readable by the runas user */
- err = db_open(&perr, "sqlite3", "/var/cache/mt-daapd"); /* FIXME */
-
- if(err) {
- DPRINTF(E_LOG,L_MAIN,"Error opening db: %s\n",perr);
-
- mdns_deinit();
- conffile_unload();
- logger_deinit();
- exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
- /* Initialize the database before starting */
- DPRINTF(E_LOG,L_MAIN,"Initializing database\n");
- if(db_init(reload)) {
- DPRINTF(E_FATAL,L_MAIN,"Error in db_init: %s\n",strerror(errno));
+ ret = conffile_load(configfile);
+ if (ret != 0)
+ {
+ DPRINTF(E_FATAL, L_MAIN, "Config file errors; please fix your config\n");
+
+ logger_deinit();
+ exit(EXIT_FAILURE);
}
- /* Spawn file scanner thread */
- ret = filescanner_init();
- if (ret != 0)
- {
- DPRINTF(E_FATAL, L_MAIN, "File scanner thread failed to start\n");
+ logger_deinit();
- mdns_deinit();
- db_deinit();
- conffile_unload();
- logger_deinit();
- exit(EXIT_FAILURE);
- }
+ /* Reinit log facility with configfile values */
+ if (loglevel < 0)
+ loglevel = cfg_getint(cfg_getsec(cfg, "general"), "loglevel");
- /* Spawn HTTPd thread */
- ret = httpd_init();
- if (ret != 0)
- {
- DPRINTF(E_FATAL, L_MAIN, "HTTPd thread failed to start\n");
+ logfile = cfg_getstr(cfg_getsec(cfg, "general"), "logfile");
- filescanner_deinit();
- mdns_deinit();
- db_deinit();
- conffile_unload();
- logger_deinit();
- exit(EXIT_FAILURE);
- }
+ ret = logger_init(logfile, logdomains, loglevel);
+ if (ret != 0)
+ {
+ fprintf(stderr, "Could not reinitialize log facility with config file settings\n");
- /* Register mDNS services */
- lib = cfg_getnsec(cfg, "library", 0);
+ conffile_unload();
+ exit(EXIT_FAILURE);
+ }
- servername = cfg_getstr(lib, "name");
+ /* Set up libevent logging callback */
+ event_set_log_callback(logger_libevent);
- for (i = 0; i < (sizeof(txtrecord) / sizeof(*txtrecord) - 1); i++)
- {
- txtrecord[i] = (char *)malloc(128);
- if (!txtrecord[i])
- {
- DPRINTF(E_FATAL, L_MAIN, "Out of memory for TXT record\n");
+ DPRINTF(E_LOG, L_MAIN, "Firefly Version %s taking off\n", VERSION);
- httpd_deinit();
- filescanner_deinit();
- mdns_deinit();
- db_deinit();
- conffile_unload();
- logger_deinit();
- exit(EXIT_FAILURE);
- }
+ /* initialize ffmpeg */
+ av_register_all();
- memset(txtrecord[i], 0, 128);
- }
+ /* Block signals for all threads except the main one */
+ sigemptyset(&sigs);
+ sigaddset(&sigs, SIGINT);
+ sigaddset(&sigs, SIGHUP);
+ sigaddset(&sigs, SIGCHLD);
+ sigaddset(&sigs, SIGTERM);
+ sigaddset(&sigs, SIGPIPE);
+ ret = pthread_sigmask(SIG_BLOCK, &sigs, NULL);
+ if (ret != 0)
+ {
+ DPRINTF(E_LOG, L_MAIN, "Error setting signal set\n");
- snprintf(txtrecord[0], 128, "txtvers=1");
- snprintf(txtrecord[1], 128, "Database ID=%0X", djb_hash(servername, strlen(servername)));
- snprintf(txtrecord[2], 128, "Machine ID=%0X", djb_hash(servername, strlen(servername)));
- snprintf(txtrecord[3], 128, "Machine Name=%s", servername);
- snprintf(txtrecord[4], 128, "mtd-version=%s", VERSION);
- snprintf(txtrecord[5], 128, "iTSh Version=131073"); /* iTunes 6.0.4 */
- snprintf(txtrecord[6], 128, "Version=196610"); /* iTunes 6.0.4 */
+ conffile_unload();
+ logger_deinit();
+ exit(EXIT_FAILURE);
+ }
- tmp = cfg_getstr(lib, "password");
- snprintf(txtrecord[7], 128, "Password=%s", (tmp) ? "true" : "false");
+ /* Daemonize and drop privileges */
+ runas = cfg_getstr(cfg_getsec(cfg, "general"), "uid");
- srand((unsigned int)time(NULL));
+ ret = daemonize(background, runas, pidfile);
+ if (ret < 0)
+ {
+ DPRINTF(E_LOG, L_MAIN, "Could not initialize server\n");
- if (ffid)
- snprintf(txtrecord[8], 128, "ffid=%s", ffid);
- else
- snprintf(txtrecord[8], 128, "ffid=%08x", rand());
+ conffile_unload();
+ logger_deinit();
+ exit(EXIT_FAILURE);
+ }
- txtrecord[9] = NULL;
+ /* Initialize libevent (after forking) */
+ evbase_main = event_init();
- DPRINTF(E_LOG,L_MAIN,"Registering rendezvous names\n");
+ DPRINTF(E_LOG, L_MAIN, "mDNS init\n");
+ ret = mdns_init();
+ if (ret != 0)
+ {
+ DPRINTF(E_FATAL, L_MAIN, "mDNS init failed\n");
- port = cfg_getint(lib, "port");
+ conffile_unload();
+ logger_deinit();
+ exit(EXIT_FAILURE);
+ }
- /* Register web server service */
- mdns_register(servername, "_http._tcp", port, txtrecord);
- /* Register RSP service */
- mdns_register(servername, "_rsp._tcp", port, txtrecord);
- /* Register DAAP service */
- mdns_register(servername, "_daap._tcp", port, txtrecord);
+ /* this will require that the db be readable by the runas user */
+ ret = db_open(&perr, "sqlite3", "/var/cache/mt-daapd"); /* FIXME */
- for (i = 0; i < (sizeof(txtrecord) / sizeof(*txtrecord) - 1); i++)
- free(txtrecord[i]);
+ if (ret != 0)
+ {
+ DPRINTF(E_FATAL, L_MAIN, "Error opening db: %s\n", perr);
- /* Set up signal fd */
- sigfd = signalfd(-1, &sigs, SFD_NONBLOCK | SFD_CLOEXEC);
- if (sigfd < 0)
- {
- DPRINTF(E_FATAL, L_MAIN, "Could not setup signalfd: %s\n", strerror(errno));
+ mdns_deinit();
+ conffile_unload();
+ logger_deinit();
+ exit(EXIT_FAILURE);
+ }
- httpd_deinit();
- filescanner_deinit();
- mdns_deinit();
- db_deinit();
- conffile_unload();
- logger_deinit();
- exit(EXIT_FAILURE);
- }
+ /* Initialize the database before starting */
+ DPRINTF(E_INFO, L_MAIN, "Initializing database\n");
+ if (db_init(reload))
+ {
+ DPRINTF(E_FATAL, L_MAIN, "Error in db_init: %s\n", strerror(errno));
+ }
- event_set(&sig_event, sigfd, EV_READ, signal_cb, NULL);
- event_base_set(evbase_main, &sig_event);
- event_add(&sig_event, NULL);
+ /* Spawn file scanner thread */
+ ret = filescanner_init();
+ if (ret != 0)
+ {
+ DPRINTF(E_FATAL, L_MAIN, "File scanner thread failed to start\n");
- /* Run the loop */
- event_base_dispatch(evbase_main);
+ mdns_deinit();
+ db_deinit();
+ conffile_unload();
+ logger_deinit();
+ exit(EXIT_FAILURE);
+ }
- DPRINTF(E_LOG,L_MAIN,"Stopping gracefully\n");
+ /* Spawn HTTPd thread */
+ ret = httpd_init();
+ if (ret != 0)
+ {
+ DPRINTF(E_FATAL, L_MAIN, "HTTPd thread failed to start\n");
- DPRINTF(E_LOG, L_MAIN, "HTTPd deinit\n");
- httpd_deinit();
+ filescanner_deinit();
+ mdns_deinit();
+ db_deinit();
+ conffile_unload();
+ logger_deinit();
+ exit(EXIT_FAILURE);
+ }
- DPRINTF(E_LOG, L_MAIN, "File scanner deinit\n");
- filescanner_deinit();
+ /* Register mDNS services */
+ lib = cfg_getnsec(cfg, "library", 0);
- DPRINTF(E_LOG, L_MAIN, "mDNS deinit\n");
- mdns_deinit();
+ servername = cfg_getstr(lib, "name");
- conffile_unload();
+ for (i = 0; i < (sizeof(txtrecord) / sizeof(*txtrecord) - 1); i++)
+ {
+ txtrecord[i] = (char *)malloc(128);
+ if (!txtrecord[i])
+ {
+ DPRINTF(E_FATAL, L_MAIN, "Out of memory for TXT record\n");
- DPRINTF(E_LOG,L_MAIN,"Closing database\n");
- db_deinit();
+ httpd_deinit();
+ filescanner_deinit();
+ mdns_deinit();
+ db_deinit();
+ conffile_unload();
+ logger_deinit();
+ exit(EXIT_FAILURE);
+ }
- if (background)
- {
- ret = unlink(pidfile);
- if (ret < 0)
- DPRINTF(E_WARN, L_MAIN, "Could not unlink PID file %s: %s\n", pidfile, strerror(errno));
- }
+ memset(txtrecord[i], 0, 128);
+ }
- DPRINTF(E_LOG,L_MAIN,"Done!\n");
+ snprintf(txtrecord[0], 128, "txtvers=1");
+ snprintf(txtrecord[1], 128, "Database ID=%0X", djb_hash(servername, strlen(servername)));
+ snprintf(txtrecord[2], 128, "Machine ID=%0X", djb_hash(servername, strlen(servername)));
+ snprintf(txtrecord[3], 128, "Machine Name=%s", servername);
+ snprintf(txtrecord[4], 128, "mtd-version=%s", VERSION);
+ snprintf(txtrecord[5], 128, "iTSh Version=131073"); /* iTunes 6.0.4 */
+ snprintf(txtrecord[6], 128, "Version=196610"); /* iTunes 6.0.4 */
- logger_deinit();
+ tmp = cfg_getstr(lib, "password");
+ snprintf(txtrecord[7], 128, "Password=%s", (tmp) ? "true" : "false");
- return EXIT_SUCCESS;
+ srand((unsigned int)time(NULL));
+
+ if (ffid)
+ snprintf(txtrecord[8], 128, "ffid=%s", ffid);
+ else
+ snprintf(txtrecord[8], 128, "ffid=%08x", rand());
+
+ txtrecord[9] = NULL;
+
+ DPRINTF(E_LOG,L_MAIN,"Registering rendezvous names\n");
+
+ port = cfg_getint(lib, "port");
+
+ /* Register web server service */
+ mdns_register(servername, "_http._tcp", port, txtrecord);
+ /* Register RSP service */
+ mdns_register(servername, "_rsp._tcp", port, txtrecord);
+ /* Register DAAP service */
+ mdns_register(servername, "_daap._tcp", port, txtrecord);
+
+ for (i = 0; i < (sizeof(txtrecord) / sizeof(*txtrecord) - 1); i++)
+ free(txtrecord[i]);
+
+ /* Set up signal fd */
+ sigfd = signalfd(-1, &sigs, SFD_NONBLOCK | SFD_CLOEXEC);
+ if (sigfd < 0)
+ {
+ DPRINTF(E_FATAL, L_MAIN, "Could not setup signalfd: %s\n", strerror(errno));
+
+ httpd_deinit();
+ filescanner_deinit();
+ mdns_deinit();
+ db_deinit();
+ conffile_unload();
+ logger_deinit();
+ exit(EXIT_FAILURE);
+ }
+
+ event_set(&sig_event, sigfd, EV_READ, signal_cb, NULL);
+ event_base_set(evbase_main, &sig_event);
+ event_add(&sig_event, NULL);
+
+ /* Run the loop */
+ event_base_dispatch(evbase_main);
+
+ DPRINTF(E_LOG, L_MAIN, "Stopping gracefully\n");
+
+ DPRINTF(E_LOG, L_MAIN, "HTTPd deinit\n");
+ httpd_deinit();
+
+ DPRINTF(E_LOG, L_MAIN, "File scanner deinit\n");
+ filescanner_deinit();
+
+ DPRINTF(E_LOG, L_MAIN, "mDNS deinit\n");
+ mdns_deinit();
+
+ conffile_unload();
+
+ DPRINTF(E_LOG, L_MAIN, "Closing database\n");
+ db_deinit();
+
+ if (background)
+ {
+ ret = unlink(pidfile);
+ if (ret < 0)
+ DPRINTF(E_WARN, L_MAIN, "Could not unlink PID file %s: %s\n", pidfile, strerror(errno));
+ }
+
+ DPRINTF(E_LOG, L_MAIN, "Exiting.\n");
+
+ logger_deinit();
+
+ return EXIT_SUCCESS;
}
-