From: Andre Noll Date: Sat, 27 Aug 2016 13:05:13 +0000 (+0200) Subject: Convert para_audiod to lopsub. X-Git-Tag: v0.6.0~2^2~21 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=15d4c69ddcf88dd9046ed8d2847a428145a32045 Convert para_audiod to lopsub. 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). --- diff --git a/Makefile.real b/Makefile.real index 799bbad4..d4562018 100644 --- a/Makefile.real +++ b/Makefile.real @@ -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 diff --git a/audiod.c b/audiod.c index ca8cd13b..2351a8ed 100644 --- a/audiod.c +++ b/audiod.c @@ -17,15 +17,13 @@ #include #include +#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" @@ -43,6 +41,15 @@ /** 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, ¶ms); - 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, ¶ms); - 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; diff --git a/audiod.h b/audiod.h index 7073c6dd..295a02bc 100644 --- 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 */ diff --git a/audiod_command.c b/audiod_command.c index a26d1931..8319b0f1 100644 --- a/audiod_command.c +++ b/audiod_command.c @@ -15,9 +15,9 @@ #include #include +#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" diff --git a/configure.ac b/configure.ac index 1d31a598..a290c22b 100644 --- a/configure.ac +++ b/configure.ac @@ -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 index 4e93464b..00000000 --- a/m4/gengetopt/audiod.m4 +++ /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) - - -######################### -section "General options" -######################### - - -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) - - -######################## -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.. - - 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' - -" - diff --git a/m4/lls/audiod.suite.m4 b/m4/lls/audiod.suite.m4 new file mode 100644 index 00000000..31f60425 --- /dev/null +++ b/m4/lls/audiod.suite.m4 @@ -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 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 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 is [ []] []. + + Valid colors for and are "normal", "black", "red", "green", + "yellow", "blue", "magenta", "cyan", and "white". + + The 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 index 00000000..5c047128 --- /dev/null +++ b/m4/lls/include/daemon.m4 @@ -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 index 00000000..8d49cc76 --- /dev/null +++ b/m4/lls/include/group.m4 @@ -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 . 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 . 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 index 00000000..a7364e19 --- /dev/null +++ b/m4/lls/include/log-timing.m4 @@ -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 index 00000000..e3d40a14 --- /dev/null +++ b/m4/lls/include/logfile.m4 @@ -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 index 00000000..70d44b43 --- /dev/null +++ b/m4/lls/include/priority.m4 @@ -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 index 00000000..6d4d31b7 --- /dev/null +++ b/m4/lls/include/user.m4 @@ -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 . 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 . This + option has no effect if PROGRAM() is started as a non-root user (i.e. + EUID != 0). + [/help] +