audiod: Demote severity level of command errors.
[paraslash.git] / audiod.c
index 74d0ce233b46407c208022229df9a5da26e88f3b..119adbc0be2ddbf24a7d06de4b77a5a3d88bd230 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -1,8 +1,4 @@
-/*
- * Copyright (C) 2005 Andre Noll <maan@tuebingen.mpg.de>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
+/* Copyright (C) 2005 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
 
 /** \file audiod.c The paraslash's audio daemon. */
 
@@ -21,6 +17,7 @@
 #include "recv_cmd.lsg.h"
 #include "para.h"
 #include "error.h"
+#include "lsu.h"
 #include "crypt.h"
 #include "list.h"
 #include "sched.h"
@@ -109,9 +106,7 @@ struct slot_info {
  * para_audiod uses \p MAX_STREAM_SLOTS different slots, each of which may
  * be associated with a receiver/filter/writer triple. This array holds all
  * information on the status of these slots.
- *
- * \sa struct slot_info
- * */
+ */
 struct slot_info slot[MAX_STREAM_SLOTS];
 
 /** The vss status flags audiod is interested in. */
@@ -167,8 +162,8 @@ struct status_task {
 char *stat_item_values[NUM_STAT_ITEMS] = {NULL};
 
 /**
- * the current mode of operation of which can be changed by the on/off/cycle
- * commands. It is either, AUDIOD_OFF, AUDIOD_ON or AUDIOD_STANDBY.
+ * The current mode of operation (AUDIOD_OFF, AUDIOD_ON or AUDIOD_STANDBY).
+ * Set by the on/off/cycle commands.
  */
 int audiod_status = AUDIOD_ON;
 
@@ -179,20 +174,20 @@ static struct status_task status_task_struct;
 static uid_t *uid_whitelist;
 
 /**
- * the task that calls the status command of para_server
+ * The task that calls the status command of para_server.
  *
- * \sa struct status_task
+ * \sa \ref struct status_task.
  */
 static struct status_task *stat_task = &status_task_struct;
 
 struct command_task {
        /** The local listening socket. */
        int fd;
-       /** the associated task structure */
+       /** The associated task structure. */
        struct task *task;
 };
 
-/** iterate over all supported audio formats */
+/** Iterate over all supported audio formats. */
 #define FOR_EACH_AUDIO_FORMAT(af) for (af = 0; af < NUM_AUDIO_FORMATS; af++)
 
 /**
@@ -384,81 +379,36 @@ empty:
 
 static void parse_config_or_die(void)
 {
-       int ret;
-       char *cf, *errctx = NULL;
-       void *map;
-       size_t sz;
+       int i, ret;
+       uint32_t n;
 
-       if (OPT_GIVEN(CONFIG_FILE))
-               cf = para_strdup(OPT_STRING_VAL(CONFIG_FILE));
-       else {
-               char *home = para_homedir();
-               cf = make_message("%s/.paraslash/audiod.conf", home);
-               free(home);
-       }
-       ret = mmap_full_file(cf, O_RDONLY, &map, &sz, NULL);
+       ret = lsu_merge_config_file_options(OPT_STRING_VAL(CONFIG_FILE),
+               "audiod.conf", &lpr, CMD_PTR, audiod_suite, 0U /* flags */);
        if (ret < 0) {
-               if (ret != -E_EMPTY && ret != -ERRNO_TO_PARA_ERROR(ENOENT))
-                       goto free_cf;
-               if (ret == -ERRNO_TO_PARA_ERROR(ENOENT) && OPT_GIVEN(CONFIG_FILE))
-                       goto free_cf;
-       } else {
-               int cf_argc;
-               char **cf_argv;
-               struct lls_parse_result *cf_lpr, *merged_lpr;
-               ret = lls(lls_convert_config(map, sz, NULL, &cf_argv, &errctx));
-               para_munmap(map, sz);
-               if (ret < 0)
-                       goto free_cf;
-               cf_argc = ret;
-               ret = lls(lls_parse(cf_argc, cf_argv, CMD_PTR, &cf_lpr, &errctx));
-               lls_free_argv(cf_argv);
-               if (ret < 0)
-                       goto free_cf;
-               ret = lls(lls_merge(lpr, cf_lpr, CMD_PTR, &merged_lpr,
-                       &errctx));
-               lls_free_parse_result(cf_lpr, CMD_PTR);
-               if (ret < 0)
-                       goto free_cf;
-               lls_free_parse_result(lpr, CMD_PTR);
-               lpr = merged_lpr;
+               PARA_EMERG_LOG("failed to parse config file: %s\n",
+                       para_strerror(-ret));
+               exit(EXIT_FAILURE);
        }
        daemon_set_loglevel(ENUM_STRING_VAL(LOGLEVEL));
-       if (OPT_GIVEN(USER_ALLOW)) {
-               uint32_t n = OPT_GIVEN(USER_ALLOW);
-               int i;
-
-               uid_whitelist = para_malloc(n * sizeof(uid_t));
-               for (i = 0; i < n; i++) {
-                       const char *arg = lls_string_val(i,
-                               OPT_RESULT(USER_ALLOW));
-                       int32_t val;
-                       struct passwd *pw;
-                       ret = para_atoi32(arg, &val);
-                       if (ret >= 0) {
-                               uid_whitelist[i] = val;
-                               continue;
-                       }
-                       errno = 0; /* see getpwnam(3) */
-                       pw = getpwnam(arg);
-                       if (!pw) {
-                               PARA_EMERG_LOG("invalid username: %s\n", arg);
-                               free(uid_whitelist);
-                               goto free_cf;
-                       }
-                       uid_whitelist[i] = pw->pw_uid;
+       n = OPT_GIVEN(USER_ALLOW);
+       if (n == 0)
+               return;
+       uid_whitelist = para_malloc(n * sizeof(uid_t));
+       for (i = 0; i < n; i++) {
+               const char *arg = lls_string_val(i, OPT_RESULT(USER_ALLOW));
+               int32_t val;
+               struct passwd *pw;
+               ret = para_atoi32(arg, &val);
+               if (ret >= 0) {
+                       uid_whitelist[i] = val;
+                       continue;
                }
-       }
-       ret = 0;
-free_cf:
-       free(cf);
-       if (ret < 0) {
-               if (errctx)
-                       PARA_ERROR_LOG("%s\n", errctx);
-               free(errctx);
-               lls_free_parse_result(lpr, CMD_PTR);
-               PARA_EMERG_LOG("%s\n", para_strerror(-ret));
-               exit(EXIT_FAILURE);
+               pw = getpwnam(arg);
+               if (!pw) {
+                       PARA_EMERG_LOG("invalid username: %s\n", arg);
+                       exit(EXIT_FAILURE);
+               }
+               uid_whitelist[i] = pw->pw_uid;
        }
 }
 
@@ -495,7 +445,8 @@ static void close_receiver(int slot_num)
        task_reap(&s->receiver_node->task);
        free(s->receiver_node);
        s->receiver_node = NULL;
-       stat_task->current_audio_format_num = -1;
+       if (audiod_status == AUDIOD_ON)
+               stat_task->current_audio_format_num = -1;
        tv_add(now, &(struct timeval)EMBRACE(0, 200 * 1000),
                &a->restart_barrier);
 }
@@ -529,6 +480,23 @@ static void close_writers(struct slot_info *s)
        s->wns = NULL;
 }
 
