Convert para_audiod to lopsub.
authorAndre Noll <maan@tuebingen.mpg.de>
Sat, 27 Aug 2016 13:05:13 +0000 (15:05 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 26 Mar 2017 09:02:28 +0000 (11:02 +0200)
This commit replaces the gengetopt file for para_audiod by a lopsub
suite, introducing several new files in m/lls/include which correspond
to options also needed by para_server (which has not been converted
to lopsub yet).

The audiod_status_info enumeration is now provided by lopsub and can
be removed from audiod.h.

The patch also  adds a new description section to the manual page
para_audiod(1).

14 files changed:
Makefile.real
audiod.c
audiod.h
audiod_command.c
configure.ac
m4/gengetopt/audiod.m4 [deleted file]
m4/lls/audiod.suite.m4 [new file with mode: 0644]
m4/lls/include/color.m4 [new file with mode: 0644]
m4/lls/include/daemon.m4 [new file with mode: 0644]
m4/lls/include/group.m4 [new file with mode: 0644]
m4/lls/include/log-timing.m4 [new file with mode: 0644]
m4/lls/include/logfile.m4 [new file with mode: 0644]
m4/lls/include/priority.m4 [new file with mode: 0644]
m4/lls/include/user.m4 [new file with mode: 0644]

index 799bbad..d456201 100644 (file)
@@ -43,12 +43,13 @@ all_objs := $(sort $(recv_objs) $(filter_objs) $(client_objs) $(gui_objs) \
        $(audiod_objs) $(audioc_objs) $(fade_objs) $(server_objs) \
        $(write_objs) $(afh_objs) $(play_objs))
 deps := $(addprefix $(dep_dir)/, $(filter-out %.cmdline.d, $(all_objs:.o=.d)))
-converted_executables := audioc client fade play recv write filter gui afh
+converted_executables := audioc client fade play recv write filter gui afh audiod
 unconverted_executables := $(filter-out $(converted_executables), $(executables))
 
 afh_objs += afh.lsg.o
 audioc_objs += audioc.lsg.o
-audiod_objs += $(addsuffix _cmd.lsg.o, recv filter audiod write) client.lsg.o
+audiod_objs += $(addsuffix _cmd.lsg.o, recv filter audiod write) \
+       client.lsg.o audiod.lsg.o
 client_objs += client.lsg.o
 fade_objs += fade.lsg.o
 filter_objs += filter_cmd.lsg.o filter.lsg.o
index ca8cd13..2351a8e 100644 (file)
--- a/audiod.c
+++ b/audiod.c
 #include <pwd.h>
 #include <lopsub.h>
 
+#include "audiod.lsg.h"
 #include "recv_cmd.lsg.h"
-#include "client.lsg.h"
 #include "para.h"
 #include "error.h"
 #include "crypt.h"
-#include "audiod.cmdline.h"
 #include "list.h"
 #include "sched.h"
-#include "ggo.h"
 #include "buffer_tree.h"
 #include "recv.h"
 #include "filter.h"
 /** Array of error strings. */
 DEFINE_PARA_ERRLIST;
 
+static struct lls_parse_result *lpr;
+#define CMD_PTR (lls_cmd(0, audiod_suite))
+#define OPT_RESULT(_name) (lls_opt_result(LSG_AUDIOD_PARA_AUDIOD_OPT_ ## _name, lpr))
+#define OPT_GIVEN(_name) (lls_opt_given(OPT_RESULT(_name)))
+#define OPT_STRING_VAL(_name) (lls_string_val(0, OPT_RESULT(_name)))
+#define OPT_UINT32_VAL(_name) (lls_uint32_val(0, OPT_RESULT(_name)))
+#define ENUM_STRING_VAL(_name) (lls_enum_string_val(OPT_UINT32_VAL(_name), \
+       lls_opt(LSG_AUDIOD_PARA_AUDIOD_OPT_ ## _name, CMD_PTR)))
+
 __printf_2_3 void (*para_log)(int, const char*, ...) = daemon_log;
 /** define the array containing all supported audio formats */
 const char *audio_formats[] = {AUDIOD_AUDIO_FORMAT_ARRAY NULL};
@@ -165,19 +172,10 @@ char *stat_item_values[NUM_STAT_ITEMS] = {NULL};
  */
 int audiod_status = AUDIOD_ON;
 
-/**
- * the gengetopt args_info struct that holds information on all command line
- * arguments
- */
-static struct audiod_args_info conf;
-
 static char *socket_name;
 static struct audio_format_info afi[NUM_AUDIO_FORMATS];
-
 static struct signal_task *signal_task;
-
 static struct status_task status_task_struct;
-
 static uid_t *uid_whitelist;
 
 /**
@@ -398,58 +396,82 @@ empty:
 
 static void parse_config_or_die(void)
 {
-       int ret, i;
-       char *config_file;
-       struct audiod_cmdline_parser_params params = {
-               .override = 0,
-               .initialize = 0,
-               .check_required = 1,
-               .check_ambiguity = 0,
-               .print_errors = 1
-       };
-
-       if (conf.config_file_given)
-               config_file = para_strdup(conf.config_file_arg);
+       int ret;
+       char *cf, *errctx = NULL;
+       void *map;
+       size_t sz;
+
+       if (OPT_GIVEN(CONFIG_FILE))
+               cf = para_strdup(OPT_STRING_VAL(CONFIG_FILE));
        else {
                char *home = para_homedir();
-               config_file = make_message("%s/.paraslash/audiod.conf", home);
+               cf = make_message("%s/.paraslash/audiod.conf", home);
                free(home);
        }
-       ret = file_exists(config_file);
-       if (conf.config_file_given && !ret) {
-               PARA_EMERG_LOG("can not read config file %s\n", config_file);
-               free(config_file);
-               goto err;
-       }
-       if (ret) {
-               audiod_cmdline_parser_config_file(config_file, &conf, &params);
-               daemon_set_loglevel(conf.loglevel_arg);
+       ret = mmap_full_file(cf, O_RDONLY, &map, &sz, NULL);
+       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;
        }
-       free(config_file);
-       if (conf.user_allow_given > 0) {
-               uid_whitelist = para_malloc(conf.user_allow_given
-                       * sizeof(uid_t));
-               for (i = 0; i < conf.user_allow_given; i++) {
+       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(conf.user_allow_arg[i], &val);
+                       ret = para_atoi32(arg, &val);
                        if (ret >= 0) {
                                uid_whitelist[i] = val;
                                continue;
                        }
                        errno = 0; /* see getpwnam(3) */
-                       pw = getpwnam(conf.user_allow_arg[i]);
+                       pw = getpwnam(arg);
                        if (!pw) {
-                               PARA_EMERG_LOG("invalid username: %s\n",
-                                       conf.user_allow_arg[i]);
-                               goto err;
+                               PARA_EMERG_LOG("invalid username: %s\n", arg);
+                               free(uid_whitelist);
+                               goto free_cf;
                        }
                        uid_whitelist[i] = pw->pw_uid;
                }
        }
