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 <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <ltdl.h>
31 #include <sys/stat.h>
32 #include <dirent.h>
33 #include <time.h>
34 #include <fcntl.h>
35 #include <ctype.h>
36 
37 #include <pulse/xmalloc.h>
38 #include <pulse/error.h>
39 
40 #include <pulsecore/module.h>
41 #include <pulsecore/sink.h>
42 #include <pulsecore/source.h>
43 #include <pulsecore/client.h>
44 #include <pulsecore/sink-input.h>
45 #include <pulsecore/source-output.h>
46 #include <pulsecore/tokenizer.h>
47 #include <pulsecore/strbuf.h>
48 #include <pulsecore/namereg.h>
49 #include <pulsecore/cli-text.h>
50 #include <pulsecore/core-scache.h>
51 #include <pulsecore/sound-file.h>
52 #include <pulsecore/play-memchunk.h>
53 #include <pulsecore/sound-file-stream.h>
54 #include <pulsecore/shared.h>
55 #include <pulsecore/core-util.h>
56 #include <pulsecore/message-handler.h>
57 #include <pulsecore/core-error.h>
58 #include <pulsecore/modinfo.h>
59 #include <pulsecore/dynarray.h>
60 
61 #include "cli-command.h"
62 
63 struct command {
64     const char *name;
65     int (*proc) (pa_core *c, pa_tokenizer*t, pa_strbuf *buf, bool *fail);
66     const char *help;
67     unsigned args;
68 };
69 
70 #define META_INCLUDE ".include"
71 #define META_FAIL ".fail"
72 #define META_NOFAIL ".nofail"
73 #define META_IFEXISTS ".ifexists"
74 #define META_ELSE ".else"
75 #define META_ENDIF ".endif"
76 
77 enum {
78     IFSTATE_NONE = -1,
79     IFSTATE_FALSE = 0,
80     IFSTATE_TRUE = 1,
81 };
82 
83 /* Prototypes for all available commands */
84 static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
85 static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
86 static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
87 static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
88 static int pa_cli_command_cards(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
89 static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
90 static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
91 static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
92 static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
93 static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
94 static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
95 static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
96 static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
97 static int pa_cli_command_describe(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
98 static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
99 static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
100 static int pa_cli_command_source_output_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
101 static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
102 static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
103 static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
104 static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
105 static int pa_cli_command_source_output_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
106 static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
107 static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
108 static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
109 static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
110 static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
111 static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
112 static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
113 static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
114 static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
115 static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
116 static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
117 static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
118 static int pa_cli_command_list_shared_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
119 static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
120 static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
121 static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
122 static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
123 static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
124 static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
125 static int pa_cli_command_log_target(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
126 static int pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
127 static int pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
128 static int pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
129 static int pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
130 static int pa_cli_command_update_sink_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
131 static int pa_cli_command_update_source_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
132 static int pa_cli_command_update_sink_input_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
133 static int pa_cli_command_update_source_output_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
134 static int pa_cli_command_card_profile(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
135 static int pa_cli_command_sink_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
136 static int pa_cli_command_source_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
137 static int pa_cli_command_port_offset(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
138 static int pa_cli_command_dump_volumes(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
139 static int pa_cli_command_send_message_to_object(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
140 
141 /* A method table for all available commands */
142 
143 static const struct command commands[] = {
144     { "help",                    pa_cli_command_help,               "Show this help",               1 },
145     { "list-modules",            pa_cli_command_modules,            "List loaded modules",          1 },
146     { "list-cards",              pa_cli_command_cards,              "List cards",                   1 },
147     { "list-sinks",              pa_cli_command_sinks,              "List loaded sinks",            1 },
148     { "list-sources",            pa_cli_command_sources,            "List loaded sources",          1 },
149     { "list-clients",            pa_cli_command_clients,            "List loaded clients",          1 },
150     { "list-sink-inputs",        pa_cli_command_sink_inputs,        "List sink inputs",             1 },
151     { "list-source-outputs",     pa_cli_command_source_outputs,     "List source outputs",          1 },
152     { "stat",                    pa_cli_command_stat,               "Show memory block statistics", 1 },
153     { "info",                    pa_cli_command_info,               "Show comprehensive status",    1 },
154     { "ls",                      pa_cli_command_info,               NULL,                           1 },
155     { "list",                    pa_cli_command_info,               NULL,                           1 },
156     { "load-module",             pa_cli_command_load,               "Load a module (args: name, arguments)", 3},
157     { "unload-module",           pa_cli_command_unload,             "Unload a module (args: index|name)", 2},
158     { "describe-module",         pa_cli_command_describe,           "Describe a module (arg: name)", 2},
159     { "set-sink-volume",         pa_cli_command_sink_volume,        "Set the volume of a sink (args: index|name, volume)", 3},
160     { "set-source-volume",       pa_cli_command_source_volume,      "Set the volume of a source (args: index|name, volume)", 3},
161     { "set-sink-mute",           pa_cli_command_sink_mute,          "Set the mute switch of a sink (args: index|name, bool)", 3},
162     { "set-source-mute",         pa_cli_command_source_mute,        "Set the mute switch of a source (args: index|name, bool)", 3},
163     { "set-sink-input-volume",   pa_cli_command_sink_input_volume,  "Set the volume of a sink input (args: index, volume)", 3},
164     { "set-source-output-volume",pa_cli_command_source_output_volume,"Set the volume of a source output (args: index, volume)", 3},
165     { "set-sink-input-mute",     pa_cli_command_sink_input_mute,    "Set the mute switch of a sink input (args: index, bool)", 3},
166     { "set-source-output-mute",  pa_cli_command_source_output_mute, "Set the mute switch of a source output (args: index, bool)", 3},
167     { "set-default-sink",        pa_cli_command_sink_default,       "Set the default sink (args: index|name)", 2},
168     { "set-default-source",      pa_cli_command_source_default,     "Set the default source (args: index|name)", 2},
169     { "set-card-profile",        pa_cli_command_card_profile,       "Change the profile of a card (args: index|name, profile-name)", 3},
170     { "set-sink-port",           pa_cli_command_sink_port,          "Change the port of a sink (args: index|name, port-name)", 3},
171     { "set-source-port",         pa_cli_command_source_port,        "Change the port of a source (args: index|name, port-name)", 3},
172     { "set-port-latency-offset", pa_cli_command_port_offset,        "Change the latency of a port (args: card-index|card-name, port-name, latency-offset)", 4},
173     { "suspend-sink",            pa_cli_command_suspend_sink,       "Suspend sink (args: index|name, bool)", 3},
174     { "suspend-source",          pa_cli_command_suspend_source,     "Suspend source (args: index|name, bool)", 3},
175     { "suspend",                 pa_cli_command_suspend,            "Suspend all sinks and all sources (args: bool)", 2},
176     { "move-sink-input",         pa_cli_command_move_sink_input,    "Move sink input to another sink (args: index, sink)", 3},
177     { "move-source-output",      pa_cli_command_move_source_output, "Move source output to another source (args: index, source)", 3},
178     { "update-sink-proplist",    pa_cli_command_update_sink_proplist, "Update the properties of a sink (args: index|name, properties)", 3},
179     { "update-source-proplist",  pa_cli_command_update_source_proplist, "Update the properties of a source (args: index|name, properties)", 3},
180     { "update-sink-input-proplist", pa_cli_command_update_sink_input_proplist, "Update the properties of a sink input (args: index, properties)", 3},
181     { "update-source-output-proplist", pa_cli_command_update_source_output_proplist, "Update the properties of a source output (args: index, properties)", 3},
182     { "list-samples",            pa_cli_command_scache_list,        "List all entries in the sample cache", 1},
183     { "play-sample",             pa_cli_command_scache_play,        "Play a sample from the sample cache (args: name, sink|index)", 3},
184     { "remove-sample",           pa_cli_command_scache_remove,      "Remove a sample from the sample cache (args: name)", 2},
185     { "load-sample",             pa_cli_command_scache_load,        "Load a sound file into the sample cache (args: name, filename)", 3},
186     { "load-sample-lazy",        pa_cli_command_scache_load,        "Lazily load a sound file into the sample cache (args: name, filename)", 3},
187     { "load-sample-dir-lazy",    pa_cli_command_scache_load_dir,    "Lazily load all files in a directory into the sample cache (args: pathname)", 2},
188     { "kill-client",             pa_cli_command_kill_client,        "Kill a client (args: index)", 2},
189     { "kill-sink-input",         pa_cli_command_kill_sink_input,    "Kill a sink input (args: index)", 2},
190     { "kill-source-output",      pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2},
191     { "set-log-target",          pa_cli_command_log_target,         "Change the log target (args: null|auto|syslog|stderr|file:PATH|newfile:PATH)", 2},
192     { "set-log-level",           pa_cli_command_log_level,          "Change the log level (args: numeric level)", 2},
193     { "set-log-meta",            pa_cli_command_log_meta,           "Show source code location in log messages (args: bool)", 2},
194     { "set-log-time",            pa_cli_command_log_time,           "Show timestamps in log messages (args: bool)", 2},
195     { "set-log-backtrace",       pa_cli_command_log_backtrace,      "Show backtrace in log messages (args: frames)", 2},
196     { "send-message",            pa_cli_command_send_message_to_object, "Send a message to an object (args: recipient, message, message_parameters)", 4},
197     { "play-file",               pa_cli_command_play_file,          "Play a sound file (args: filename, sink|index)", 3},
198     { "dump",                    pa_cli_command_dump,               "Dump daemon configuration", 1},
199     { "dump-volumes",            pa_cli_command_dump_volumes,       "Debug: Show the state of all volumes", 1 },
200     { "shared",                  pa_cli_command_list_shared_props,  "Debug: Show shared properties", 1},
201     { "exit",                    pa_cli_command_exit,               "Terminate the daemon",         1 },
202     { "vacuum",                  pa_cli_command_vacuum,             NULL, 1},
203     { NULL, NULL, NULL, 0 }
204 };
205 
206 static const char whitespace[] = " \t\n\r";
207 static const char linebreak[] = "\n\r";
208 
parse_index(const char *n)209 static uint32_t parse_index(const char *n) {
210     uint32_t idx;
211 
212     if (pa_atou(n, &idx) < 0)
213         return (uint32_t) PA_IDXSET_INVALID;
214 
215     return idx;
216 }
217 
pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)218 static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
219     pa_core_assert_ref(c);
220     pa_assert(t);
221     pa_assert(buf);
222     pa_assert(fail);
223 
224     if (pa_core_exit(c, false, 0) < 0)
225         pa_strbuf_puts(buf, "Not allowed to terminate daemon.\n");
226 
227     return 0;
228 }
229 
pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)230 static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
231     const struct command*command;
232 
233     pa_core_assert_ref(c);
234     pa_assert(t);
235     pa_assert(buf);
236     pa_assert(fail);
237 
238     pa_strbuf_puts(buf, "Available commands:\n");
239 
240     for (command = commands; command->name; command++)
241         if (command->help)
242             pa_strbuf_printf(buf, "    %-25s %s\n", command->name, command->help);
243     return 0;
244 }
245 
pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)246 static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
247     char *s;
248 
249     pa_core_assert_ref(c);
250     pa_assert(t);
251     pa_assert(buf);
252     pa_assert(fail);
253 
254     pa_assert_se(s = pa_module_list_to_string(c));
255     pa_strbuf_puts(buf, s);
256     pa_xfree(s);
257     return 0;
258 }
259 
pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)260 static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
261     char *s;
262 
263     pa_core_assert_ref(c);
264     pa_assert(t);
265     pa_assert(buf);
266     pa_assert(fail);
267 
268     pa_assert_se(s = pa_client_list_to_string(c));
269     pa_strbuf_puts(buf, s);
270     pa_xfree(s);
271     return 0;
272 }
273 
pa_cli_command_cards(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)274 static int pa_cli_command_cards(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
275     char *s;
276 
277     pa_core_assert_ref(c);
278     pa_assert(t);
279     pa_assert(buf);
280     pa_assert(fail);
281 
282     pa_assert_se(s = pa_card_list_to_string(c));
283     pa_strbuf_puts(buf, s);
284     pa_xfree(s);
285     return 0;
286 }
287 
pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)288 static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
289     char *s;
290 
291     pa_core_assert_ref(c);
292     pa_assert(t);
293     pa_assert(buf);
294     pa_assert(fail);
295 
296     pa_assert_se(s = pa_sink_list_to_string(c));
297     pa_strbuf_puts(buf, s);
298     pa_xfree(s);
299     return 0;
300 }
301 
pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)302 static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
303     char *s;
304 
305     pa_core_assert_ref(c);
306     pa_assert(t);
307     pa_assert(buf);
308     pa_assert(fail);
309 
310     pa_assert_se(s = pa_source_list_to_string(c));
311     pa_strbuf_puts(buf, s);
312     pa_xfree(s);
313     return 0;
314 }
315 
pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)316 static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
317     char *s;
318 
319     pa_core_assert_ref(c);
320     pa_assert(t);
321     pa_assert(buf);
322     pa_assert(fail);
323 
324     pa_assert_se(s = pa_sink_input_list_to_string(c));
325     pa_strbuf_puts(buf, s);
326     pa_xfree(s);
327     return 0;
328 }
329 
pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)330 static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
331     char *s;
332 
333     pa_core_assert_ref(c);
334     pa_assert(t);
335     pa_assert(buf);
336     pa_assert(fail);
337 
338     pa_assert_se(s = pa_source_output_list_to_string(c));
339     pa_strbuf_puts(buf, s);
340     pa_xfree(s);
341     return 0;
342 }
343 
pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)344 static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
345     char ss[PA_SAMPLE_SPEC_SNPRINT_MAX];
346     char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
347     char bytes[PA_BYTES_SNPRINT_MAX];
348     const pa_mempool_stat *mstat;
349     unsigned k;
350 
351     static const char* const type_table[PA_MEMBLOCK_TYPE_MAX] = {
352         [PA_MEMBLOCK_POOL] = "POOL",
353         [PA_MEMBLOCK_POOL_EXTERNAL] = "POOL_EXTERNAL",
354         [PA_MEMBLOCK_APPENDED] = "APPENDED",
355         [PA_MEMBLOCK_USER] = "USER",
356         [PA_MEMBLOCK_FIXED] = "FIXED",
357         [PA_MEMBLOCK_IMPORTED] = "IMPORTED",
358     };
359 
360     pa_core_assert_ref(c);
361     pa_assert(t);
362     pa_assert(buf);
363     pa_assert(fail);
364 
365     mstat = pa_mempool_get_stat(c->mempool);
366 
367     pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n",
368                      (unsigned) pa_atomic_load(&mstat->n_allocated),
369                      pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->allocated_size)));
370 
371     pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n",
372                      (unsigned) pa_atomic_load(&mstat->n_accumulated),
373                      pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->accumulated_size)));
374 
375     pa_strbuf_printf(buf, "Memory blocks imported from other processes: %u, size: %s.\n",
376                      (unsigned) pa_atomic_load(&mstat->n_imported),
377                      pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->imported_size)));
378 
379     pa_strbuf_printf(buf, "Memory blocks exported to other processes: %u, size: %s.\n",
380                      (unsigned) pa_atomic_load(&mstat->n_exported),
381                      pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->exported_size)));
382 
383     pa_strbuf_printf(buf, "Total sample cache size: %s.\n",
384                      pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_scache_total_size(c)));
385 
386     pa_strbuf_printf(buf, "Default sample spec: %s\n",
387                      pa_sample_spec_snprint(ss, sizeof(ss), &c->default_sample_spec));
388 
389     pa_strbuf_printf(buf, "Default channel map: %s\n",
390                      pa_channel_map_snprint(cm, sizeof(cm), &c->default_channel_map));
391 
392     pa_strbuf_printf(buf, "Default sink name: %s\n"
393                      "Default source name: %s\n",
394                      c->default_sink ? c->default_sink->name : "none",
395                      c->default_source ? c->default_source->name : "none");
396 
397     for (k = 0; k < PA_MEMBLOCK_TYPE_MAX; k++)
398         pa_strbuf_printf(buf,
399                          "Memory blocks of type %s: %u allocated/%u accumulated.\n",
400                          type_table[k],
401                          (unsigned) pa_atomic_load(&mstat->n_allocated_by_type[k]),
402                          (unsigned) pa_atomic_load(&mstat->n_accumulated_by_type[k]));
403 
404     return 0;
405 }
406 
pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)407 static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
408     pa_core_assert_ref(c);
409     pa_assert(t);
410     pa_assert(buf);
411     pa_assert(fail);
412 
413     pa_cli_command_stat(c, t, buf, fail);
414     pa_cli_command_modules(c, t, buf, fail);
415     pa_cli_command_sinks(c, t, buf, fail);
416     pa_cli_command_sources(c, t, buf, fail);
417     pa_cli_command_clients(c, t, buf, fail);
418     pa_cli_command_cards(c, t, buf, fail);
419     pa_cli_command_sink_inputs(c, t, buf, fail);
420     pa_cli_command_source_outputs(c, t, buf, fail);
421     pa_cli_command_scache_list(c, t, buf, fail);
422     return 0;
423 }
424 
pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)425 static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
426     const char *name;
427     pa_error_code_t err;
428     pa_module *m = NULL;
429 
430     pa_core_assert_ref(c);
431     pa_assert(t);
432     pa_assert(buf);
433     pa_assert(fail);
434 
435     if (!(name = pa_tokenizer_get(t, 1))) {
436         pa_strbuf_puts(buf, "You need to specify the module name and optionally arguments.\n");
437         return -1;
438     }
439 
440     if ((err = pa_module_load(&m, c, name,  pa_tokenizer_get(t, 2))) < 0) {
441         if (err == PA_ERR_EXIST) {
442             pa_strbuf_puts(buf, "Module already loaded; ignoring.\n");
443         } else {
444             pa_strbuf_puts(buf, "Module load failed.\n");
445             return -1;
446         }
447     }
448 
449     return 0;
450 }
451 
pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)452 static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
453     pa_module *m;
454     uint32_t idx;
455     const char *i;
456     bool unloaded = false;
457 
458     pa_core_assert_ref(c);
459     pa_assert(t);
460     pa_assert(buf);
461     pa_assert(fail);
462 
463     if (!(i = pa_tokenizer_get(t, 1))) {
464         pa_strbuf_puts(buf, "You need to specify the module index or name.\n");
465         return -1;
466     }
467 
468     if (pa_atou(i, &idx) >= 0) {
469         if (!(m = pa_idxset_get_by_index(c->modules, idx))) {
470             pa_strbuf_puts(buf, "Invalid module index.\n");
471             return -1;
472         }
473 
474         pa_module_unload(m, false);
475 
476     } else {
477         PA_IDXSET_FOREACH(m, c->modules, idx)
478             if (pa_streq(i, m->name)) {
479                 unloaded = true;
480                 pa_module_unload(m, false);
481             }
482 
483         if (unloaded == false) {
484             pa_strbuf_printf(buf, "Module %s not loaded.\n", i);
485             return -1;
486         }
487     }
488 
489     return 0;
490 }
491 
pa_cli_command_describe(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)492 static int pa_cli_command_describe(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
493     const char *name;
494     pa_modinfo *i;
495 
496     pa_core_assert_ref(c);
497     pa_assert(t);
498     pa_assert(buf);
499     pa_assert(fail);
500 
501     if (!(name = pa_tokenizer_get(t, 1))) {
502         pa_strbuf_puts(buf, "You need to specify the module name.\n");
503         return -1;
504     }
505 
506     if ((i = pa_modinfo_get_by_name(name))) {
507 
508         pa_strbuf_printf(buf, "Name: %s\n", name);
509 
510         if (!i->description && !i->version && !i->author && !i->usage)
511             pa_strbuf_printf(buf, "No module information available\n");
512         else {
513             if (i->version)
514                 pa_strbuf_printf(buf, "Version: %s\n", i->version);
515             if (i->description)
516                 pa_strbuf_printf(buf, "Description: %s\n", i->description);
517             if (i->author)
518                 pa_strbuf_printf(buf, "Author: %s\n", i->author);
519             if (i->usage)
520                 pa_strbuf_printf(buf, "Usage: %s\n", i->usage);
521             pa_strbuf_printf(buf, "Load Once: %s\n", pa_yes_no(i->load_once));
522             if (i->deprecated)
523                 pa_strbuf_printf(buf, "Warning, deprecated: %s\n", i->deprecated);
524         }
525 
526         pa_modinfo_free(i);
527     } else
528         pa_strbuf_puts(buf, "Failed to open module.\n");
529 
530     return 0;
531 }
532 
pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)533 static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
534     const char *n, *v;
535     pa_sink *sink;
536     uint32_t volume;
537     pa_cvolume cvolume;
538 
539     pa_core_assert_ref(c);
540     pa_assert(t);
541     pa_assert(buf);
542     pa_assert(fail);
543 
544     if (!(n = pa_tokenizer_get(t, 1))) {
545         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
546         return -1;
547     }
548 
549     if (!(v = pa_tokenizer_get(t, 2))) {
550         pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n");
551         return -1;
552     }
553 
554     if (pa_atou(v, &volume) < 0) {
555         pa_strbuf_puts(buf, "Failed to parse volume.\n");
556         return -1;
557     }
558 
559     if (!PA_VOLUME_IS_VALID(volume)) {
560         pa_strbuf_puts(buf, "Volume outside permissible range.\n");
561         return -1;
562     }
563 
564     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
565         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
566         return -1;
567     }
568 
569     pa_cvolume_set(&cvolume, 1, volume);
570     pa_sink_set_volume(sink, &cvolume, true, true);
571     return 0;
572 }
573 
pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)574 static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
575     const char *n, *v;
576     pa_sink_input *si;
577     pa_volume_t volume;
578     pa_cvolume cvolume;
579     uint32_t idx;
580 
581     pa_core_assert_ref(c);
582     pa_assert(t);
583     pa_assert(buf);
584     pa_assert(fail);
585 
586     if (!(n = pa_tokenizer_get(t, 1))) {
587         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
588         return -1;
589     }
590 
591     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
592         pa_strbuf_puts(buf, "Failed to parse index.\n");
593         return -1;
594     }
595 
596     if (!(v = pa_tokenizer_get(t, 2))) {
597         pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n");
598         return -1;
599     }
600 
601     if (pa_atou(v, &volume) < 0) {
602         pa_strbuf_puts(buf, "Failed to parse volume.\n");
603         return -1;
604     }
605 
606     if (!PA_VOLUME_IS_VALID(volume)) {
607         pa_strbuf_puts(buf, "Volume outside permissible range.\n");
608         return -1;
609     }
610 
611     if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx))) {
612         pa_strbuf_puts(buf, "No sink input found with this index.\n");
613         return -1;
614     }
615 
616     if (!si->volume_writable) {
617         pa_strbuf_puts(buf, "This sink input's volume can't be changed.\n");
618         return -1;
619     }
620 
621     pa_cvolume_set(&cvolume, 1, volume);
622     pa_sink_input_set_volume(si, &cvolume, true, true);
623     return 0;
624 }
625 
pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)626 static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
627     const char *n, *v;
628     pa_source *source;
629     uint32_t volume;
630     pa_cvolume cvolume;
631 
632     pa_core_assert_ref(c);
633     pa_assert(t);
634     pa_assert(buf);
635     pa_assert(fail);
636 
637     if (!(n = pa_tokenizer_get(t, 1))) {
638         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
639         return -1;
640     }
641 
642     if (!(v = pa_tokenizer_get(t, 2))) {
643         pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n");
644         return -1;
645     }
646 
647     if (pa_atou(v, &volume) < 0) {
648         pa_strbuf_puts(buf, "Failed to parse volume.\n");
649         return -1;
650     }
651 
652     if (!PA_VOLUME_IS_VALID(volume)) {
653         pa_strbuf_puts(buf, "Volume outside permissible range.\n");
654         return -1;
655     }
656 
657     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
658         pa_strbuf_puts(buf, "No source found by this name or index.\n");
659         return -1;
660     }
661 
662     pa_cvolume_set(&cvolume, 1, volume);
663     pa_source_set_volume(source, &cvolume, true, true);
664     return 0;
665 }
666 
pa_cli_command_source_output_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)667 static int pa_cli_command_source_output_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
668     const char *n, *v;
669     pa_source_output *so;
670     pa_volume_t volume;
671     pa_cvolume cvolume;
672     uint32_t idx;
673 
674     pa_core_assert_ref(c);
675     pa_assert(t);
676     pa_assert(buf);
677     pa_assert(fail);
678 
679     if (!(n = pa_tokenizer_get(t, 1))) {
680         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
681         return -1;
682     }
683 
684     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
685         pa_strbuf_puts(buf, "Failed to parse index.\n");
686         return -1;
687     }
688 
689     if (!(v = pa_tokenizer_get(t, 2))) {
690         pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n");
691         return -1;
692     }
693 
694     if (pa_atou(v, &volume) < 0) {
695         pa_strbuf_puts(buf, "Failed to parse volume.\n");
696         return -1;
697     }
698 
699     if (!PA_VOLUME_IS_VALID(volume)) {
700         pa_strbuf_puts(buf, "Volume outside permissible range.\n");
701         return -1;
702     }
703 
704     if (!(so = pa_idxset_get_by_index(c->source_outputs, idx))) {
705         pa_strbuf_puts(buf, "No source output found with this index.\n");
706         return -1;
707     }
708 
709     if (!so->volume_writable) {
710         pa_strbuf_puts(buf, "This source output's volume can't be changed.\n");
711         return -1;
712     }
713 
714     pa_cvolume_set(&cvolume, 1, volume);
715     pa_source_output_set_volume(so, &cvolume, true, true);
716     return 0;
717 }
718 
pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)719 static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
720     const char *n, *m;
721     pa_sink *sink;
722     int mute;
723 
724     pa_core_assert_ref(c);
725     pa_assert(t);
726     pa_assert(buf);
727     pa_assert(fail);
728 
729     if (!(n = pa_tokenizer_get(t, 1))) {
730         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
731         return -1;
732     }
733 
734     if (!(m = pa_tokenizer_get(t, 2))) {
735         pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
736         return -1;
737     }
738 
739     if ((mute = pa_parse_boolean(m)) < 0) {
740         pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
741         return -1;
742     }
743 
744     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
745         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
746         return -1;
747     }
748 
749     pa_sink_set_mute(sink, mute, true);
750     return 0;
751 }
752 
pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)753 static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
754     const char *n, *m;
755     pa_source *source;
756     int mute;
757 
758     pa_core_assert_ref(c);
759     pa_assert(t);
760     pa_assert(buf);
761     pa_assert(fail);
762 
763     if (!(n = pa_tokenizer_get(t, 1))) {
764         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
765         return -1;
766     }
767 
768     if (!(m = pa_tokenizer_get(t, 2))) {
769         pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
770         return -1;
771     }
772 
773     if ((mute = pa_parse_boolean(m)) < 0) {
774         pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
775         return -1;
776     }
777 
778     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
779         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
780         return -1;
781     }
782 
783     pa_source_set_mute(source, mute, true);
784     return 0;
785 }
786 
pa_cli_command_update_sink_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)787 static int pa_cli_command_update_sink_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
788     const char *n, *s;
789     pa_sink *sink;
790     pa_proplist *p;
791 
792     pa_core_assert_ref(c);
793     pa_assert(t);
794     pa_assert(buf);
795     pa_assert(fail);
796 
797     if (!(n = pa_tokenizer_get(t, 1))) {
798         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
799         return -1;
800     }
801 
802     if (!(s = pa_tokenizer_get(t, 2))) {
803         pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
804         return -1;
805     }
806 
807     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
808         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
809         return -1;
810     }
811 
812     if (!(p = pa_proplist_from_string(s))) {
813         pa_strbuf_puts(buf, "Failed to parse proplist.\n");
814         return -1;
815     }
816 
817     pa_sink_update_proplist(sink, PA_UPDATE_REPLACE, p);
818 
819     pa_proplist_free(p);
820 
821     return 0;
822 }
823 
pa_cli_command_update_source_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)824 static int pa_cli_command_update_source_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
825     const char *n, *s;
826     pa_source *source;
827     pa_proplist *p;
828 
829     pa_core_assert_ref(c);
830     pa_assert(t);
831     pa_assert(buf);
832     pa_assert(fail);
833 
834     if (!(n = pa_tokenizer_get(t, 1))) {
835         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
836         return -1;
837     }
838 
839     if (!(s = pa_tokenizer_get(t, 2))) {
840         pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
841         return -1;
842     }
843 
844     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
845         pa_strbuf_puts(buf, "No source found by this name or index.\n");
846         return -1;
847     }
848 
849     if (!(p = pa_proplist_from_string(s))) {
850         pa_strbuf_puts(buf, "Failed to parse proplist.\n");
851         return -1;
852     }
853 
854     pa_source_update_proplist(source, PA_UPDATE_REPLACE, p);
855 
856     pa_proplist_free(p);
857 
858     return 0;
859 }
860 
pa_cli_command_update_sink_input_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)861 static int pa_cli_command_update_sink_input_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
862     const char *n, *s;
863     pa_sink_input *si;
864     uint32_t idx;
865     pa_proplist *p;
866 
867     pa_core_assert_ref(c);
868     pa_assert(t);
869     pa_assert(buf);
870     pa_assert(fail);
871 
872     if (!(n = pa_tokenizer_get(t, 1))) {
873         pa_strbuf_puts(buf, "You need to specify a sink input either by index.\n");
874         return -1;
875     }
876 
877     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
878         pa_strbuf_puts(buf, "Failed to parse index.\n");
879         return -1;
880     }
881 
882     if (!(s = pa_tokenizer_get(t, 2))) {
883         pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
884         return -1;
885     }
886 
887     if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
888         pa_strbuf_puts(buf, "No sink input found with this index.\n");
889         return -1;
890     }
891 
892     if (!(p = pa_proplist_from_string(s))) {
893         pa_strbuf_puts(buf, "Failed to parse proplist.\n");
894         return -1;
895     }
896 
897     pa_sink_input_update_proplist(si, PA_UPDATE_REPLACE, p);
898 
899     pa_proplist_free(p);
900 
901     return 0;
902 }
903 
pa_cli_command_update_source_output_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)904 static int pa_cli_command_update_source_output_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
905     const char *n, *s;
906     pa_source_output *so;
907     uint32_t idx;
908     pa_proplist *p;
909 
910     pa_core_assert_ref(c);
911     pa_assert(t);
912     pa_assert(buf);
913     pa_assert(fail);
914 
915     if (!(n = pa_tokenizer_get(t, 1))) {
916         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
917         return -1;
918     }
919 
920     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
921         pa_strbuf_puts(buf, "Failed to parse index.\n");
922         return -1;
923     }
924 
925     if (!(s = pa_tokenizer_get(t, 2))) {
926         pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
927         return -1;
928     }
929 
930     if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) {
931         pa_strbuf_puts(buf, "No source output found with this index.\n");
932         return -1;
933     }
934 
935     if (!(p = pa_proplist_from_string(s))) {
936         pa_strbuf_puts(buf, "Failed to parse proplist.\n");
937         return -1;
938     }
939 
940     pa_source_output_update_proplist(so, PA_UPDATE_REPLACE, p);
941 
942     pa_proplist_free(p);
943 
944     return 0;
945 }
946 
pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)947 static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
948     const char *n, *v;
949     pa_sink_input *si;
950     uint32_t idx;
951     int mute;
952 
953     pa_core_assert_ref(c);
954     pa_assert(t);
955     pa_assert(buf);
956     pa_assert(fail);
957 
958     if (!(n = pa_tokenizer_get(t, 1))) {
959         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
960         return -1;
961     }
962 
963     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
964         pa_strbuf_puts(buf, "Failed to parse index.\n");
965         return -1;
966     }
967 
968     if (!(v = pa_tokenizer_get(t, 2))) {
969         pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
970         return -1;
971     }
972 
973     if ((mute = pa_parse_boolean(v)) < 0) {
974         pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
975         return -1;
976     }
977 
978     if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
979         pa_strbuf_puts(buf, "No sink input found with this index.\n");
980         return -1;
981     }
982 
983     pa_sink_input_set_mute(si, mute, true);
984     return 0;
985 }
986 
pa_cli_command_source_output_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)987 static int pa_cli_command_source_output_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
988     const char *n, *v;
989     pa_source_output *so;
990     uint32_t idx;
991     int mute;
992 
993     pa_core_assert_ref(c);
994     pa_assert(t);
995     pa_assert(buf);
996     pa_assert(fail);
997 
998     if (!(n = pa_tokenizer_get(t, 1))) {
999         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
1000         return -1;
1001     }
1002 
1003     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1004         pa_strbuf_puts(buf, "Failed to parse index.\n");
1005         return -1;
1006     }
1007 
1008     if (!(v = pa_tokenizer_get(t, 2))) {
1009         pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
1010         return -1;
1011     }
1012 
1013     if ((mute = pa_parse_boolean(v)) < 0) {
1014         pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
1015         return -1;
1016     }
1017 
1018     if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) {
1019         pa_strbuf_puts(buf, "No source output found with this index.\n");
1020         return -1;
1021     }
1022 
1023     pa_source_output_set_mute(so, mute, true);
1024     return 0;
1025 }
1026 
pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1027 static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1028     const char *n;
1029     pa_sink *s;
1030 
1031     pa_core_assert_ref(c);
1032     pa_assert(t);
1033     pa_assert(buf);
1034     pa_assert(fail);
1035 
1036     if (!(n = pa_tokenizer_get(t, 1))) {
1037         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
1038         return -1;
1039     }
1040 
1041     if ((s = pa_namereg_get(c, n, PA_NAMEREG_SINK)))
1042         pa_core_set_configured_default_sink(c, s->name);
1043     else
1044         pa_strbuf_printf(buf, "Sink %s does not exist.\n", n);
1045 
1046     return 0;
1047 }
1048 
pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1049 static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1050     const char *n;
1051     pa_source *s;
1052 
1053     pa_core_assert_ref(c);
1054     pa_assert(t);
1055     pa_assert(buf);
1056     pa_assert(fail);
1057 
1058     if (!(n = pa_tokenizer_get(t, 1))) {
1059         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
1060         return -1;
1061     }
1062 
1063     if ((s = pa_namereg_get(c, n, PA_NAMEREG_SOURCE)))
1064         pa_core_set_configured_default_source(c, s->name);
1065     else
1066         pa_strbuf_printf(buf, "Source %s does not exist.\n", n);
1067     return 0;
1068 }
1069 
pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1070 static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1071     const char *n;
1072     pa_client *client;
1073     uint32_t idx;
1074 
1075     pa_core_assert_ref(c);
1076     pa_assert(t);
1077     pa_assert(buf);
1078     pa_assert(fail);
1079 
1080     if (!(n = pa_tokenizer_get(t, 1))) {
1081         pa_strbuf_puts(buf, "You need to specify a client by its index.\n");
1082         return -1;
1083     }
1084 
1085     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1086         pa_strbuf_puts(buf, "Failed to parse index.\n");
1087         return -1;
1088     }
1089 
1090     if (!(client = pa_idxset_get_by_index(c->clients, idx))) {
1091         pa_strbuf_puts(buf, "No client found by this index.\n");
1092         return -1;
1093     }
1094 
1095     pa_client_kill(client);
1096     return 0;
1097 }
1098 
pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1099 static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1100     const char *n;
1101     pa_sink_input *sink_input;
1102     uint32_t idx;
1103 
1104     pa_core_assert_ref(c);
1105     pa_assert(t);
1106     pa_assert(buf);
1107     pa_assert(fail);
1108 
1109     if (!(n = pa_tokenizer_get(t, 1))) {
1110         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
1111         return -1;
1112     }
1113 
1114     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1115         pa_strbuf_puts(buf, "Failed to parse index.\n");
1116         return -1;
1117     }
1118 
1119     if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, idx))) {
1120         pa_strbuf_puts(buf, "No sink input found by this index.\n");
1121         return -1;
1122     }
1123 
1124     pa_sink_input_kill(sink_input);
1125     return 0;
1126 }
1127 
pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1128 static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1129     const char *n;
1130     pa_source_output *source_output;
1131     uint32_t idx;
1132 
1133     pa_core_assert_ref(c);
1134     pa_assert(t);
1135     pa_assert(buf);
1136     pa_assert(fail);
1137 
1138     if (!(n = pa_tokenizer_get(t, 1))) {
1139         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
1140         return -1;
1141     }
1142 
1143     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1144         pa_strbuf_puts(buf, "Failed to parse index.\n");
1145         return -1;
1146     }
1147 
1148     if (!(source_output = pa_idxset_get_by_index(c->source_outputs, idx))) {
1149         pa_strbuf_puts(buf, "No source output found by this index.\n");
1150         return -1;
1151     }
1152 
1153     pa_source_output_kill(source_output);
1154     return 0;
1155 }
1156 
pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1157 static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1158     char *s;
1159 
1160     pa_core_assert_ref(c);
1161     pa_assert(t);
1162     pa_assert(buf);
1163     pa_assert(fail);
1164 
1165     pa_assert_se(s = pa_scache_list_to_string(c));
1166     pa_strbuf_puts(buf, s);
1167     pa_xfree(s);
1168 
1169     return 0;
1170 }
1171 
pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1172 static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1173     const char *n, *sink_name;
1174     pa_sink *sink;
1175     uint32_t idx;
1176 
1177     pa_core_assert_ref(c);
1178     pa_assert(t);
1179     pa_assert(buf);
1180     pa_assert(fail);
1181 
1182     if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
1183         pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n");
1184         return -1;
1185     }
1186 
1187     if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) {
1188         pa_strbuf_puts(buf, "No sink by that name.\n");
1189         return -1;
1190     }
1191 
1192     if (pa_scache_play_item(c, n, sink, PA_VOLUME_NORM, NULL, &idx) < 0) {
1193         pa_strbuf_puts(buf, "Failed to play sample.\n");
1194         return -1;
1195     }
1196 
1197     pa_strbuf_printf(buf, "Playing on sink input #%i\n", idx);
1198 
1199     return 0;
1200 }
1201 
pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1202 static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1203     const char *n;
1204 
1205     pa_core_assert_ref(c);
1206     pa_assert(t);
1207     pa_assert(buf);
1208     pa_assert(fail);
1209 
1210     if (!(n = pa_tokenizer_get(t, 1))) {
1211         pa_strbuf_puts(buf, "You need to specify a sample name.\n");
1212         return -1;
1213     }
1214 
1215     if (pa_scache_remove_item(c, n) < 0) {
1216         pa_strbuf_puts(buf, "Failed to remove sample.\n");
1217         return -1;
1218     }
1219 
1220     return 0;
1221 }
1222 
pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1223 static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1224     const char *fname, *n;
1225     int r;
1226 
1227     pa_core_assert_ref(c);
1228     pa_assert(t);
1229     pa_assert(buf);
1230     pa_assert(fail);
1231 
1232     if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) {
1233         pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n");
1234         return -1;
1235     }
1236 
1237     if (strstr(pa_tokenizer_get(t, 0), "lazy"))
1238         r = pa_scache_add_file_lazy(c, n, fname, NULL);
1239     else
1240         r = pa_scache_add_file(c, n, fname, NULL);
1241 
1242     if (r < 0)
1243         pa_strbuf_puts(buf, "Failed to load sound file.\n");
1244 
1245     return 0;
1246 }
1247 
pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1248 static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1249     const char *pname;
1250 
1251     pa_core_assert_ref(c);
1252     pa_assert(t);
1253     pa_assert(buf);
1254     pa_assert(fail);
1255 
1256     if (!(pname = pa_tokenizer_get(t, 1))) {
1257         pa_strbuf_puts(buf, "You need to specify a path name.\n");
1258         return -1;
1259     }
1260 
1261     if (pa_scache_add_directory_lazy(c, pname) < 0) {
1262         pa_strbuf_puts(buf, "Failed to load directory.\n");
1263         return -1;
1264     }
1265 
1266     return 0;
1267 }
1268 
pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1269 static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1270     const char *fname, *sink_name;
1271     pa_sink *sink;
1272 
1273     pa_core_assert_ref(c);
1274     pa_assert(t);
1275     pa_assert(buf);
1276     pa_assert(fail);
1277 
1278     if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
1279         pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n");
1280         return -1;
1281     }
1282 
1283     if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) {
1284         pa_strbuf_puts(buf, "No sink by that name.\n");
1285         return -1;
1286     }
1287 #ifdef SNDFILE_ENABLE
1288     if (pa_play_file(sink, fname, NULL) < 0) {
1289         pa_strbuf_puts(buf, "Failed to play sound file.\n");
1290         return -1;
1291     }
1292 #else
1293     return -1;
1294 #endif
1295     return 0;
1296 }
1297 
pa_cli_command_list_shared_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1298 static int pa_cli_command_list_shared_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1299     pa_core_assert_ref(c);
1300     pa_assert(t);
1301     pa_assert(buf);
1302     pa_assert(fail);
1303 
1304     pa_shared_dump(c, buf);
1305     return 0;
1306 }
1307 
pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1308 static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1309     pa_core_assert_ref(c);
1310     pa_assert(t);
1311     pa_assert(buf);
1312     pa_assert(fail);
1313 
1314     pa_mempool_vacuum(c->mempool);
1315 
1316     return 0;
1317 }
1318 
pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1319 static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1320     const char *n, *k;
1321     pa_sink_input *si;
1322     pa_sink *sink;
1323     uint32_t idx;
1324 
1325     pa_core_assert_ref(c);
1326     pa_assert(t);
1327     pa_assert(buf);
1328     pa_assert(fail);
1329 
1330     if (!(n = pa_tokenizer_get(t, 1))) {
1331         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
1332         return -1;
1333     }
1334 
1335     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1336         pa_strbuf_puts(buf, "Failed to parse index.\n");
1337         return -1;
1338     }
1339 
1340     if (!(k = pa_tokenizer_get(t, 2))) {
1341         pa_strbuf_puts(buf, "You need to specify a sink.\n");
1342         return -1;
1343     }
1344 
1345     if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
1346         pa_strbuf_puts(buf, "No sink input found with this index.\n");
1347         return -1;
1348     }
1349 
1350     if (!(sink = pa_namereg_get(c, k, PA_NAMEREG_SINK))) {
1351         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
1352         return -1;
1353     }
1354 
1355     if (pa_sink_input_move_to(si, sink, true) < 0) {
1356         pa_strbuf_puts(buf, "Moved failed.\n");
1357         return -1;
1358     }
1359     return 0;
1360 }
1361 
pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1362 static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1363     const char *n, *k;
1364     pa_source_output *so;
1365     pa_source *source;
1366     uint32_t idx;
1367 
1368     pa_core_assert_ref(c);
1369     pa_assert(t);
1370     pa_assert(buf);
1371     pa_assert(fail);
1372 
1373     if (!(n = pa_tokenizer_get(t, 1))) {
1374         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
1375         return -1;
1376     }
1377 
1378     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1379         pa_strbuf_puts(buf, "Failed to parse index.\n");
1380         return -1;
1381     }
1382 
1383     if (!(k = pa_tokenizer_get(t, 2))) {
1384         pa_strbuf_puts(buf, "You need to specify a source.\n");
1385         return -1;
1386     }
1387 
1388     if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) {
1389         pa_strbuf_puts(buf, "No source output found with this index.\n");
1390         return -1;
1391     }
1392 
1393     if (!(source = pa_namereg_get(c, k, PA_NAMEREG_SOURCE))) {
1394         pa_strbuf_puts(buf, "No source found by this name or index.\n");
1395         return -1;
1396     }
1397 
1398     if (pa_source_output_move_to(so, source, true) < 0) {
1399         pa_strbuf_puts(buf, "Moved failed.\n");
1400         return -1;
1401     }
1402     return 0;
1403 }
1404 
pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1405 static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1406     const char *n, *m;
1407     pa_sink *sink;
1408     int suspend, r;
1409 
1410     pa_core_assert_ref(c);
1411     pa_assert(t);
1412     pa_assert(buf);
1413     pa_assert(fail);
1414 
1415     if (!(n = pa_tokenizer_get(t, 1))) {
1416         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
1417         return -1;
1418     }
1419 
1420     if (!(m = pa_tokenizer_get(t, 2))) {
1421         pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
1422         return -1;
1423     }
1424 
1425     if ((suspend = pa_parse_boolean(m)) < 0) {
1426         pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
1427         return -1;
1428     }
1429 
1430     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
1431         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
1432         return -1;
1433     }
1434 
1435     pa_log_debug("%s of sink %s requested via CLI.", suspend ? "Suspending" : "Resuming", sink->name);
1436 
1437     if ((r = pa_sink_suspend(sink, suspend, PA_SUSPEND_USER)) < 0)
1438         pa_strbuf_printf(buf, "Failed to resume/suspend sink: %s\n", pa_strerror(r));
1439 
1440     return 0;
1441 }
1442 
pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1443 static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1444     const char *n, *m;
1445     pa_source *source;
1446     int suspend, r;
1447 
1448     pa_core_assert_ref(c);
1449     pa_assert(t);
1450     pa_assert(buf);
1451     pa_assert(fail);
1452 
1453     if (!(n = pa_tokenizer_get(t, 1))) {
1454         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
1455         return -1;
1456     }
1457 
1458     if (!(m = pa_tokenizer_get(t, 2))) {
1459         pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
1460         return -1;
1461     }
1462 
1463     if ((suspend = pa_parse_boolean(m)) < 0) {
1464         pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
1465         return -1;
1466     }
1467 
1468     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
1469         pa_strbuf_puts(buf, "No source found by this name or index.\n");
1470         return -1;
1471     }
1472 
1473     pa_log_debug("%s of source %s requested via CLI.", suspend ? "Suspending" : "Resuming", source->name);
1474 
1475     if ((r = pa_source_suspend(source, suspend, PA_SUSPEND_USER)) < 0)
1476         pa_strbuf_printf(buf, "Failed to resume/suspend source: %s\n", pa_strerror(r));
1477 
1478     return 0;
1479 }
1480 
pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1481 static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1482     const char *m;
1483     int suspend, r;
1484 
1485     pa_core_assert_ref(c);
1486     pa_assert(t);
1487     pa_assert(buf);
1488     pa_assert(fail);
1489 
1490     if (!(m = pa_tokenizer_get(t, 1))) {
1491         pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
1492         return -1;
1493     }
1494 
1495     if ((suspend = pa_parse_boolean(m)) < 0) {
1496         pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
1497         return -1;
1498     }
1499 
1500     pa_log_debug("%s of all sinks and sources requested via CLI.", suspend ? "Suspending" : "Resuming");
1501 
1502     if ((r = pa_sink_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0)
1503         pa_strbuf_printf(buf, "Failed to resume/suspend all sinks: %s\n", pa_strerror(r));
1504 
1505     if ((r = pa_source_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0)
1506         pa_strbuf_printf(buf, "Failed to resume/suspend all sources: %s\n", pa_strerror(r));
1507 
1508     return 0;
1509 }
1510 
pa_cli_command_log_target(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1511 static int pa_cli_command_log_target(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1512     const char *m;
1513     pa_log_target *log_target = NULL;
1514 
1515     pa_core_assert_ref(c);
1516     pa_assert(t);
1517     pa_assert(buf);
1518     pa_assert(fail);
1519 
1520     if (!(m = pa_tokenizer_get(t, 1))) {
1521         pa_strbuf_puts(buf, "You need to specify a log target (null|auto|syslog|stderr|file:PATH|newfile:PATH).\n");
1522         return -1;
1523     }
1524 
1525     /* 'auto' is actually the effect with 'stderr' */
1526     if (pa_streq(m, "auto"))
1527         log_target = pa_log_target_new(PA_LOG_STDERR, NULL);
1528     else {
1529         log_target = pa_log_parse_target(m);
1530 
1531         if (!log_target) {
1532             pa_strbuf_puts(buf, "Invalid log target.\n");
1533             return -1;
1534         }
1535     }
1536 
1537     if (pa_log_set_target(log_target) < 0) {
1538         pa_strbuf_puts(buf, "Failed to set log target.\n");
1539         pa_log_target_free(log_target);
1540         return -1;
1541     }
1542 
1543     pa_log_target_free(log_target);
1544 
1545     return 0;
1546 }
1547 
pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1548 static int pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1549     const char *m;
1550     uint32_t level;
1551 
1552     pa_core_assert_ref(c);
1553     pa_assert(t);
1554     pa_assert(buf);
1555     pa_assert(fail);
1556 
1557     if (!(m = pa_tokenizer_get(t, 1))) {
1558         pa_strbuf_puts(buf, "You need to specify a log level (0..4).\n");
1559         return -1;
1560     }
1561 
1562     if (pa_atou(m, &level) < 0 || level >= PA_LOG_LEVEL_MAX) {
1563         pa_strbuf_puts(buf, "Failed to parse log level.\n");
1564         return -1;
1565     }
1566 
1567     pa_log_set_level(level);
1568 
1569     return 0;
1570 }
1571 
pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1572 static int pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1573     const char *m;
1574     int b;
1575 
1576     pa_core_assert_ref(c);
1577     pa_assert(t);
1578     pa_assert(buf);
1579     pa_assert(fail);
1580 
1581     if (!(m = pa_tokenizer_get(t, 1))) {
1582         pa_strbuf_puts(buf, "You need to specify a boolean.\n");
1583         return -1;
1584     }
1585 
1586     if ((b = pa_parse_boolean(m)) < 0) {
1587         pa_strbuf_puts(buf, "Failed to parse log meta switch.\n");
1588         return -1;
1589     }
1590 
1591     pa_log_set_flags(PA_LOG_PRINT_META, b ? PA_LOG_SET : PA_LOG_UNSET);
1592 
1593     return 0;
1594 }
1595 
pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1596 static int pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1597     const char *m;
1598     int b;
1599 
1600     pa_core_assert_ref(c);
1601     pa_assert(t);
1602     pa_assert(buf);
1603     pa_assert(fail);
1604 
1605     if (!(m = pa_tokenizer_get(t, 1))) {
1606         pa_strbuf_puts(buf, "You need to specify a boolean.\n");
1607         return -1;
1608     }
1609 
1610     if ((b = pa_parse_boolean(m)) < 0) {
1611         pa_strbuf_puts(buf, "Failed to parse log meta switch.\n");
1612         return -1;
1613     }
1614 
1615     pa_log_set_flags(PA_LOG_PRINT_TIME, b ? PA_LOG_SET : PA_LOG_UNSET);
1616 
1617     return 0;
1618 }
1619 
pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1620 static int pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1621     const char *m;
1622     uint32_t nframes;
1623 
1624     pa_core_assert_ref(c);
1625     pa_assert(t);
1626     pa_assert(buf);
1627     pa_assert(fail);
1628 
1629     if (!(m = pa_tokenizer_get(t, 1))) {
1630         pa_strbuf_puts(buf, "You need to specify a backtrace level.\n");
1631         return -1;
1632     }
1633 
1634     if (pa_atou(m, &nframes) < 0 || nframes >= 1000) {
1635         pa_strbuf_puts(buf, "Failed to parse backtrace level.\n");
1636         return -1;
1637     }
1638 
1639     pa_log_set_show_backtrace(nframes);
1640 
1641     return 0;
1642 }
1643 
pa_cli_command_card_profile(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1644 static int pa_cli_command_card_profile(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1645     const char *n, *p;
1646     pa_card *card;
1647     pa_card_profile *profile;
1648 
1649     pa_core_assert_ref(c);
1650     pa_assert(t);
1651     pa_assert(buf);
1652     pa_assert(fail);
1653 
1654     if (!(n = pa_tokenizer_get(t, 1))) {
1655         pa_strbuf_puts(buf, "You need to specify a card either by its name or its index.\n");
1656         return -1;
1657     }
1658 
1659     if (!(p = pa_tokenizer_get(t, 2))) {
1660         pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
1661         return -1;
1662     }
1663 
1664     if (!(card = pa_namereg_get(c, n, PA_NAMEREG_CARD))) {
1665         pa_strbuf_puts(buf, "No card found by this name or index.\n");
1666         return -1;
1667     }
1668 
1669     if (!(profile = pa_hashmap_get(card->profiles, p))) {
1670         pa_strbuf_printf(buf, "No such profile: %s\n", p);
1671         return -1;
1672     }
1673 
1674     if (pa_card_set_profile(card, profile, true) < 0) {
1675         pa_strbuf_printf(buf, "Failed to set card profile to '%s'.\n", p);
1676         return -1;
1677     }
1678 
1679     return 0;
1680 }
1681 
pa_cli_command_sink_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1682 static int pa_cli_command_sink_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1683     const char *n, *p;
1684     pa_sink *sink;
1685 
1686     pa_core_assert_ref(c);
1687     pa_assert(t);
1688     pa_assert(buf);
1689     pa_assert(fail);
1690 
1691     if (!(n = pa_tokenizer_get(t, 1))) {
1692         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
1693         return -1;
1694     }
1695 
1696     if (!(p = pa_tokenizer_get(t, 2))) {
1697         pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
1698         return -1;
1699     }
1700 
1701     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
1702         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
1703         return -1;
1704     }
1705 
1706     if (pa_sink_set_port(sink, p, true) < 0) {
1707         pa_strbuf_printf(buf, "Failed to set sink port to '%s'.\n", p);
1708         return -1;
1709     }
1710 
1711     return 0;
1712 }
1713 
pa_cli_command_source_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1714 static int pa_cli_command_source_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1715     const char *n, *p;
1716     pa_source *source;
1717 
1718     pa_core_assert_ref(c);
1719     pa_assert(t);
1720     pa_assert(buf);
1721     pa_assert(fail);
1722 
1723     if (!(n = pa_tokenizer_get(t, 1))) {
1724         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
1725         return -1;
1726     }
1727 
1728     if (!(p = pa_tokenizer_get(t, 2))) {
1729         pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
1730         return -1;
1731     }
1732 
1733     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
1734         pa_strbuf_puts(buf, "No source found by this name or index.\n");
1735         return -1;
1736     }
1737 
1738     if (pa_source_set_port(source, p, true) < 0) {
1739         pa_strbuf_printf(buf, "Failed to set source port to '%s'.\n", p);
1740         return -1;
1741     }
1742 
1743     return 0;
1744 }
1745 
pa_cli_command_port_offset(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1746 static int pa_cli_command_port_offset(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1747     const char *n, *p, *l;
1748     pa_device_port *port;
1749     pa_card *card;
1750     int32_t offset;
1751 
1752     pa_core_assert_ref(c);
1753     pa_assert(t);
1754     pa_assert(buf);
1755     pa_assert(fail);
1756 
1757     if (!(n = pa_tokenizer_get(t, 1))) {
1758         pa_strbuf_puts(buf, "You need to specify a card either by its name or its index.\n");
1759         return -1;
1760     }
1761 
1762     if (!(p = pa_tokenizer_get(t, 2))) {
1763         pa_strbuf_puts(buf, "You need to specify a port by its name.\n");
1764         return -1;
1765     }
1766 
1767     if (!(l = pa_tokenizer_get(t, 3))) {
1768         pa_strbuf_puts(buf, "You need to specify a latency offset.\n");
1769         return -1;
1770     }
1771 
1772     if (pa_atoi(l, &offset) < 0) {
1773         pa_strbuf_puts(buf, "Failed to parse the latency offset.\n");
1774         return -1;
1775     }
1776 
1777     if (!(card = pa_namereg_get(c, n, PA_NAMEREG_CARD))) {
1778         pa_strbuf_puts(buf, "No card found by this name or index.\n");
1779         return -1;
1780     }
1781 
1782     if (!(port = pa_hashmap_get(card->ports, p))) {
1783         pa_strbuf_puts(buf, "No port found by this name.\n");
1784         return -1;
1785     }
1786 
1787     pa_device_port_set_latency_offset(port, offset);
1788 
1789     return 0;
1790 }
1791 
pa_cli_command_send_message_to_object(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1792 static int pa_cli_command_send_message_to_object(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1793     const char *object_path, *message, *message_parameters;
1794     char *response = NULL;
1795     int ret;
1796 
1797     pa_core_assert_ref(c);
1798     pa_assert(t);
1799     pa_assert(buf);
1800     pa_assert(fail);
1801 
1802 
1803     if (!(object_path = pa_tokenizer_get(t, 1))) {
1804         pa_strbuf_puts(buf, "You need to specify an object path as recipient for the message.\n");
1805            return -1;
1806     }
1807 
1808     if (!(message = pa_tokenizer_get(t, 2))) {
1809         pa_strbuf_puts(buf, "You need to specify a message name.\n");
1810         return -1;
1811     }
1812 
1813     /* parameters may be NULL */
1814     message_parameters = pa_tokenizer_get(t, 3);
1815 
1816     ret = pa_message_handler_send_message(c, object_path, message, message_parameters, &response);
1817 
1818     if (ret < 0) {
1819         pa_strbuf_printf(buf, "Send message failed: %s\n", pa_strerror(ret));
1820         ret = -1;
1821 
1822     } else {
1823         if (response)
1824             pa_strbuf_puts(buf, response);
1825         pa_strbuf_puts(buf, "\n");
1826         ret = 0;
1827     }
1828 
1829     pa_xfree(response);
1830     return ret;
1831 }
1832 
pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1833 static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1834     pa_module *m;
1835     pa_sink *sink;
1836     pa_source *source;
1837     pa_card *card;
1838     bool nl;
1839     uint32_t idx;
1840     time_t now;
1841 #ifdef HAVE_CTIME_R
1842     char txt[256];
1843 #endif
1844 
1845     pa_core_assert_ref(c);
1846     pa_assert(t);
1847     pa_assert(buf);
1848     pa_assert(fail);
1849 
1850     time(&now);
1851 
1852 #ifdef HAVE_CTIME_R
1853     pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt));
1854 #else
1855     pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now));
1856 #endif
1857 
1858     PA_IDXSET_FOREACH(m, c->modules, idx) {
1859 
1860         pa_strbuf_printf(buf, "load-module %s", m->name);
1861 
1862         if (m->argument)
1863             pa_strbuf_printf(buf, " %s", m->argument);
1864 
1865         pa_strbuf_puts(buf, "\n");
1866     }
1867 
1868     nl = false;
1869     PA_IDXSET_FOREACH(sink, c->sinks, idx) {
1870 
1871         if (!nl) {
1872             pa_strbuf_puts(buf, "\n");
1873             nl = true;
1874         }
1875 
1876         pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_max(pa_sink_get_volume(sink, false)));
1877         pa_strbuf_printf(buf, "set-sink-mute %s %s\n", sink->name, pa_yes_no(pa_sink_get_mute(sink, false)));
1878         pa_strbuf_printf(buf, "suspend-sink %s %s\n", sink->name, pa_yes_no(sink->state == PA_SINK_SUSPENDED));
1879     }
1880 
1881     nl = false;
1882     PA_IDXSET_FOREACH(source, c->sources, idx) {
1883 
1884         if (!nl) {
1885             pa_strbuf_puts(buf, "\n");
1886             nl = true;
1887         }
1888 
1889         pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_max(pa_source_get_volume(source, false)));
1890         pa_strbuf_printf(buf, "set-source-mute %s %s\n", source->name, pa_yes_no(pa_source_get_mute(source, false)));
1891         pa_strbuf_printf(buf, "suspend-source %s %s\n", source->name, pa_yes_no(source->state == PA_SOURCE_SUSPENDED));
1892     }
1893 
1894     nl = false;
1895     PA_IDXSET_FOREACH(card, c->cards, idx) {
1896 
1897         if (!nl) {
1898             pa_strbuf_puts(buf, "\n");
1899             nl = true;
1900         }
1901 
1902         pa_strbuf_printf(buf, "set-card-profile %s %s\n", card->name, card->active_profile->name);
1903     }
1904 
1905     nl = false;
1906     if (c->default_sink) {
1907         if (!nl) {
1908             pa_strbuf_puts(buf, "\n");
1909             nl = true;
1910         }
1911 
1912         pa_strbuf_printf(buf, "set-default-sink %s\n", c->default_sink->name);
1913     }
1914 
1915     if (c->default_source) {
1916         if (!nl)
1917             pa_strbuf_puts(buf, "\n");
1918 
1919         pa_strbuf_printf(buf, "set-default-source %s\n", c->default_source->name);
1920     }
1921 
1922     pa_strbuf_puts(buf, "\n### EOF\n");
1923 
1924     return 0;
1925 }
1926 
pa_cli_command_dump_volumes(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail)1927 static int pa_cli_command_dump_volumes(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1928     pa_sink *s;
1929     pa_source *so;
1930     pa_sink_input *i;
1931     pa_source_output *o;
1932     uint32_t s_idx, i_idx;
1933     char v_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
1934     pa_channel_map *map;
1935 
1936     pa_core_assert_ref(c);
1937     pa_assert(t);
1938     pa_assert(buf);
1939     pa_assert(fail);
1940 
1941     PA_IDXSET_FOREACH(s, c->sinks, s_idx) {
1942         map = &s->channel_map;
1943         pa_strbuf_printf(buf, "Sink %d: ", s_idx);
1944         pa_strbuf_printf(buf,
1945                          "reference = %s, ",
1946                          pa_cvolume_snprint_verbose(v_str,
1947                                                     sizeof(v_str),
1948                                                     &s->reference_volume,
1949                                                     map,
1950                                                     s->flags & PA_SINK_DECIBEL_VOLUME));
1951         pa_strbuf_printf(buf,
1952                          "real = %s, ",
1953                          pa_cvolume_snprint_verbose(v_str,
1954                                                     sizeof(v_str),
1955                                                     &s->real_volume,
1956                                                     &s->channel_map,
1957                                                     s->flags & PA_SINK_DECIBEL_VOLUME));
1958         pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &s->soft_volume, map, true));
1959         pa_strbuf_printf(buf,
1960                          "current_hw = %s, ",
1961                          pa_cvolume_snprint_verbose(v_str,
1962                                                     sizeof(v_str),
1963                                                     &s->thread_info.current_hw_volume,
1964                                                     map,
1965                                                     s->flags & PA_SINK_DECIBEL_VOLUME));
1966         pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(s->save_volume));
1967 
1968         PA_IDXSET_FOREACH(i, s->inputs, i_idx) {
1969             map = &i->channel_map;
1970             pa_strbuf_printf(buf, "\tInput %d: ", i_idx);
1971             pa_strbuf_printf(buf, "volume = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->volume, map, true));
1972             pa_strbuf_printf(buf,
1973                              "reference_ratio = %s, ",
1974                              pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->reference_ratio, map, true));
1975             pa_strbuf_printf(buf,
1976                              "real_ratio = %s, ",
1977                              pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->real_ratio, map, true));
1978             pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->soft_volume, map, true));
1979             pa_strbuf_printf(buf,
1980                              "volume_factor = %s, ",
1981                              pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->volume_factor, map, true));
1982             pa_strbuf_printf(buf,
1983                              "volume_factor_sink = %s, ",
1984                              pa_cvolume_snprint_verbose(v_str,
1985                                                         sizeof(v_str),
1986                                                         &i->volume_factor_sink,
1987                                                         &i->sink->channel_map,
1988                                                         true));
1989             pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(i->save_volume));
1990         }
1991     }
1992 
1993     PA_IDXSET_FOREACH(so, c->sources, s_idx) {
1994         map = &so->channel_map;
1995         pa_strbuf_printf(buf, "Source %d: ", s_idx);
1996         pa_strbuf_printf(buf,
1997                          "reference = %s, ",
1998                          pa_cvolume_snprint_verbose(v_str,
1999                                                     sizeof(v_str),
2000                                                     &so->reference_volume,
2001                                                     map,
2002                                                     so->flags & PA_SOURCE_DECIBEL_VOLUME));
2003         pa_strbuf_printf(buf,
2004                          "real = %s, ",
2005                          pa_cvolume_snprint_verbose(v_str,
2006                                                     sizeof(v_str),
2007                                                     &so->real_volume,
2008                                                     map,
2009                                                     so->flags & PA_SOURCE_DECIBEL_VOLUME));
2010         pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &so->soft_volume, map, true));
2011         pa_strbuf_printf(buf,
2012                          "current_hw = %s, ",
2013                          pa_cvolume_snprint_verbose(v_str,
2014                                                     sizeof(v_str),
2015                                                     &so->thread_info.current_hw_volume,
2016                                                     map,
2017                                                     so->flags & PA_SOURCE_DECIBEL_VOLUME));
2018         pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(so->save_volume));
2019 
2020         PA_IDXSET_FOREACH(o, so->outputs, i_idx) {
2021             map = &o->channel_map;
2022             pa_strbuf_printf(buf, "\tOutput %d: ", i_idx);
2023             pa_strbuf_printf(buf, "volume = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->volume, map, true));
2024             pa_strbuf_printf(buf,
2025                              "reference_ratio = %s, ",
2026                              pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->reference_ratio, map, true));
2027             pa_strbuf_printf(buf,
2028                              "real_ratio = %s, ",
2029                              pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->real_ratio, map, true));
2030             pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->soft_volume, map, true));
2031             pa_strbuf_printf(buf,
2032                              "volume_factor = %s, ",
2033                              pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->volume_factor, map, true));
2034             pa_strbuf_printf(buf,
2035                              "volume_factor_source = %s, ",
2036                              pa_cvolume_snprint_verbose(v_str,
2037                                                         sizeof(v_str),
2038                                                         &o->volume_factor_source,
2039                                                         &o->source->channel_map,
2040                                                         true));
2041             pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(o->save_volume));
2042         }
2043     }
2044 
2045     return 0;
2046 }
2047 
pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, bool *fail, int *ifstate)2048 int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, bool *fail, int *ifstate) {
2049     const char *cs;
2050 
2051     pa_assert(c);
2052     pa_assert(s);
2053     pa_assert(buf);
2054 
2055     cs = s+strspn(s, whitespace);
2056 
2057     if (*cs == '#' || !*cs)
2058         return 0;
2059     else if (*cs == '.') {
2060         if (!strcmp(cs, META_ELSE)) {
2061             if (!ifstate || *ifstate == IFSTATE_NONE) {
2062                 pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
2063                 return -1;
2064             } else if (*ifstate == IFSTATE_TRUE)
2065                 *ifstate = IFSTATE_FALSE;
2066             else
2067                 *ifstate = IFSTATE_TRUE;
2068             return 0;
2069         } else if (!strcmp(cs, META_ENDIF)) {
2070             if (!ifstate || *ifstate == IFSTATE_NONE) {
2071                 pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
2072                 return -1;
2073             } else
2074                 *ifstate = IFSTATE_NONE;
2075             return 0;
2076         }
2077         if (ifstate && *ifstate == IFSTATE_FALSE)
2078             return 0;
2079         if (!strcmp(cs, META_FAIL))
2080             *fail = true;
2081         else if (!strcmp(cs, META_NOFAIL))
2082             *fail = false;
2083         else {
2084             size_t l;
2085             l = strcspn(cs, whitespace);
2086 
2087             if (l == sizeof(META_INCLUDE)-1 && !strncmp(cs, META_INCLUDE, l)) {
2088                 struct stat st;
2089                 const char *fn = cs+l+strspn(cs+l, whitespace);
2090 
2091                 char *filename;
2092 #ifdef OS_IS_WIN32
2093                 if (strncmp(fn, PA_DEFAULT_CONFIG_DIR, strlen(PA_DEFAULT_CONFIG_DIR)) == 0)
2094                     filename = pa_sprintf_malloc("%s" PA_PATH_SEP "etc" PA_PATH_SEP "pulse" PA_PATH_SEP "%s",
2095                                             pa_win32_get_toplevel(NULL),
2096                                             fn + strlen(PA_DEFAULT_CONFIG_DIR));
2097                 else
2098 #endif
2099                 filename = pa_xstrdup(fn);
2100 
2101                 if (stat(filename, &st) < 0) {
2102                     pa_log_warn("stat('%s'): %s", filename, pa_cstrerror(errno));
2103                     if (*fail) {
2104                         pa_xfree(filename);
2105                         return -1;
2106                     }
2107                 } else {
2108                     if (S_ISDIR(st.st_mode)) {
2109                         DIR *d;
2110 
2111                         if (!(d = opendir(filename))) {
2112                             pa_log_warn("Failed to read '%s': %s", filename, pa_cstrerror(errno));
2113                             if (*fail) {
2114                                 pa_xfree(filename);
2115                                 return -1;
2116                             }
2117                         } else {
2118                             unsigned i, count;
2119                             char **sorted_files;
2120                             struct dirent *de;
2121                             bool failed = false;
2122                             pa_dynarray *files = pa_dynarray_new(NULL);
2123 
2124                             while ((de = readdir(d))) {
2125                                 char *extn;
2126                                 size_t flen = strlen(de->d_name);
2127 
2128                                 if (flen < 4)
2129                                     continue;
2130 
2131                                 extn = &de->d_name[flen-3];
2132                                 if (strncmp(extn, ".pa", 3) == 0)
2133                                     pa_dynarray_append(files, pa_sprintf_malloc("%s" PA_PATH_SEP "%s", filename, de->d_name));
2134                             }
2135 
2136                             closedir(d);
2137                             if ((count = pa_dynarray_size(files))) {
2138                                 sorted_files = pa_xnew(char*, count);
2139                                 for (i = 0; i < count; ++i)
2140                                     sorted_files[i] = pa_dynarray_get(files, i);
2141                                 pa_dynarray_free(files);
2142 
2143                                 for (i = 0; i < count; ++i) {
2144                                     for (unsigned j = 0; j < count; ++j) {
2145                                         if (strcmp(sorted_files[i], sorted_files[j]) < 0) {
2146                                             char *tmp = sorted_files[i];
2147                                             sorted_files[i] = sorted_files[j];
2148                                             sorted_files[j] = tmp;
2149                                         }
2150                                     }
2151                                 }
2152 
2153                                 for (i = 0; i < count; ++i) {
2154                                     if (!failed) {
2155                                         if (pa_cli_command_execute_file(c, sorted_files[i], buf, fail) < 0 && *fail)
2156                                             failed = true;
2157                                     }
2158 
2159                                     pa_xfree(sorted_files[i]);
2160                                 }
2161                                 pa_xfree(sorted_files);
2162                                 if (failed) {
2163                                     pa_xfree(filename);
2164                                     return -1;
2165                                 }
2166                             }
2167                         }
2168                     } else if (pa_cli_command_execute_file(c, filename, buf, fail) < 0 && *fail) {
2169                         pa_xfree(filename);
2170                         return -1;
2171                     }
2172                 }
2173                 pa_xfree(filename);
2174             } else if (l == sizeof(META_IFEXISTS)-1 && !strncmp(cs, META_IFEXISTS, l)) {
2175                 if (!ifstate) {
2176                     pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
2177                     return -1;
2178                 } else if (*ifstate != IFSTATE_NONE) {
2179                     pa_strbuf_printf(buf, "Nested %s commands not supported\n", cs);
2180                     return -1;
2181                 } else {
2182                     const char *filename = cs+l+strspn(cs+l, whitespace);
2183                     *ifstate = pa_module_exists(filename) ? IFSTATE_TRUE : IFSTATE_FALSE;
2184                 }
2185             } else {
2186                 pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs);
2187                 if (*fail) return -1;
2188             }
2189         }
2190     } else {
2191         const struct command*command;
2192         int unknown = 1;
2193         size_t l;
2194 
2195         if (ifstate && *ifstate == IFSTATE_FALSE)
2196             return 0;
2197 
2198         l = strcspn(cs, whitespace);
2199 
2200         for (command = commands; command->name; command++)
2201             if (strlen(command->name) == l && !strncmp(cs, command->name, l)) {
2202                 int ret;
2203                 pa_tokenizer *t = pa_tokenizer_new(cs, command->args);
2204                 pa_assert(t);
2205                 ret = command->proc(c, t, buf, fail);
2206                 pa_tokenizer_free(t);
2207                 unknown = 0;
2208 
2209                 if (ret < 0 && *fail)
2210                     return -1;
2211 
2212                 break;
2213             }
2214 
2215         if (unknown) {
2216             pa_strbuf_printf(buf, "Unknown command: %s\n", cs);
2217             if (*fail)
2218                 return -1;
2219         }
2220     }
2221 
2222     return 0;
2223 }
2224 
pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, bool *fail)2225 int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, bool *fail) {
2226     return pa_cli_command_execute_line_stateful(c, s, buf, fail, NULL);
2227 }
2228 
pa_cli_command_execute_file_stream(pa_core *c, FILE *f, pa_strbuf *buf, bool *fail)2229 int pa_cli_command_execute_file_stream(pa_core *c, FILE *f, pa_strbuf *buf, bool *fail) {
2230     char line[2048];
2231     int ifstate = IFSTATE_NONE;
2232     int ret = -1;
2233     bool _fail = true;
2234 
2235     pa_assert(c);
2236     pa_assert(f);
2237     pa_assert(buf);
2238 
2239     if (!fail)
2240         fail = &_fail;
2241 
2242     while (fgets(line, sizeof(line), f)) {
2243         pa_strip_nl(line);
2244 
2245         if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail)
2246             goto fail;
2247     }
2248 
2249     ret = 0;
2250 
2251 fail:
2252 
2253     return ret;
2254 }
2255 
pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, bool *fail)2256 int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, bool *fail) {
2257     FILE *f = NULL;
2258     int ret = -1;
2259     bool _fail = true;
2260 
2261     pa_assert(c);
2262     pa_assert(fn);
2263     pa_assert(buf);
2264 
2265     if (!fail)
2266         fail = &_fail;
2267 
2268     if (!(f = pa_fopen_cloexec(fn, "r"))) {
2269         pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, pa_cstrerror(errno));
2270         if (!*fail)
2271             ret = 0;
2272         goto fail;
2273     }
2274 
2275     pa_log_debug("Parsing script '%s'", fn);
2276     ret = pa_cli_command_execute_file_stream(c, f, buf, fail);
2277 
2278 fail:
2279     if (f)
2280         fclose(f);
2281 
2282     return ret;
2283 }
2284 
pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, bool *fail)2285 int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, bool *fail) {
2286     const char *p;
2287     int ifstate = IFSTATE_NONE;
2288     bool _fail = true;
2289 
2290     pa_assert(c);
2291     pa_assert(s);
2292     pa_assert(buf);
2293 
2294     if (!fail)
2295         fail = &_fail;
2296 
2297     p = s;
2298     while (*p) {
2299         size_t l = strcspn(p, linebreak);
2300         char *line = pa_xstrndup(p, l);
2301 
2302         if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail) {
2303             pa_xfree(line);
2304             return -1;
2305         }
2306         pa_xfree(line);
2307 
2308         p += l;
2309         p += strspn(p, linebreak);
2310     }
2311 
2312     return 0;
2313 }
2314