+static void notify_writers(int error)
+{
+       int i;
+
+       FOR_EACH_SLOT(i) {
+               struct slot_info *s = slot + i;
+               struct audio_format_info *a;
+               int j;
+
+               if (s->format < 0)
+                       continue;
+               a = afi + s->format;
+               for (j = 0; j < a->num_writers; j++)
+                       task_notify(s->wns[j].task, error);
+       }
+}
+
 static void close_filters(struct slot_info *s)
 {
        int i;
@@ -668,6 +636,7 @@ static int open_receiver(int format)
                EMBRACE(.name = name, .context = rn));
        ret = r->open(rn);
        if (ret < 0) {
+               PARA_ERROR_LOG("could not open %s receiver\n", name);
                btr_remove_node(&rn->btrn);
                free(rn);
                return ret;
@@ -780,8 +749,8 @@ static void compute_time_diff(const struct timeval *status_time)
        if (count > 5) {
                int s = tv_diff(&diff, &stat_task->sa_time_diff, &tmp);
                if (tv_diff(&max_deviation, &tmp, NULL) < 0)
-                       PARA_WARNING_LOG("time diff jump: %lums\n",
-                               s * tv2ms(&tmp));
+                       PARA_WARNING_LOG("time diff jump: %c%lums\n",
+                               s < 0? '-' : '+', tv2ms(&tmp));
        }
        count++;
        sa_time_diff_sign = tv_convex_combination(
@@ -803,38 +772,38 @@ static int update_item(int itemnum, char *buf)
 {
        long unsigned sec, usec;
 
-       if (stat_task->clock_diff_count && itemnum != SI_CURRENT_TIME)
+       if (stat_task->clock_diff_count && itemnum != SI_current_time)
                return 1;
        free(stat_item_values[itemnum]);
        stat_item_values[itemnum] = para_strdup(buf);
        stat_client_write_item(itemnum);
        switch (itemnum) {
-       case SI_STATUS_FLAGS:
+       case SI_status_flags:
                stat_task->vss_status = 0;
                if (strchr(buf, 'N'))
                        stat_task->vss_status |= VSS_STATUS_FLAG_NEXT;
                if (strchr(buf, 'P'))
                        stat_task->vss_status |= VSS_STATUS_FLAG_PLAYING;
                break;
-       case SI_OFFSET:
+       case SI_offset:
                stat_task->offset_seconds = atoi(buf);
                break;
-       case SI_SECONDS_TOTAL:
+       case SI_seconds_total:
                stat_task->length_seconds = atoi(buf);
                break;
-       case SI_STREAM_START:
+       case SI_stream_start:
                if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) {
                        stat_task->server_stream_start.tv_sec = sec;
                        stat_task->server_stream_start.tv_usec = usec;
                }
                break;
-       case SI_CURRENT_TIME:
+       case SI_current_time:
                if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) {
                        struct timeval tv = {sec, usec};
                        compute_time_diff(&tv);
                }
                break;
-       case SI_FORMAT:
+       case SI_format:
                stat_task->current_audio_format_num
                        = get_audio_format_num(buf);
        }
@@ -850,7 +819,7 @@ static int parse_stream_command(const char *txt, const char **cmd)
                return -E_MISSING_COLON;
        *cmd = p + 1;
        len = p - txt;
-       re = malloc(len + 1);
+       re = para_malloc(len + 1);
        strncpy(re, txt, len);
        re[len] = '\0';
        ret = get_matching_audio_format_nums(re);
@@ -1099,7 +1068,7 @@ static int signal_post_select(struct sched *s, void *context)
        case SIGINT:
        case SIGTERM:
        case SIGHUP:
-               PARA_NOTICE_LOG("received signal %d\n", signum);
+               PARA_WARNING_LOG("terminating on signal %d\n", signum);
                task_notify_all(s, E_AUDIOD_SIGNAL);
                return -E_AUDIOD_SIGNAL;
        }
