X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=audiod.c;h=3fe654a73c1f71004baf554996df82d100f83933;hp=74298e3c5f3822cda0e7565beaaf39d7520231b6;hb=cb193b91d68778125739fe129d49f3c5f4abf999;hpb=751fface082c907983978023bdcb43540a462192 diff --git a/audiod.c b/audiod.c index 74298e3c..3fe654a7 100644 --- a/audiod.c +++ b/audiod.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -14,6 +14,7 @@ #include #include #include +#include #include "para.h" #include "error.h" @@ -144,10 +145,12 @@ struct audiod_args_info conf; static char *socket_name; static struct audio_format_info afi[NUM_AUDIO_FORMATS]; -static struct signal_task signal_task_struct, *sig_task = &signal_task_struct; +static struct signal_task *signal_task; static struct status_task status_task_struct; +static uid_t *uid_whitelist; + /** * the task that calls the status command of para_server * @@ -155,14 +158,22 @@ static struct status_task status_task_struct; */ static struct status_task *stat_task = &status_task_struct; -/** - * the task for handling audiod commands +/* + * The task for handling audiod commands. + * + * We need two listening sockets for backward compability: on Linux systems + * fd[0] is an abstract socket (more precisely, a socket bound to an address in + * the abstract namespace), and fd[1] is the usual pathname socket. On other + * systems, fd[0] is negative, and only the pathname socket is used. * - * \sa struct task, struct sched + * For 0.5.x we accept connections on both sockets to make sure that old + * para_audioc versions can still connect. New versions use only the abstract + * socket. Hence after v0.6.0 we can go back to a single socket, either an + * abstract one (Linux) or a pathname socket (all other systems). */ struct command_task { - /** the local listening socket */ - int fd; + /** The local listening sockets. */ + int fd[2]; /** the associated task structure */ struct task *task; }; @@ -310,20 +321,9 @@ empty: return para_strdup(NULL); } -static int want_colors(void) -{ - if (conf.color_arg == color_arg_no) - return 0; - if (conf.color_arg == color_arg_yes) - return 1; - if (conf.logfile_given) - return 0; - return isatty(STDERR_FILENO); -} - static void parse_config_or_die(void) { - int ret; + int ret, i; char *config_file; struct audiod_cmdline_parser_params params = { .override = 0, @@ -343,6 +343,7 @@ static void parse_config_or_die(void) 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) { @@ -350,16 +351,35 @@ static void parse_config_or_die(void) daemon_set_loglevel(conf.loglevel_arg); } 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++) { + int32_t val; + struct passwd *pw; + ret = para_atoi32(conf.user_allow_arg[i], &val); + if (ret >= 0) { + uid_whitelist[i] = val; + continue; + } + errno = 0; /* see getpwnam(3) */ + pw = getpwnam(conf.user_allow_arg[i]); + if (!pw) { + PARA_EMERG_LOG("invalid username: %s\n", + conf.user_allow_arg[i]); + goto err; + } + uid_whitelist[i] = pw->pw_uid; + } + } return; err: - free(config_file); exit(EXIT_FAILURE); } static void setup_signal_handling(void) { - sig_task->fd = para_signal_init(); - PARA_INFO_LOG("signal pipe: fd %d\n", sig_task->fd); + signal_task = signal_init_or_die(); para_install_sighandler(SIGINT); para_install_sighandler(SIGTERM); para_install_sighandler(SIGHUP); @@ -390,6 +410,7 @@ 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; tv_add(now, &(struct timeval)EMBRACE(0, 200 * 1000), &a->restart_barrier); } @@ -966,11 +987,8 @@ static int parse_stream_args(void) } /* does not unlink socket on errors */ -static int audiod_get_socket(void) +static void init_local_sockets(struct command_task *ct) { - struct sockaddr_un unix_addr; - int ret, fd; - if (conf.socket_given) socket_name = para_strdup(conf.socket_arg); else { @@ -982,30 +1000,15 @@ static int audiod_get_socket(void) PARA_NOTICE_LOG("local socket: %s\n", socket_name); if (conf.force_given) unlink(socket_name); - ret = create_local_socket(socket_name, &unix_addr, + ct->fd[0] = create_local_socket(socket_name, 0); + ct->fd[1] = create_local_socket(socket_name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH); - if (ret < 0) - goto err; - fd = ret; - if (listen(fd , 5) < 0) { - ret = -ERRNO_TO_PARA_ERROR(errno); - goto err; - } - ret = mark_fd_nonblocking(fd); - if (ret < 0) - goto err; - return fd; -err: - PARA_EMERG_LOG("%s\n", para_strerror(-ret)); + if (ct->fd[0] >= 0 || ct->fd[1] >= 0) + return; + PARA_EMERG_LOG("%s\n", para_strerror(-ct->fd[1])); exit(EXIT_FAILURE); } -static void signal_pre_select(struct sched *s, void *context) -{ - struct signal_task *st = context; - para_fd_set(st->fd, &s->rfds, &s->max_fileno); -} - static int signal_post_select(struct sched *s, void *context) { struct signal_task *st = context; @@ -1029,28 +1032,38 @@ static int signal_post_select(struct sched *s, void *context) static void command_pre_select(struct sched *s, void *context) { struct command_task *ct = context; - para_fd_set(ct->fd, &s->rfds, &s->max_fileno); + int i; + + for (i = 0; i < 2; i++) + if (ct->fd[i] >= 0) + para_fd_set(ct->fd[i], &s->rfds, &s->max_fileno); } static int command_post_select(struct sched *s, void *context) { - int ret; + int ret, i; struct command_task *ct = context; static struct timeval last_status_dump; struct timeval tmp, delay; - bool force = true; + bool force = false; ret = task_get_notification(ct->task); if (ret < 0) return ret; - ret = handle_connect(ct->fd, &s->rfds); - if (ret < 0) { - PARA_ERROR_LOG("%s\n", para_strerror(-ret)); - if (ret == -E_AUDIOD_TERM) { - task_notify_all(s, -ret); - return ret; - } - } else if (ret > 0) + for (i = 0; i < 2; i++) { + if (ct->fd[i] < 0) + continue; + ret = handle_connect(ct->fd[i], &s->rfds, uid_whitelist); + if (ret < 0) { + PARA_ERROR_LOG("%s\n", para_strerror(-ret)); + if (ret == -E_AUDIOD_TERM) { + task_notify_all(s, -ret); + return ret; + } + } else if (ret > 0) + force = true; + } + if (force == true) goto dump; /* if last status dump was less than 500ms ago, do nothing */ @@ -1067,8 +1080,8 @@ static int command_post_select(struct sched *s, void *context) delay.tv_sec = 5; delay.tv_usec = 0; tv_add(&last_status_dump, &delay, &tmp); - if (tv_diff(now, &tmp, NULL) < 0) - force = false; + if (tv_diff(now, &tmp, NULL) > 0) + force = true; dump: audiod_status_dump(force); last_status_dump = *now; @@ -1077,7 +1090,7 @@ dump: static void init_command_task(struct command_task *ct) { - ct->fd = audiod_get_socket(); /* doesn't return on errors */ + init_local_sockets(ct); /* doesn't return on errors */ ct->task = task_register(&(struct task_info) { .name = "command", @@ -1167,6 +1180,7 @@ static void audiod_cleanup(void) close_unused_slots(); audiod_cmdline_parser_free(&conf); close_stat_clients(); + free(uid_whitelist); } /* @@ -1358,18 +1372,6 @@ __noreturn static void print_help_and_die(void) exit(0); } -static void init_colors_or_die(void) -{ - int i; - - if (!want_colors()) - return; - daemon_set_default_log_colors(); - daemon_set_flag(DF_COLOR_LOG); - for (i = 0; i < conf.log_color_given; i++) - daemon_set_log_color_or_die(conf.log_color_arg[i]); -} - /** * the main function of para_audiod * @@ -1402,9 +1404,10 @@ int main(int argc, char *argv[]) writer_init(); if (conf.help_given || conf.detailed_help_given) print_help_and_die(); - drop_privileges_or_die(conf.user_arg, conf.group_arg); + daemon_drop_privileges_or_die(conf.user_arg, conf.group_arg); parse_config_or_die(); - init_colors_or_die(); + daemon_init_colors_or_die(conf.color_arg, color_arg_auto, color_arg_no, + conf.logfile_given, conf.log_color_arg, conf.log_color_given); init_random_seed_or_die(); daemon_set_flag(DF_LOG_TIME); daemon_set_flag(DF_LOG_HOSTNAME); @@ -1420,8 +1423,8 @@ int main(int argc, char *argv[]) PARA_EMERG_LOG("%s\n", para_strerror(-ret)); exit(EXIT_FAILURE); } - log_welcome("para_audiod"); - set_server_start_time(NULL); + daemon_log_welcome("para_audiod"); + daemon_set_start_time(); set_initial_status(); FOR_EACH_SLOT(i) clear_slot(i); @@ -1433,11 +1436,11 @@ int main(int argc, char *argv[]) if (conf.daemon_given) daemonize(false /* parent exits immediately */); - sig_task->task = task_register(&(struct task_info) { + signal_task->task = task_register(&(struct task_info) { .name = "signal", .pre_select = signal_pre_select, .post_select = signal_post_select, - .context = sig_task, + .context = signal_task, }, &sched); sched.default_timeout.tv_sec = 2; @@ -1445,6 +1448,7 @@ int main(int argc, char *argv[]) ret = schedule(&sched); audiod_cleanup(); sched_shutdown(&sched); + signal_shutdown(signal_task); if (ret < 0) PARA_EMERG_LOG("%s\n", para_strerror(-ret));