1/***
2  This file is part of PulseAudio.
3
4  Copyright 2004-2006 Lennart Poettering
5  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7  PulseAudio is free software; you can redistribute it and/or modify
8  it under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 2.1 of the License,
10  or (at your option) any later version.
11
12  PulseAudio is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  General Public License for more details.
16
17  You should have received a copy of the GNU Lesser General Public License
18  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19***/
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include <errno.h>
26#include <stdio.h>
27#include <string.h>
28#include <unistd.h>
29#include <fcntl.h>
30#include <sys/stat.h>
31
32#ifdef HAVE_SCHED_H
33#include <sched.h>
34#endif
35
36#include <pulse/xmalloc.h>
37#include <pulse/timeval.h>
38#include <pulse/version.h>
39
40#include <pulsecore/core-error.h>
41#include <pulsecore/core-util.h>
42#include <pulsecore/i18n.h>
43#include <pulsecore/strbuf.h>
44#include <pulsecore/conf-parser.h>
45#include <pulsecore/resampler.h>
46#include <pulsecore/macro.h>
47
48#include "daemon-conf.h"
49
50#define DEFAULT_SCRIPT_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "default.pa"
51#define DEFAULT_SCRIPT_FILE_USER PA_PATH_SEP "default.pa"
52#define DEFAULT_SYSTEM_SCRIPT_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "system.pa"
53
54#define DEFAULT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "daemon.conf"
55#define DEFAULT_CONFIG_FILE_USER PA_PATH_SEP "daemon.conf"
56
57#define ENV_SCRIPT_FILE "PULSE_SCRIPT"
58#define ENV_CONFIG_FILE "PULSE_CONFIG"
59#define ENV_DL_SEARCH_PATH "PULSE_DLPATH"
60
61static const pa_daemon_conf default_conf = {
62    .cmd = PA_CMD_DAEMON,
63    .daemonize = false,
64    .fail = true,
65    .high_priority = true,
66    .nice_level = -11,
67    .realtime_scheduling = true,
68    .realtime_priority = 5,  /* Half of JACK's default rtprio */
69    .disallow_module_loading = false,
70    .disallow_exit = false,
71    .flat_volumes = false,
72    .rescue_streams = true,
73    .exit_idle_time = -1,
74    .scache_idle_time = 20,
75    .script_commands = NULL,
76    .dl_search_path = NULL,
77    .load_default_script_file = true,
78    .default_script_file = NULL,
79    .log_target = NULL,
80    .log_level = PA_LOG_NOTICE,
81    .log_backtrace = 0,
82    .log_meta = false,
83    .log_time = false,
84    .resample_method = PA_RESAMPLER_AUTO,
85    .avoid_resampling = false,
86    .disable_remixing = false,
87    .remixing_use_all_sink_channels = true,
88    .remixing_produce_lfe = false,
89    .remixing_consume_lfe = false,
90    .lfe_crossover_freq = 0,
91    .config_file = NULL,
92    .use_pid_file = true,
93    .system_instance = false,
94#ifdef HAVE_DBUS
95    .local_server_type = PA_SERVER_TYPE_UNSET, /* The actual default is _USER, but we have to detect when the user doesn't specify this option. */
96#endif
97    .no_cpu_limit = true,
98    .disable_shm = false,
99    .disable_memfd = false,
100    .lock_memory = false,
101    .deferred_volume = true,
102    .default_n_fragments = 4,
103    .default_fragment_size_msec = 25,
104    .deferred_volume_safety_margin_usec = 8000,
105    .deferred_volume_extra_delay_usec = 0,
106    .default_sample_spec = { .format = PA_SAMPLE_S16NE, .rate = 44100, .channels = 2 },
107    .alternate_sample_rate = 48000,
108    .default_channel_map = { .channels = 2, .map = { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT } },
109    .shm_size = 0
110#ifdef HAVE_SYS_RESOURCE_H
111   ,.rlimit_fsize = { .value = 0, .is_set = false },
112    .rlimit_data = { .value = 0, .is_set = false },
113    .rlimit_stack = { .value = 0, .is_set = false },
114    .rlimit_core = { .value = 0, .is_set = false }
115#ifdef RLIMIT_RSS
116   ,.rlimit_rss = { .value = 0, .is_set = false }
117#endif
118#ifdef RLIMIT_NPROC
119   ,.rlimit_nproc = { .value = 0, .is_set = false }
120#endif
121#ifdef RLIMIT_NOFILE
122   ,.rlimit_nofile = { .value = 256, .is_set = true }
123#endif
124#ifdef RLIMIT_MEMLOCK
125   ,.rlimit_memlock = { .value = 0, .is_set = false }
126#endif
127#ifdef RLIMIT_AS
128   ,.rlimit_as = { .value = 0, .is_set = false }
129#endif
130#ifdef RLIMIT_LOCKS
131   ,.rlimit_locks = { .value = 0, .is_set = false }
132#endif
133#ifdef RLIMIT_SIGPENDING
134   ,.rlimit_sigpending = { .value = 0, .is_set = false }
135#endif
136#ifdef RLIMIT_MSGQUEUE
137   ,.rlimit_msgqueue = { .value = 0, .is_set = false }
138#endif
139#ifdef RLIMIT_NICE
140   ,.rlimit_nice = { .value = 31, .is_set = true }     /* nice level of -11 */
141#endif
142#ifdef RLIMIT_RTPRIO
143   ,.rlimit_rtprio = { .value = 9, .is_set = true }    /* One below JACK's default for the server */
144#endif
145#ifdef RLIMIT_RTTIME
146   ,.rlimit_rttime = { .value = 200*PA_USEC_PER_MSEC, .is_set = true } /* rtkit's limit is 200 ms */
147#endif
148#endif
149};
150
151pa_daemon_conf *pa_daemon_conf_new(void) {
152    pa_daemon_conf *c;
153
154    c = pa_xnewdup(pa_daemon_conf, &default_conf, 1);
155
156#ifdef OS_IS_WIN32
157    c->dl_search_path = pa_sprintf_malloc("%s" PA_PATH_SEP "lib" PA_PATH_SEP "pulse-%d.%d" PA_PATH_SEP "modules",
158                                          pa_win32_get_toplevel(NULL), PA_MAJOR, PA_MINOR);
159#else
160#ifdef HAVE_RUNNING_FROM_BUILD_TREE
161    if (pa_run_from_build_tree()) {
162        pa_log_notice("Detected that we are run from the build tree, fixing search path.");
163#ifdef MESON_BUILD
164        c->dl_search_path = pa_xstrdup(PA_BUILDDIR PA_PATH_SEP "src" PA_PATH_SEP "modules");
165#else
166        c->dl_search_path = pa_xstrdup(PA_BUILDDIR);
167#endif // Endof #ifdef MESON_BUILD
168    } else
169#endif // Endof #ifdef HAVE_RUNNING_FROM_BUILD_TREE
170        c->dl_search_path = pa_xstrdup(PA_DLSEARCHPATH);
171#endif // Endof #ifdef OS_IS_WIN32
172
173    return c;
174}
175
176void pa_daemon_conf_free(pa_daemon_conf *c) {
177    pa_assert(c);
178
179    pa_xfree(c->script_commands);
180    pa_xfree(c->dl_search_path);
181    pa_xfree(c->default_script_file);
182
183    if (c->log_target)
184        pa_log_target_free(c->log_target);
185
186    pa_xfree(c->config_file);
187    pa_xfree(c);
188}
189
190int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string) {
191    pa_log_target *log_target = NULL;
192
193    pa_assert(c);
194    pa_assert(string);
195
196    if (!pa_streq(string, "auto")) {
197        log_target = pa_log_parse_target(string);
198
199        if (!log_target)
200            return -1;
201    }
202
203    c->log_target = log_target;
204
205    return 0;
206}
207
208int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string) {
209    uint32_t u;
210    pa_assert(c);
211    pa_assert(string);
212
213    if (pa_atou(string, &u) >= 0) {
214        if (u >= PA_LOG_LEVEL_MAX)
215            return -1;
216
217        c->log_level = (pa_log_level_t) u;
218    } else if (pa_startswith(string, "debug"))
219        c->log_level = PA_LOG_DEBUG;
220    else if (pa_startswith(string, "info"))
221        c->log_level = PA_LOG_INFO;
222    else if (pa_startswith(string, "notice"))
223        c->log_level = PA_LOG_NOTICE;
224    else if (pa_startswith(string, "warn"))
225        c->log_level = PA_LOG_WARN;
226    else if (pa_startswith(string, "err"))
227        c->log_level = PA_LOG_ERROR;
228    else
229        return -1;
230
231    return 0;
232}
233
234int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string) {
235    int m;
236    pa_assert(c);
237    pa_assert(string);
238
239    if ((m = pa_parse_resample_method(string)) < 0)
240        return -1;
241
242    c->resample_method = m;
243    return 0;
244}
245
246int pa_daemon_conf_set_local_server_type(pa_daemon_conf *c, const char *string) {
247    pa_assert(c);
248    pa_assert(string);
249
250    if (pa_streq(string, "user"))
251        c->local_server_type = PA_SERVER_TYPE_USER;
252    else if (pa_streq(string, "system")) {
253        c->local_server_type = PA_SERVER_TYPE_SYSTEM;
254    } else if (pa_streq(string, "none")) {
255        c->local_server_type = PA_SERVER_TYPE_NONE;
256    } else
257        return -1;
258
259    return 0;
260}
261
262static int parse_log_target(pa_config_parser_state *state) {
263    pa_daemon_conf *c;
264
265    pa_assert(state);
266
267    c = state->data;
268
269    if (pa_daemon_conf_set_log_target(c, state->rvalue) < 0) {
270        pa_log(_("[%s:%u] Invalid log target '%s'."), state->filename, state->lineno, state->rvalue);
271        return -1;
272    }
273
274    return 0;
275}
276
277static int parse_log_level(pa_config_parser_state *state) {
278    pa_daemon_conf *c;
279
280    pa_assert(state);
281
282    c = state->data;
283
284    if (pa_daemon_conf_set_log_level(c, state->rvalue) < 0) {
285        pa_log(_("[%s:%u] Invalid log level '%s'."), state->filename, state->lineno, state->rvalue);
286        return -1;
287    }
288
289    return 0;
290}
291
292static int parse_resample_method(pa_config_parser_state *state) {
293    pa_daemon_conf *c;
294
295    pa_assert(state);
296
297    c = state->data;
298
299    if (pa_daemon_conf_set_resample_method(c, state->rvalue) < 0) {
300        pa_log(_("[%s:%u] Invalid resample method '%s'."), state->filename, state->lineno, state->rvalue);
301        return -1;
302    }
303
304    return 0;
305}
306
307#ifdef HAVE_SYS_RESOURCE_H
308static int parse_rlimit(pa_config_parser_state *state) {
309    struct pa_rlimit *r;
310
311    pa_assert(state);
312
313    r = state->data;
314
315    if (state->rvalue[strspn(state->rvalue, "\t ")] == 0) {
316        /* Empty string */
317        r->is_set = 0;
318        r->value = 0;
319    } else {
320        int32_t k;
321        if (pa_atoi(state->rvalue, &k) < 0) {
322            pa_log(_("[%s:%u] Invalid rlimit '%s'."), state->filename, state->lineno, state->rvalue);
323            return -1;
324        }
325        r->is_set = k >= 0;
326        r->value = k >= 0 ? (rlim_t) k : 0;
327    }
328
329    return 0;
330}
331#endif
332
333static int parse_sample_format(pa_config_parser_state *state) {
334    pa_daemon_conf *c;
335    pa_sample_format_t f;
336
337    pa_assert(state);
338
339    c = state->data;
340
341    if ((f = pa_parse_sample_format(state->rvalue)) < 0) {
342        pa_log(_("[%s:%u] Invalid sample format '%s'."), state->filename, state->lineno, state->rvalue);
343        return -1;
344    }
345
346    c->default_sample_spec.format = f;
347    return 0;
348}
349
350static int parse_sample_rate(pa_config_parser_state *state) {
351    pa_daemon_conf *c;
352    uint32_t r;
353
354    pa_assert(state);
355
356    c = state->data;
357
358    if (pa_atou(state->rvalue, &r) < 0 || !pa_sample_rate_valid(r)) {
359        pa_log(_("[%s:%u] Invalid sample rate '%s'."), state->filename, state->lineno, state->rvalue);
360        return -1;
361    }
362
363    c->default_sample_spec.rate = r;
364    return 0;
365}
366
367static int parse_alternate_sample_rate(pa_config_parser_state *state) {
368    pa_daemon_conf *c;
369    uint32_t r;
370
371    pa_assert(state);
372
373    c = state->data;
374
375    if (pa_atou(state->rvalue, &r) < 0 || !pa_sample_rate_valid(r)) {
376        pa_log(_("[%s:%u] Invalid sample rate '%s'."), state->filename, state->lineno, state->rvalue);
377        return -1;
378    }
379
380    c->alternate_sample_rate = r;
381    return 0;
382}
383
384struct channel_conf_info {
385    pa_daemon_conf *conf;
386    bool default_sample_spec_set;
387    bool default_channel_map_set;
388};
389
390static int parse_sample_channels(pa_config_parser_state *state) {
391    struct channel_conf_info *i;
392    int32_t n;
393
394    pa_assert(state);
395
396    i = state->data;
397
398    if (pa_atoi(state->rvalue, &n) < 0 || !pa_channels_valid(n)) {
399        pa_log(_("[%s:%u] Invalid sample channels '%s'."), state->filename, state->lineno, state->rvalue);
400        return -1;
401    }
402
403    i->conf->default_sample_spec.channels = (uint8_t) n;
404    i->default_sample_spec_set = true;
405    return 0;
406}
407
408static int parse_channel_map(pa_config_parser_state *state) {
409    struct channel_conf_info *i;
410
411    pa_assert(state);
412
413    i = state->data;
414
415    if (!pa_channel_map_parse(&i->conf->default_channel_map, state->rvalue)) {
416        pa_log(_("[%s:%u] Invalid channel map '%s'."), state->filename, state->lineno, state->rvalue);
417        return -1;
418    }
419
420    i->default_channel_map_set = true;
421    return 0;
422}
423
424static int parse_fragments(pa_config_parser_state *state) {
425    pa_daemon_conf *c;
426    int32_t n;
427
428    pa_assert(state);
429
430    c = state->data;
431
432    if (pa_atoi(state->rvalue, &n) < 0 || n < 2) {
433        pa_log(_("[%s:%u] Invalid number of fragments '%s'."), state->filename, state->lineno, state->rvalue);
434        return -1;
435    }
436
437    c->default_n_fragments = (unsigned) n;
438    return 0;
439}
440
441static int parse_fragment_size_msec(pa_config_parser_state *state) {
442    pa_daemon_conf *c;
443    int32_t n;
444
445    pa_assert(state);
446
447    c = state->data;
448
449    if (pa_atoi(state->rvalue, &n) < 0 || n < 1) {
450        pa_log(_("[%s:%u] Invalid fragment size '%s'."), state->filename, state->lineno, state->rvalue);
451        return -1;
452    }
453
454    c->default_fragment_size_msec = (unsigned) n;
455    return 0;
456}
457
458static int parse_nice_level(pa_config_parser_state *state) {
459    pa_daemon_conf *c;
460    int32_t level;
461
462    pa_assert(state);
463
464    c = state->data;
465
466    if (pa_atoi(state->rvalue, &level) < 0 || level < -20 || level > 19) {
467        pa_log(_("[%s:%u] Invalid nice level '%s'."), state->filename, state->lineno, state->rvalue);
468        return -1;
469    }
470
471    c->nice_level = (int) level;
472    return 0;
473}
474
475static int parse_rtprio(pa_config_parser_state *state) {
476#if !defined(OS_IS_WIN32) && defined(HAVE_SCHED_H)
477    pa_daemon_conf *c;
478    int32_t rtprio;
479#endif
480
481    pa_assert(state);
482
483#ifdef OS_IS_WIN32
484    pa_log("[%s:%u] Realtime priority not available on win32.", state->filename, state->lineno);
485#else
486# ifdef HAVE_SCHED_H
487    c = state->data;
488
489    if (pa_atoi(state->rvalue, &rtprio) < 0 || rtprio < sched_get_priority_min(SCHED_FIFO) || rtprio > sched_get_priority_max(SCHED_FIFO)) {
490        pa_log("[%s:%u] Invalid realtime priority '%s'.", state->filename, state->lineno, state->rvalue);
491        return -1;
492    }
493
494    c->realtime_priority = (int) rtprio;
495# endif
496#endif /* OS_IS_WIN32 */
497
498    return 0;
499}
500
501static int parse_disable_lfe_remix(pa_config_parser_state *state) {
502    pa_daemon_conf *c;
503    int k;
504
505    pa_assert(state);
506    c = state->data;
507
508    if ((k = pa_parse_boolean(state->rvalue)) < 0) {
509        pa_log("[%s:%u] Failed to parse boolean value: %s", state->filename, state->lineno, state->rvalue);
510        return -1;
511    }
512
513    c->remixing_produce_lfe = c->remixing_consume_lfe = !k;
514
515    pa_log("[%s:%u] Deprecated option 'disable-lfe-remixing' found.", state->filename, state->lineno);
516    pa_log("[%s:%u] Please migrate to 'remixing-produce-lfe' and 'remixing-consume-lfe', set both to '%s'.",
517           state->filename, state->lineno, pa_yes_no(c->remixing_produce_lfe));
518
519    return 0;
520}
521
522static int parse_enable_lfe_remix(pa_config_parser_state *state) {
523    pa_daemon_conf *c;
524    int k;
525
526    pa_assert(state);
527    c = state->data;
528
529    if ((k = pa_parse_boolean(state->rvalue)) < 0) {
530        pa_log("[%s:%u] Failed to parse boolean value: %s", state->filename, state->lineno, state->rvalue);
531        return -1;
532    }
533
534    c->remixing_produce_lfe = c->remixing_consume_lfe = k;
535
536    pa_log("[%s:%u] Deprecated option 'enable-lfe-remixing' found.", state->filename, state->lineno);
537    pa_log("[%s:%u] Please migrate to 'remixing-produce-lfe' and 'remixing-consume-lfe', set both to '%s'.",
538           state->filename, state->lineno, pa_yes_no(c->remixing_produce_lfe));
539
540    return 0;
541}
542
543#ifdef HAVE_DBUS
544static int parse_server_type(pa_config_parser_state *state) {
545    pa_daemon_conf *c;
546
547    pa_assert(state);
548
549    c = state->data;
550
551    if (pa_daemon_conf_set_local_server_type(c, state->rvalue) < 0) {
552        pa_log(_("[%s:%u] Invalid server type '%s'."), state->filename, state->lineno, state->rvalue);
553        return -1;
554    }
555
556    return 0;
557}
558#endif
559
560int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
561    int r = -1;
562    FILE *f = NULL;
563    struct channel_conf_info ci;
564    pa_config_item table[] = {
565        { "daemonize",                  pa_config_parse_bool,     &c->daemonize, NULL },
566        { "fail",                       pa_config_parse_bool,     &c->fail, NULL },
567        { "high-priority",              pa_config_parse_bool,     &c->high_priority, NULL },
568        { "realtime-scheduling",        pa_config_parse_bool,     &c->realtime_scheduling, NULL },
569        { "disallow-module-loading",    pa_config_parse_bool,     &c->disallow_module_loading, NULL },
570        { "allow-module-loading",       pa_config_parse_not_bool, &c->disallow_module_loading, NULL },
571        { "disallow-exit",              pa_config_parse_bool,     &c->disallow_exit, NULL },
572        { "allow-exit",                 pa_config_parse_not_bool, &c->disallow_exit, NULL },
573        { "use-pid-file",               pa_config_parse_bool,     &c->use_pid_file, NULL },
574        { "system-instance",            pa_config_parse_bool,     &c->system_instance, NULL },
575#ifdef HAVE_DBUS
576        { "local-server-type",          parse_server_type,        c, NULL },
577#endif
578        { "no-cpu-limit",               pa_config_parse_bool,     &c->no_cpu_limit, NULL },
579        { "cpu-limit",                  pa_config_parse_not_bool, &c->no_cpu_limit, NULL },
580        { "disable-shm",                pa_config_parse_bool,     &c->disable_shm, NULL },
581        { "enable-shm",                 pa_config_parse_not_bool, &c->disable_shm, NULL },
582        { "enable-memfd",               pa_config_parse_not_bool, &c->disable_memfd, NULL },
583        { "flat-volumes",               pa_config_parse_bool,     &c->flat_volumes, NULL },
584        { "rescue-streams",             pa_config_parse_bool,     &c->rescue_streams, NULL },
585        { "lock-memory",                pa_config_parse_bool,     &c->lock_memory, NULL },
586        { "enable-deferred-volume",     pa_config_parse_bool,     &c->deferred_volume, NULL },
587        { "exit-idle-time",             pa_config_parse_int,      &c->exit_idle_time, NULL },
588        { "scache-idle-time",           pa_config_parse_int,      &c->scache_idle_time, NULL },
589        { "realtime-priority",          parse_rtprio,             c, NULL },
590        { "dl-search-path",             pa_config_parse_string,   &c->dl_search_path, NULL },
591        { "default-script-file",        pa_config_parse_string,   &c->default_script_file, NULL },
592        { "log-target",                 parse_log_target,         c, NULL },
593        { "log-level",                  parse_log_level,          c, NULL },
594        { "verbose",                    parse_log_level,          c, NULL },
595        { "resample-method",            parse_resample_method,    c, NULL },
596        { "default-sample-format",      parse_sample_format,      c, NULL },
597        { "default-sample-rate",        parse_sample_rate,        c, NULL },
598        { "alternate-sample-rate",      parse_alternate_sample_rate, c, NULL },
599        { "default-sample-channels",    parse_sample_channels,    &ci,  NULL },
600        { "default-channel-map",        parse_channel_map,        &ci,  NULL },
601        { "default-fragments",          parse_fragments,          c, NULL },
602        { "default-fragment-size-msec", parse_fragment_size_msec, c, NULL },
603        { "deferred-volume-safety-margin-usec",
604                                        pa_config_parse_unsigned, &c->deferred_volume_safety_margin_usec, NULL },
605        { "deferred-volume-extra-delay-usec",
606                                        pa_config_parse_int,      &c->deferred_volume_extra_delay_usec, NULL },
607        { "nice-level",                 parse_nice_level,         c, NULL },
608        { "avoid-resampling",           pa_config_parse_bool,     &c->avoid_resampling, NULL },
609        { "disable-remixing",           pa_config_parse_bool,     &c->disable_remixing, NULL },
610        { "enable-remixing",            pa_config_parse_not_bool, &c->disable_remixing, NULL },
611        { "remixing-use-all-sink-channels",
612                                        pa_config_parse_bool,     &c->remixing_use_all_sink_channels, NULL },
613        { "disable-lfe-remixing",       parse_disable_lfe_remix,  c, NULL },
614        { "enable-lfe-remixing",        parse_enable_lfe_remix,   c, NULL },
615        { "remixing-produce-lfe",       pa_config_parse_bool,     &c->remixing_produce_lfe, NULL },
616        { "remixing-consume-lfe",       pa_config_parse_bool,     &c->remixing_consume_lfe, NULL },
617        { "lfe-crossover-freq",         pa_config_parse_unsigned, &c->lfe_crossover_freq, NULL },
618        { "load-default-script-file",   pa_config_parse_bool,     &c->load_default_script_file, NULL },
619        { "shm-size-bytes",             pa_config_parse_size,     &c->shm_size, NULL },
620        { "log-meta",                   pa_config_parse_bool,     &c->log_meta, NULL },
621        { "log-time",                   pa_config_parse_bool,     &c->log_time, NULL },
622        { "log-backtrace",              pa_config_parse_unsigned, &c->log_backtrace, NULL },
623#ifdef HAVE_SYS_RESOURCE_H
624        { "rlimit-fsize",               parse_rlimit,             &c->rlimit_fsize, NULL },
625        { "rlimit-data",                parse_rlimit,             &c->rlimit_data, NULL },
626        { "rlimit-stack",               parse_rlimit,             &c->rlimit_stack, NULL },
627        { "rlimit-core",                parse_rlimit,             &c->rlimit_core, NULL },
628#ifdef RLIMIT_RSS
629        { "rlimit-rss",                 parse_rlimit,             &c->rlimit_rss, NULL },
630#endif
631#ifdef RLIMIT_NOFILE
632        { "rlimit-nofile",              parse_rlimit,             &c->rlimit_nofile, NULL },
633#endif
634#ifdef RLIMIT_AS
635        { "rlimit-as",                  parse_rlimit,             &c->rlimit_as, NULL },
636#endif
637#ifdef RLIMIT_NPROC
638        { "rlimit-nproc",               parse_rlimit,             &c->rlimit_nproc, NULL },
639#endif
640#ifdef RLIMIT_MEMLOCK
641        { "rlimit-memlock",             parse_rlimit,             &c->rlimit_memlock, NULL },
642#endif
643#ifdef RLIMIT_LOCKS
644        { "rlimit-locks",               parse_rlimit,             &c->rlimit_locks, NULL },
645#endif
646#ifdef RLIMIT_SIGPENDING
647        { "rlimit-sigpending",          parse_rlimit,             &c->rlimit_sigpending, NULL },
648#endif
649#ifdef RLIMIT_MSGQUEUE
650        { "rlimit-msgqueue",            parse_rlimit,             &c->rlimit_msgqueue, NULL },
651#endif
652#ifdef RLIMIT_NICE
653        { "rlimit-nice",                parse_rlimit,             &c->rlimit_nice, NULL },
654#endif
655#ifdef RLIMIT_RTPRIO
656        { "rlimit-rtprio",              parse_rlimit,             &c->rlimit_rtprio, NULL },
657#endif
658#ifdef RLIMIT_RTTIME
659        { "rlimit-rttime",              parse_rlimit,             &c->rlimit_rttime, NULL },
660#endif
661#endif
662        { NULL,                         NULL,                     NULL, NULL },
663    };
664
665    pa_xfree(c->config_file);
666    c->config_file = NULL;
667
668    const char *default_config_file = DEFAULT_CONFIG_FILE;
669#ifdef HAVE_RUNNING_FROM_BUILD_TREE
670    if (pa_run_from_build_tree()) {
671        pa_log_notice("Detected that we are run from the build tree, fixing default daemon.conf file path.");
672#ifdef MESON_BUILD
673        default_config_file = PA_BUILDDIR PA_PATH_SEP "src" PA_PATH_SEP "daemon" PA_PATH_SEP "daemon.conf";
674#else
675        default_config_file = PA_BUILDDIR PA_PATH_SEP "daemon.conf";
676#endif // Endof #ifdef MESON_BUILD
677    }
678#endif // Endof #ifdef HAVE_RUNNING_FROM_BUILD_TREE
679
680    f = filename ?
681        pa_fopen_cloexec(c->config_file = pa_xstrdup(filename), "r") :
682        pa_open_config_file(default_config_file, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file);
683
684    if (!f && errno != ENOENT) {
685        pa_log_warn(_("Failed to open configuration file: %s"), pa_cstrerror(errno));
686        goto finish;
687    }
688
689    ci.default_channel_map_set = ci.default_sample_spec_set = false;
690    ci.conf = c;
691
692    r = f ? pa_config_parse(c->config_file, f, table, NULL, true, NULL) : 0;
693
694    if (r >= 0) {
695
696        /* Make sure that channel map and sample spec fit together */
697
698        if (ci.default_sample_spec_set &&
699            ci.default_channel_map_set &&
700            c->default_channel_map.channels != c->default_sample_spec.channels) {
701            pa_log_error(_("The specified default channel map has a different number of channels than the specified default number of channels."));
702            r = -1;
703            goto finish;
704        } else if (ci.default_sample_spec_set)
705            pa_channel_map_init_extend(&c->default_channel_map, c->default_sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
706        else if (ci.default_channel_map_set)
707            c->default_sample_spec.channels = c->default_channel_map.channels;
708    }
709
710finish:
711    if (f)
712        fclose(f);
713
714    return r;
715}
716
717int pa_daemon_conf_env(pa_daemon_conf *c) {
718    char *e;
719    pa_assert(c);
720
721    if ((e = getenv(ENV_DL_SEARCH_PATH))) {
722        pa_xfree(c->dl_search_path);
723        c->dl_search_path = pa_xstrdup(e);
724    }
725    if ((e = getenv(ENV_SCRIPT_FILE))) {
726        pa_xfree(c->default_script_file);
727        c->default_script_file = pa_xstrdup(e);
728    }
729
730    return 0;
731}
732
733const char *pa_daemon_conf_get_default_script_file(pa_daemon_conf *c) {
734    pa_assert(c);
735
736    if (!c->default_script_file) {
737        if (c->system_instance)
738            c->default_script_file = pa_find_config_file(DEFAULT_SYSTEM_SCRIPT_FILE, NULL, ENV_SCRIPT_FILE);
739        else
740            c->default_script_file = pa_find_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE);
741    }
742
743    return c->default_script_file;
744}
745
746FILE *pa_daemon_conf_open_default_script_file(pa_daemon_conf *c) {
747    FILE *f;
748    pa_assert(c);
749
750    if (!c->default_script_file) {
751        if (c->system_instance)
752            f = pa_open_config_file(DEFAULT_SYSTEM_SCRIPT_FILE, NULL, ENV_SCRIPT_FILE, &c->default_script_file);
753        else
754            f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file);
755    } else
756        f = pa_fopen_cloexec(c->default_script_file, "r");
757
758    return f;
759}
760
761char *pa_daemon_conf_dump(pa_daemon_conf *c) {
762    static const char* const log_level_to_string[] = {
763        [PA_LOG_DEBUG] = "debug",
764        [PA_LOG_INFO] = "info",
765        [PA_LOG_NOTICE] = "notice",
766        [PA_LOG_WARN] = "warning",
767        [PA_LOG_ERROR] = "error"
768    };
769
770#ifdef HAVE_DBUS
771    static const char* const server_type_to_string[] = {
772        [PA_SERVER_TYPE_UNSET] = "!!UNSET!!",
773        [PA_SERVER_TYPE_USER] = "user",
774        [PA_SERVER_TYPE_SYSTEM] = "system",
775        [PA_SERVER_TYPE_NONE] = "none"
776    };
777#endif
778
779    pa_strbuf *s;
780    char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
781    char *log_target = NULL;
782
783    pa_assert(c);
784
785    s = pa_strbuf_new();
786
787    if (c->config_file)
788        pa_strbuf_printf(s, _("### Read from configuration file: %s ###\n"), c->config_file);
789
790    pa_assert(c->log_level < PA_LOG_LEVEL_MAX);
791
792    if (c->log_target)
793        log_target = pa_log_target_to_string(c->log_target);
794
795    pa_strbuf_printf(s, "daemonize = %s\n", pa_yes_no(c->daemonize));
796    pa_strbuf_printf(s, "fail = %s\n", pa_yes_no(c->fail));
797    pa_strbuf_printf(s, "high-priority = %s\n", pa_yes_no(c->high_priority));
798    pa_strbuf_printf(s, "nice-level = %i\n", c->nice_level);
799    pa_strbuf_printf(s, "realtime-scheduling = %s\n", pa_yes_no(c->realtime_scheduling));
800    pa_strbuf_printf(s, "realtime-priority = %i\n", c->realtime_priority);
801    pa_strbuf_printf(s, "allow-module-loading = %s\n", pa_yes_no(!c->disallow_module_loading));
802    pa_strbuf_printf(s, "allow-exit = %s\n", pa_yes_no(!c->disallow_exit));
803    pa_strbuf_printf(s, "use-pid-file = %s\n", pa_yes_no(c->use_pid_file));
804    pa_strbuf_printf(s, "system-instance = %s\n", pa_yes_no(c->system_instance));
805#ifdef HAVE_DBUS
806    pa_strbuf_printf(s, "local-server-type = %s\n", server_type_to_string[c->local_server_type]);
807#endif
808    pa_strbuf_printf(s, "cpu-limit = %s\n", pa_yes_no(!c->no_cpu_limit));
809    pa_strbuf_printf(s, "enable-shm = %s\n", pa_yes_no(!c->disable_shm));
810    pa_strbuf_printf(s, "flat-volumes = %s\n", pa_yes_no(c->flat_volumes));
811    pa_strbuf_printf(s, "rescue-streams = %s\n", pa_yes_no(c->rescue_streams));
812    pa_strbuf_printf(s, "lock-memory = %s\n", pa_yes_no(c->lock_memory));
813    pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time);
814    pa_strbuf_printf(s, "scache-idle-time = %i\n", c->scache_idle_time);
815    pa_strbuf_printf(s, "dl-search-path = %s\n", pa_strempty(c->dl_search_path));
816    pa_strbuf_printf(s, "default-script-file = %s\n", pa_strempty(pa_daemon_conf_get_default_script_file(c)));
817    pa_strbuf_printf(s, "load-default-script-file = %s\n", pa_yes_no(c->load_default_script_file));
818    pa_strbuf_printf(s, "log-target = %s\n", pa_strempty(log_target));
819    pa_strbuf_printf(s, "log-level = %s\n", log_level_to_string[c->log_level]);
820    pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method));
821    pa_strbuf_printf(s, "avoid-resampling = %s\n", pa_yes_no(c->avoid_resampling));
822    pa_strbuf_printf(s, "enable-remixing = %s\n", pa_yes_no(!c->disable_remixing));
823    pa_strbuf_printf(s, "remixing-use-all-sink-channels = %s\n", pa_yes_no(c->remixing_use_all_sink_channels));
824    pa_strbuf_printf(s, "remixing-produce-lfe = %s\n", pa_yes_no(c->remixing_produce_lfe));
825    pa_strbuf_printf(s, "remixing-consume-lfe = %s\n", pa_yes_no(c->remixing_consume_lfe));
826    pa_strbuf_printf(s, "lfe-crossover-freq = %u\n", c->lfe_crossover_freq);
827    pa_strbuf_printf(s, "default-sample-format = %s\n", pa_sample_format_to_string(c->default_sample_spec.format));
828    pa_strbuf_printf(s, "default-sample-rate = %u\n", c->default_sample_spec.rate);
829    pa_strbuf_printf(s, "alternate-sample-rate = %u\n", c->alternate_sample_rate);
830    pa_strbuf_printf(s, "default-sample-channels = %u\n", c->default_sample_spec.channels);
831    pa_strbuf_printf(s, "default-channel-map = %s\n", pa_channel_map_snprint(cm, sizeof(cm), &c->default_channel_map));
832    pa_strbuf_printf(s, "default-fragments = %u\n", c->default_n_fragments);
833    pa_strbuf_printf(s, "default-fragment-size-msec = %u\n", c->default_fragment_size_msec);
834    pa_strbuf_printf(s, "enable-deferred-volume = %s\n", pa_yes_no(c->deferred_volume));
835    pa_strbuf_printf(s, "deferred-volume-safety-margin-usec = %u\n", c->deferred_volume_safety_margin_usec);
836    pa_strbuf_printf(s, "deferred-volume-extra-delay-usec = %d\n", c->deferred_volume_extra_delay_usec);
837    pa_strbuf_printf(s, "shm-size-bytes = %lu\n", (unsigned long) c->shm_size);
838    pa_strbuf_printf(s, "log-meta = %s\n", pa_yes_no(c->log_meta));
839    pa_strbuf_printf(s, "log-time = %s\n", pa_yes_no(c->log_time));
840    pa_strbuf_printf(s, "log-backtrace = %u\n", c->log_backtrace);
841#ifdef HAVE_SYS_RESOURCE_H
842    pa_strbuf_printf(s, "rlimit-fsize = %li\n", c->rlimit_fsize.is_set ? (long int) c->rlimit_fsize.value : -1);
843    pa_strbuf_printf(s, "rlimit-data = %li\n", c->rlimit_data.is_set ? (long int) c->rlimit_data.value : -1);
844    pa_strbuf_printf(s, "rlimit-stack = %li\n", c->rlimit_stack.is_set ? (long int) c->rlimit_stack.value : -1);
845    pa_strbuf_printf(s, "rlimit-core = %li\n", c->rlimit_core.is_set ? (long int) c->rlimit_core.value : -1);
846#ifdef RLIMIT_RSS
847    pa_strbuf_printf(s, "rlimit-rss = %li\n", c->rlimit_rss.is_set ? (long int) c->rlimit_rss.value : -1);
848#endif
849#ifdef RLIMIT_AS
850    pa_strbuf_printf(s, "rlimit-as = %li\n", c->rlimit_as.is_set ? (long int) c->rlimit_as.value : -1);
851#endif
852#ifdef RLIMIT_NPROC
853    pa_strbuf_printf(s, "rlimit-nproc = %li\n", c->rlimit_nproc.is_set ? (long int) c->rlimit_nproc.value : -1);
854#endif
855#ifdef RLIMIT_NOFILE
856    pa_strbuf_printf(s, "rlimit-nofile = %li\n", c->rlimit_nofile.is_set ? (long int) c->rlimit_nofile.value : -1);
857#endif
858#ifdef RLIMIT_MEMLOCK
859    pa_strbuf_printf(s, "rlimit-memlock = %li\n", c->rlimit_memlock.is_set ? (long int) c->rlimit_memlock.value : -1);
860#endif
861#ifdef RLIMIT_LOCKS
862    pa_strbuf_printf(s, "rlimit-locks = %li\n", c->rlimit_locks.is_set ? (long int) c->rlimit_locks.value : -1);
863#endif
864#ifdef RLIMIT_SIGPENDING
865    pa_strbuf_printf(s, "rlimit-sigpending = %li\n", c->rlimit_sigpending.is_set ? (long int) c->rlimit_sigpending.value : -1);
866#endif
867#ifdef RLIMIT_MSGQUEUE
868    pa_strbuf_printf(s, "rlimit-msgqueue = %li\n", c->rlimit_msgqueue.is_set ? (long int) c->rlimit_msgqueue.value : -1);
869#endif
870#ifdef RLIMIT_NICE
871    pa_strbuf_printf(s, "rlimit-nice = %li\n", c->rlimit_nice.is_set ? (long int) c->rlimit_nice.value : -1);
872#endif
873#ifdef RLIMIT_RTPRIO
874    pa_strbuf_printf(s, "rlimit-rtprio = %li\n", c->rlimit_rtprio.is_set ? (long int) c->rlimit_rtprio.value : -1);
875#endif
876#ifdef RLIMIT_RTTIME
877    pa_strbuf_printf(s, "rlimit-rttime = %li\n", c->rlimit_rttime.is_set ? (long int) c->rlimit_rttime.value : -1);
878#endif
879#endif
880
881    pa_xfree(log_target);
882
883    return pa_strbuf_to_string_free(s);
884}
885