@@ -1125,7 +1094,7 @@ static int command_post_select(struct sched *s, void *context)
                return ret;
        ret = handle_connect(ct->fd, &s->rfds);
        if (ret < 0) {
-               PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+               PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
                if (ret == -E_AUDIOD_TERM) {
                        task_notify_all(s, -ret);
                        return ret;
@@ -1266,8 +1235,9 @@ static void start_stop_decoders(void)
        struct slot_info *sl;
 
        close_unused_slots();
-       if (audiod_status != AUDIOD_ON ||
-                       !(stat_task->vss_status & VSS_STATUS_FLAG_PLAYING))
+       if (audiod_status != AUDIOD_ON)
+               return notify_writers(E_NOT_PLAYING);
+       if (!(stat_task->vss_status & VSS_STATUS_FLAG_PLAYING))
                return notify_receivers(E_NOT_PLAYING);
        if (!must_start_decoder())
                return;
@@ -1386,10 +1356,10 @@ static int status_post_select(struct sched *s, void *context)
                client_open(argc, argv, &st->ct, NULL, NULL, st->btrn, s);
                set_stat_task_restart_barrier(5);
        }
-       free(stat_item_values[SI_BASENAME]);
-       stat_item_values[SI_BASENAME] = para_strdup(
+       free(stat_item_values[SI_basename]);
+       stat_item_values[SI_basename] = para_strdup(
                "no connection to para_server");
-       stat_client_write_item(SI_BASENAME);
+       stat_client_write_item(SI_basename);
        st->last_status_read = *now;
 out:
        start_stop_decoders();
@@ -1498,9 +1468,8 @@ int main(int argc, char *argv[])
        version_handle_flag("audiod", OPT_GIVEN(VERSION));
        handle_help_flags();
        parse_config_or_die();
-       init_random_seed_or_die();
+       crypt_init();
        daemon_set_priority(OPT_UINT32_VAL(PRIORITY));
-       recv_init();
        if (daemon_init_colors_or_die(OPT_UINT32_VAL(COLOR), COLOR_AUTO,
                        COLOR_NO, OPT_GIVEN(LOGFILE))) {
                for (i = 0; i < OPT_GIVEN(LOG_COLOR); i++)
@@ -1547,7 +1516,7 @@ int main(int argc, char *argv[])
        audiod_cleanup();
        sched_shutdown(&sched);
        signal_shutdown(signal_task);
-
+       crypt_shutdown();
 out:
        lls_free_parse_result(lpr, CMD_PTR);
        if (errctx)