-       return;
-err:
-       exit(EXIT_FAILURE);
+       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);
+       }
 }
 
 static void setup_signal_handling(void)
@@ -878,10 +900,11 @@ static int parse_writer_args(void)
        const char *cmd;
        struct audio_format_info *a;
 
-       for (i = 0; i < conf.writer_given; i++) {
+       for (i = 0; i < OPT_GIVEN(WRITER); i++) {
                int j, nw, af_mask;
 
-               ret = parse_stream_command(conf.writer_arg[i], &cmd);
+               ret = parse_stream_command(lls_string_val(i,
+                       OPT_RESULT(WRITER)), &cmd);
                if (ret < 0)
                        return ret;
                af_mask = ret;
@@ -923,10 +946,11 @@ static int parse_receiver_args(void)
 
        FOR_EACH_AUDIO_FORMAT(i)
                afi[i].receiver_num = -1;
-       for (i = conf.receiver_given - 1; i >= 0; i--) {
+       for (i = OPT_GIVEN(RECEIVER) - 1; i >= 0; i--) {
                int j, af_mask;
 
-               ret = parse_stream_command(conf.receiver_arg[i], &arg);
+               ret = parse_stream_command(lls_string_val(i,
+                       OPT_RESULT(RECEIVER)), &arg);
                if (ret < 0)
                        goto out;
                af_mask = ret;
@@ -1012,9 +1036,10 @@ static int parse_filter_args(void)
 {
        int i, j, ret, af_mask, num_matches;
 
-       for (i = 0; i < conf.filter_given; i++) {
+       for (i = 0; i < OPT_GIVEN(FILTER); i++) {
                const char *arg;
-               ret = parse_stream_command(conf.filter_arg[i], &arg);
+               ret = parse_stream_command(lls_string_val(i,
+                       OPT_RESULT(FILTER)), &arg);
                if (ret < 0)
                        goto out;
                af_mask = ret;
@@ -1029,7 +1054,7 @@ static int parse_filter_args(void)
                }
                if (num_matches == 0)
                        PARA_WARNING_LOG("ignoring filter spec: %s\n",
-                               conf.filter_arg[i]);
+                               lls_string_val(i, OPT_RESULT(FILTER)));
        }
        ret = init_default_filters(); /* use default values for the rest */
 out:
@@ -1055,8 +1080,8 @@ static int parse_stream_args(void)
 /* does not unlink socket on errors */
 static void init_local_sockets(struct command_task *ct)
 {
-       if (conf.socket_given)
-               socket_name = para_strdup(conf.socket_arg);
+       if (OPT_GIVEN(SOCKET))
+               socket_name = para_strdup(OPT_STRING_VAL(SOCKET));
        else {
                char *hn = para_hostname();
                socket_name = make_message("/var/paraslash/audiod_socket.%s",
@@ -1064,7 +1089,7 @@ static void init_local_sockets(struct command_task *ct)
                free(hn);
        }
        PARA_NOTICE_LOG("local socket: %s\n", socket_name);
-       if (conf.force_given)
+       if (OPT_GIVEN(FORCE))
                unlink(socket_name);
        ct->fd[0] = create_local_socket(socket_name, 0);
        ct->fd[1] = create_local_socket(socket_name,
@@ -1249,7 +1274,6 @@ static void audiod_cleanup(void)
                unlink(socket_name);
        close_stat_pipe();
        close_unused_slots();
-       audiod_cmdline_parser_free(&conf);
        close_stat_clients();
        free(uid_whitelist);
 }
@@ -1330,7 +1354,7 @@ static int status_post_select(struct sched *s, void *context)
                        goto out;
                }
                close_stat_pipe();
-               st->clock_diff_count = conf.clock_diff_count_arg;
+               st->clock_diff_count = OPT_UINT32_VAL(CLOCK_DIFF_COUNT);
                goto out;
        }
        if (st->ct) {
@@ -1398,7 +1422,7 @@ static void init_status_task(struct status_task *st)
 {
        memset(st, 0, sizeof(struct status_task));
        st->sa_time_diff_sign = 1;
-       st->clock_diff_count = conf.clock_diff_count_arg;
+       st->clock_diff_count = OPT_UINT32_VAL(CLOCK_DIFF_COUNT);
        st->current_audio_format_num = -1;
        st->btrn = btr_new_node(&(struct btr_node_description)
                EMBRACE(.name = "stat"));
@@ -1414,36 +1438,20 @@ static void init_status_task(struct status_task *st)
 static void set_initial_status(void)
 {
        audiod_status = AUDIOD_ON;
-       if (!conf.mode_given)
+       if (!OPT_GIVEN(MODE))
                return;
-       if (!strcmp(conf.mode_arg, "sb")) {
+       if (!strcmp(OPT_STRING_VAL(MODE), "sb")) {
                audiod_status = AUDIOD_STANDBY;
                return;
        }
-       if (!strcmp(conf.mode_arg, "off")) {
+       if (!strcmp(OPT_STRING_VAL(MODE), "off")) {
                audiod_status = AUDIOD_OFF;
                return;
        }
-       if (strcmp(conf.mode_arg, "on"))
+       if (strcmp(OPT_STRING_VAL(MODE), "on"))
                PARA_WARNING_LOG("invalid mode\n");
 }
 
-__noreturn static void print_help_and_die(void)
-{
-       struct ggo_help h = DEFINE_GGO_HELP(audiod);
-       bool d = conf.detailed_help_given;
-       unsigned flags;
-
-       flags = d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS;
-       ggo_print_help(&h, flags);
-
-       flags = d? GPH_MODULE_FLAGS_DETAILED : GPH_MODULE_FLAGS;
-       print_receiver_helps(flags);
-       print_filter_helps(flags);
-       print_writer_helps(flags);
-       exit(0);
-}
-
 /**
  * Lookup the given UID in the whitelist.
  *
@@ -1459,14 +1467,33 @@ bool uid_is_whitelisted(uid_t uid)
 {
        int i;
 
-       if (!conf.user_allow_given)
+       if (!OPT_GIVEN(USER_ALLOW))
                return true;
-       for (i = 0; i < conf.user_allow_given; i++)
+       for (i = 0; i < OPT_GIVEN(USER_ALLOW); i++)
                if (uid == uid_whitelist[i])
                        return true;
        return false;
 }
 
+static void handle_help_flags(void)
+{
+       char *help;
+       bool d = OPT_GIVEN(DETAILED_HELP);
+
+       if (d)
+               help = lls_long_help(CMD_PTR);
+       else if (OPT_GIVEN(HELP))
+               help = lls_short_help(CMD_PTR);
+       else
+               return;
+       printf("%s\n", help);
+       free(help);
+       print_receiver_helps(d);
+       print_filter_helps(d);
+       print_writer_helps(d);
+       exit(EXIT_SUCCESS);
+}
+
 /**
  * the main function of para_audiod
  *
@@ -1481,38 +1508,34 @@ int main(int argc, char *argv[])
 {
        int ret, i;
        struct command_task command_task_struct, *cmd_task = &command_task_struct;
-       struct audiod_cmdline_parser_params params = {
-               .override = 0,
-               .initialize = 1,
-               .check_required = 0,
-               .check_ambiguity = 0,
-               .print_errors = 1
-       };
+       char *errctx;
 
        valid_fd_012();
-       audiod_cmdline_parser_ext(argc, argv, &conf, &params);
-       daemon_set_loglevel(conf.loglevel_arg);
-       version_handle_flag("audiod", conf.version_given);
-       /* init receivers/filters/writers early to make help work */
-       recv_init();
-       if (conf.help_given || conf.detailed_help_given)
-               print_help_and_die();
-       daemon_set_priority(conf.priority_arg);
-       daemon_drop_privileges_or_die(conf.user_arg, conf.group_arg);
+       ret = lls(lls_parse(argc, argv, CMD_PTR, &lpr, &errctx));
+       if (ret < 0)
+               goto out;
+       daemon_set_loglevel(ENUM_STRING_VAL(LOGLEVEL));
+       daemon_drop_privileges_or_die(OPT_STRING_VAL(USER),
+               OPT_STRING_VAL(GROUP));
+       version_handle_flag("audiod", OPT_GIVEN(VERSION));
+       handle_help_flags();
        parse_config_or_die();
-       if (daemon_init_colors_or_die(conf.color_arg, color_arg_auto, color_arg_no,
-               conf.logfile_given)) {
-                       for (i = 0; i < conf.log_color_given; i++)
-                               daemon_set_log_color_or_die(conf.log_color_arg[i]);
-       }
        init_random_seed_or_die();
+       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++)
+                       daemon_set_log_color_or_die(lls_string_val(i,
+                               OPT_RESULT(LOG_COLOR)));
+       }
        daemon_set_flag(DF_LOG_TIME);
        daemon_set_flag(DF_LOG_HOSTNAME);
        daemon_set_flag(DF_LOG_LL);
-       if (conf.log_timing_given)
+       if (OPT_GIVEN(LOG_TIMING))
                daemon_set_flag(DF_LOG_TIMING);
-       if (conf.logfile_given) {
-               daemon_set_logfile(conf.logfile_arg);
+       if (OPT_GIVEN(LOGFILE)) {
+               daemon_set_logfile(OPT_STRING_VAL(LOGFILE));
                daemon_open_log_or_die();
        }
        ret = parse_stream_args();
@@ -1530,7 +1553,7 @@ int main(int argc, char *argv[])
        init_status_task(stat_task);
        init_command_task(cmd_task);
 
-       if (conf.daemon_given)
+       if (OPT_GIVEN(DAEMON))
                daemonize(false /* parent exits immediately */);
 
        signal_task->task = task_register(&(struct task_info) {
@@ -1547,6 +1570,10 @@ int main(int argc, char *argv[])
        sched_shutdown(&sched);
        signal_shutdown(signal_task);
 
+out:
+       lls_free_parse_result(lpr, CMD_PTR);
+       if (errctx)
+               PARA_ERROR_LOG("%s\n", errctx);
        if (ret < 0)
                PARA_EMERG_LOG("%s\n", para_strerror(-ret));
        return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
index 7073c6d..295a02b 100644 (file)
--- a/audiod.h
+++ b/audiod.h
@@ -13,15 +13,6 @@ enum {AUDIOD_AUDIO_FORMATS_ENUM};
 /** array of audio format names supported by para_audiod */
 extern const char *audio_formats[];
 
-/**
- * the possible modes of operation
- *
- * - off: disconnect from para_server
- * - on: receive status information from para_server and play the audio stream
- * - sb: only receive status information but not the audio stream
- */
-enum audiod_status_info {AUDIOD_OFF, AUDIOD_ON, AUDIOD_STANDBY};
-
 extern int audiod_status;
 
 /* defined in audiod.c */
index a26d193..8319b0f 100644 (file)
@@ -15,9 +15,9 @@
 #include <netdb.h>
 #include <lopsub.h>
 
+#include "audiod.lsg.h"
 #include "para.h"
 #include "audiod_cmd.lsg.h"
-#include "audiod.cmdline.h"
 #include "list.h"
 #include "sched.h"
 #include "buffer_tree.h"
index 1d31a59..a290c22 100644 (file)
@@ -506,9 +506,6 @@ if test -n "$CRYPTOLIB"; then
        build_audiod="yes"
        executables="$executables audiod"
        audiod_audio_formats="wma"
-       audiod_cmdline_objs="$audiod_cmdline_objs
-               audiod
-       "
        audiod_errlist_objs="$audiod_errlist_objs
                audiod
                signal
@@ -535,7 +532,6 @@ if test -n "$CRYPTOLIB"; then
                audiod_command
                fecdec_filter
                client_common
-               ggo
                udp_recv
                color
                fec
@@ -592,7 +588,7 @@ if test -n "$CRYPTOLIB"; then
        if test $HAVE_SAMPLERATE = yes; then
                audiod_errlist_objs="$audiod_errlist_objs resample_filter check_wav"
        fi
-       audiod_objs="add_cmdline($audiod_cmdline_objs) $audiod_errlist_objs"
+       audiod_objs="$audiod_errlist_objs"
        AC_SUBST(audiod_objs, add_dot_o($audiod_objs))
 
        enum="$(for i in $audiod_audio_formats; do printf "AUDIO_FORMAT_${i}, " | tr '[a-z]' '[A-Z]'; done)"
diff --git a/m4/gengetopt/audiod.m4 b/m4/gengetopt/audiod.m4
deleted file mode 100644 (file)
index 4e93464..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-args "--no-handle-help --no-handle-version --conf-parser"
-
-purpose "Connect to para_server, receive, decode and play audio streams"
-
-include(header.m4)
-define(CURRENT_PROGRAM,para_audiod)
-define(DEFAULT_CONFIG_FILE,~/.paraslash/audiod.conf)
-
-<qu>
-#########################
-section "General options"
-#########################
-</qu>
-
-include(loglevel.m4)
-include(color.m4)
-include(config_file.m4)
-include(logfile.m4)
-include(log_timing.m4)
-include(daemon.m4)
-include(user.m4)
-include(group.m4)
-include(priority.m4)
-
-<qu>
-########################
-section "Audiod options"
-########################
-
-option "force" F
-#~~~~~~~~~~~~~~~
-"force startup"
-flag off
-details="
-       If this flag is not given, para_audiod refuses to start if the
-       well-known socket file (see the --socket option) already exists
-       because this usually means that para_audiod is already running
-       and listening on that socket. After a crash or if para_audiod
-       received a SIGKILL signal, a stale socket file might remain and
-       you have to use --force once to force startup of para_audiod.
-"
-
-option "mode" m
-#~~~~~~~~~~~~~~
-"startup mode"
-string typestr="mode"
-default="on"
-optional
-details="
-       Para_audiod supports three modes of operation: On, off and
-       standby (sb).  This option selects the mode that should be
-       used on startup. If para_audiod operates in \"on\" mode, it
-       will connect to para_server in order to receive its status
-       information. If para_server announces the availability of an
-       audio stream, para_audiod will automatically download, decode
-       and play the audio stream according to the given stream I/O
-       options, see below.
-
-       In \"standby\" mode, para_audiod will only receive the
-       status information from para_server but will not download
-       the audio stream.
-
-       In \"off\" mode, para_audiod does not connect para_server at
-       all, but still listens on the local socket for connections.
-"
-
-option "socket" s
-#~~~~~~~~~~~~~~~~
-"well-known socket"
-string typestr="filename"
-optional
-details="
-       Para_audiod uses a \"well-known\" socket to listen
-       on for connections from para_audioc. This socket is a
-       special file in the file system; its location defaults to
-       /var/paraslash/audiod_sock.<host_name>.
-
-       para_audioc, the client program used to connect to para_audiod,
-       opens this socket in order to talk to para_audiod.  If the
-       default value for para_audiod is changed, para_audioc must be
-       instructed to use also \"filename\" for connecting para_audiod.
-"
-
-option "user-allow" -
-#~~~~~~~~~~~~~~~~~~~~
-"allow this user to connect to audiod"
-string typestr = "username"
-optional
-multiple
-details = "
-       Allow the user identified by username (either a string or
-       a UID) to connect to para_audiod. This option may be given
-       multiple times. If not specified at all, all users are allowed
-       to connect.
-
-       This feature is based on the ability to send unix
-       credentials through local sockets using ancillary data
-       (SCM_CREDENTIALS). Currently it only works on Linux. On
-       other operating systems the option is silently ignored and
-       all local users are allowed to connect.
-"
-
-option "clock-diff-count" -
-#~~~~~~~~~~~~~~~~~~~~~~~~~~
-"sync clock on startup"
-int typestr="count"
-default="0"
-optional
-details="
-       Check the clock difference between the host running para_server
-       and the local host running para_audiod that many times before
-       starting any stream I/0. Set this to non-zero for non-local
-       setups if the clocks of these two hosts are not synchronized
-       by ntp or similar.
-"
-
-#############################
-section "Stream I/O options"
-#############################
-
-option "receiver" r
-#~~~~~~~~~~~~~~~~~~
-"select receiver"
-string typestr="receiver_spec"
-default="http"
-optional
-multiple
-details="
-       This option may be given multiple times, for each audio format
-       separately. If multiple definitions for an audio format are
-       given, the first one is selected.
-
-       The \"receiver_spec\" consists of an audio format specifier
-       and one or more receiver arguments, separated by a colon.
-
-       The audio format specifier is a regular expression which
-       specifies the set of audio formats for which this option
-       should apply.
-
-       If any receiver options are present, the whole receiver
-       argument must be quoted:
-
-               -r 'mp3:http -i my.host.org -p 8009'
-
-       Since a single dot '.' matches the name of any audio format,
-       specifying '.' instead of 'mp3' above activates the http
-       receiver for all audio formats.
-
-"
-
-option "filter" f
-#~~~~~~~~~~~~~~~~
-"Specify the filter configuration."
-string typestr = "filter_spec"
-optional
-multiple
-details = "
-       This option may be given multiple times. The \"filter_spec\"
-       consists of an audio format specifier (see above), the name
-       of the filter, and any options for that filter. Note that
-       order matters.
-
-       The compiled-in defaults apply to all audio formats for which
-       no --filter option was given. These defaults depend on the
-       receiver being used.
-
-       For HTTP streams, only the decoder for the current audio
-       format is activated. UDP and DCCP streams, on the other
-       hand, are sent FEC-encoded by para_server. In order to play
-       such streams, the receiver output must be FEC-decoded first,
-       i.e. fed to the fecdec filter. Therefore the default for UDP
-       and DCCP streams is to activate the fecdec filter, followed
-       by the decoding filter for the audio format.
-
-       Examples:
-
-               --filter 'mp3:mp3dec'
-
-               --filter 'mp3|aac:compress --inertia 5 --damp 2'
-
-               --filter '.:fecdec'
-
-"
-
-option "writer" w
-#~~~~~~~~~~~~~~~~
-"Specify stream writer."
-string typestr="writer_spec"
-optional
-multiple
-details="
-       May be given multiple times, even multiple times for the same
-       audio format.  Default value is \"alsa\" for all supported
-       audio formats. Example:
-
-               --writer 'aac|wma:oss'
-
-"
-</qu>
diff --git a/m4/lls/audiod.suite.m4 b/m4/lls/audiod.suite.m4
new file mode 100644 (file)
index 0000000..31f6042
--- /dev/null
@@ -0,0 +1,191 @@
+m4_define(PROGRAM, para_audiod)
+m4_define(DEFAULT_CONFIG_FILE, ~/.paraslash/audiod.conf)
+[suite audiod]
+version-string = GIT_VERSION()
+[supercommand para_audiod]
+       purpose = connect to para_server, receive, decode and play audio streams
+       [description]
+               para_audiod runs on a host with an audio device and connects
+               para_server to obtain status information and receive the current audio
+               stream. The stream is transformed through any number of filters and
+               then written to the configured output device.
+
+               Moreover, para_audiod listens on a local socket and sends status
+               information to local clients on request. Access to the local socket
+               can be restricted by means of Unix socket credentials, if available.
+       [/description]
+       m4_include(common-option-section.m4)
+       m4_include(help.m4)
+       m4_include(detailed-help.m4)
+       m4_include(version.m4)
+       m4_include(config-file.m4)
+       m4_include(loglevel.m4)
+       m4_include(logfile.m4)
+       m4_include(color.m4)
+       m4_include(log-timing.m4)
+       m4_include(daemon.m4)
+       m4_include(user.m4)
+       m4_include(group.m4)
+       m4_include(priority.m4)
+       m4_include(per-command-options-section.m4)
+       [option force]
+               summary = force startup
+               short_opt = F
+               [help]
+                       If this flag is not given, para_audiod refuses to start if the
+                       well-known socket file (see the --socket option) already exists
+                       because this usually means that para_audiod is already running and
+                       listening on that socket. After a crash or if para_audiod received
+                       a SIGKILL signal, a stale socket file might remain and you have to
+                       use --force once to force startup of para_audiod.
+               [/help]
+       [option mode]
+               summary = select startup mode
+               arg_info = required_arg
+               arg_type = string
+               typestr = mode
+               values = {AUDIOD_ON = "on", AUDIOD_OFF = "off",  AUDIOD_STANDBY = "sb"}
+               default_val = on
+               [help]
+                       para_audiod supports three modes of operation: On, off and standby
+                       (sb).  This option selects the mode that should be used at startup. If
+                       mode is "on", para_audiiod connects para_server to receive status
+                       information. If the server announces the availability of an audio
+                       stream, para_audiod downloads, decodes and plays the audio stream
+                       according to the given stream I/O options, see below.
+
+                       In "standby" mode, para_audiod only receives the status information
+                       from para_server but does not download the audio stream.
+
+                       In "off" mode, para_audiod does not connect para_server at all,
+                       but still listens on the local socket.
+               [/help]
+       [option socket]
+               short_opt = s
+               summary = path to the well-known socket
+               arg_info = required_arg
+               arg_type = string
+               typestr = path
+               [help]
+                       para_audiod listens on a "well-known" socket for connections
+                       from para_audioc. This socket is a special file in the file system;
+                       its location defaults to /var/paraslash/audiod_sock.$hostname.
+
+                       para_audioc, the client program used to connect to para_audiod,
+                       opens this socket in order to talk to para_audiod. If the default
+                       value for para_audiod is changed, para_audioc must be instructed to
+                       use also <path> to connect para_audiod.
+               [/help]
+       [option user-allow]
+               summary = allow this user to connect to audiod
+               arg_info = required_arg
+               arg_type = string
+               typestr = username
+               [help]
+                       Allow the user identified by username (either a string or a UID) to
+                       connect to para_audiod. This option may be given multiple times. If
+                       not specified at all, all users are allowed to connect.
+
+                       This feature is based on the ability to send unix credentials through
+                       local sockets using ancillary data (SCM_CREDENTIALS). Currently it
+                       only works on Linux. On other operating systems the option is silently
+                       ignored and all local users are allowed to connect.
+               [/help]
+       [option clock-diff-count]
+               summary = sync clock on startup
+               arg_info = required_arg
+               arg_type = uint32
+               typestr = count
+               [help]
+                       Check the clock difference between the host running para_server and
+                       the local host running para_audiod this many times before starting
+                       any stream I/0. Set this to non-zero for non-local setups if the
+                       clocks of these two hosts are not synchronized by ntp or similar.
+               [/help]
+       [option Stream-IO-options]
+               summary = Stream I/O options
+               flag ignored
+       [option receiver]
+               short_opt = r
+               summary = select receiver
+               arg_info = required_arg
+               arg_type = string
+               typestr = receiver_spec
+               default_val = http
+               flag multiple
+               [help]
+                       This option may be given multiple times, for each audio format
+                       separately. If multiple definitions for an audio format are given,
+                       the first one is selected.
+
+                       The <receiver_spec> consists of an audio format specifier and one or
+                       more receiver arguments, separated by a colon.
+
+                       The audio format specifier is a regular expression which specifies
+                       the set of audio formats for which this option should apply.
+
+                       If any receiver options are present, the whole receiver argument must
+                       be quoted:
+
+                               -r 'mp3:http -i my.host.org -p 8009'
+
+                       Since a single dot '.' matches the name of any audio format, specifying
+                       '.' instead of 'mp3' above activates the http receiver for all audio
+                       formats.
+               [/help]
+       [option filter]
+               short_opt = f
+               summary = specify the filter configuration
+               arg_info = required_arg
+               arg_type = string
+               typestr = filter_spec
+               flag multiple
+               [help]
+                       This option may be given multiple times. The <filter_spec< consists
+                       of an audio format specifier (see above), the name of the filter,
+                       and any options for that filter. Note that order matters.
+
+                       The compiled-in defaults apply to all audio formats for which no
+                       --filter option was given. These defaults depend on the receiver
+                       being used.
+
+                       For HTTP streams, only the decoder for the current audio format
+                       is activated. UDP and DCCP streams, on the other hand, are sent
+                       FEC-encoded by para_server. In order to play such streams, the
+                       receiver output must be FEC-decoded first, i.e. fed to the fecdec
+                       filter. Therefore the default for UDP and DCCP streams is to activate
+                       the fecdec filter, followed by the decoding filter for the audio
+                       format.
+
+                       Examples:
+
+                               --filter 'mp3:mp3dec'
+
+                               --filter 'mp3|aac:compress --inertia 5 --damp 2'
+
+                               --filter '.:fecdec'
+               [/help]
+       [option writer]
+               short_opt = w
+               summary = specify one or more stream writers
+               arg_info = required_arg
+               arg_type = string
+               typestr = writer_spec
+               flag multiple
+               [help]
+                       May be given multiple times, even multiple times for the same audio
+                       format. The default is to use the first supported writer. Example:
+
+                               --writer 'aac|wma:oss'
+               [/help]
+       [option stream-delay]
+               summary = specify time interval for client sync
+               arg_info = required_arg
+               arg_type = uint32
+               typestr = count
+               [help]
+                       Check the clock difference between the host running para_server and
+                       the local host running para_audiod this many times before starting
+                       any stream I/0. Set this to non-zero for non-local setups if the
+                       clocks of these two hosts are not synchronized by ntp or similar.
+               [/help]
diff --git a/m4/lls/include/color.m4 b/m4/lls/include/color.m4
new file mode 100644 (file)
index 0000000..a23b325
--- /dev/null
@@ -0,0 +1,29 @@
+[option color]
+       short_opt = C
+       summary = activate color output
+       typestr = when
+       arg_info = required_arg
+       arg_type = string
+       values = {COLOR_YES = "yes", COLOR_NO = "no", COLOR_AUTO = "auto"}
+       default_val = auto
+[option log-color]
+       summary = select a color for one type of log message
+       typestr = color_spec
+       arg_info = required_arg
+       arg_type = string
+       flag multiple
+       [help]
+               The format of <color_spec> is [<fg> [<bg>]] [<attr>].
+
+               Valid colors for <fg> and <bg> are "normal", "black", "red", "green",
+               "yellow", "blue", "magenta", "cyan", and "white".
+
+               The <attr> value must be one of "bold", "dim", "ul", "blink",
+               "reverse".
+
+       Examples:
+
+               --log-color "debug:green"
+               --log-color "info:yellow bold"
+               --log-color "notice:white red bold"
+       [/help]
diff --git a/m4/lls/include/daemon.m4 b/m4/lls/include/daemon.m4
new file mode 100644 (file)
index 0000000..5c04712
--- /dev/null
@@ -0,0 +1,7 @@
+[option daemon]
+       short_opt = d
+       summary = run as background daemon
+       [help]
+               If this option is given and no logfile was specified, all messages
+               go to /dev/null.
+       [/help]
diff --git a/m4/lls/include/group.m4 b/m4/lls/include/group.m4
new file mode 100644 (file)
index 0000000..8d49cc7
--- /dev/null
@@ -0,0 +1,12 @@
+[option group]
+       short_opt = g
+       summary = set group id
+       arg_info = required_arg
+       arg_type = string
+       typestr = groupname
+       [help]
+               This option sets the group id according to <group>. This option is
+               silently ignored if EUID != 0. Otherwise, real/effective GID and the
+               saved set-group ID are all set to the GID given by <group>. Must not
+               be given in the config file.
+       [/help]
diff --git a/m4/lls/include/log-timing.m4 b/m4/lls/include/log-timing.m4
new file mode 100644 (file)
index 0000000..a7364e1
--- /dev/null
@@ -0,0 +1,9 @@
+[option log-timing]
+       short_opt = T
+       summary = show milliseconds in log messages
+       [help]
+               Selecting this option causes milliseconds to be included in
+               the log message output. This allows to measure the interval
+               between log messages in milliseconds which is useful for
+               identifying timing problems.
+       [/help]
diff --git a/m4/lls/include/logfile.m4 b/m4/lls/include/logfile.m4
new file mode 100644 (file)
index 0000000..e3d40a1
--- /dev/null
@@ -0,0 +1,10 @@
+[option logfile]
+short_opt = L
+arg_info = required_arg
+arg_type = string
+typestr = filename
+summary = where to write log output
+[help]
+       If this option is not given, PROGRAM() writes the log messages
+       to stderr.
+[/help]
diff --git a/m4/lls/include/priority.m4 b/m4/lls/include/priority.m4
new file mode 100644 (file)
index 0000000..70d44b4
--- /dev/null
@@ -0,0 +1,13 @@
+[option priority]
+       summary = adjust scheduling priority
+       arg_info = required_arg
+       arg_type = int32
+       typestr = prio
+       default_val = 0
+       [help]
+               The priority (also known as nice value) is a value in the range -20
+               to 19. Lower priorities cause more favorable scheduling. Since only
+               privileged processes may request a negative priority, specifying
+               a negative value works only if the daemon is started with root
+               privileges.
+       [/help]
diff --git a/m4/lls/include/user.m4 b/m4/lls/include/user.m4
new file mode 100644 (file)
index 0000000..6d4d31b
--- /dev/null
@@ -0,0 +1,21 @@
+[option user]
+       short_opt = u
+       summary = run as the given user
+       arg_info = required_arg
+       arg_type = string
+       typestr = username
+       [help]
+               PROGRAM() does not need any special privileges.
+
+               If started as root (EUID == 0) this option must be given at the
+               command line (not in the configuration file) so that PROGRAM()
+               can drop the root privileges right after parsing the command line
+               options, but before parsing the configuration file. In this case,
+               real/effective/saved UID are all set to the UID of <username>. As
+               the configuration file is read afterwards, those options that have
+               a default value depending on the UID (e.g. the directory for the
+               configuration file) are computed by using the uid of <username>. This
+               option has no effect if PROGRAM() is started as a non-root user (i.e.
+               EUID != 0).
+       [/help]
+