• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 (pa_streq(n, "@NONE@"))
1042         pa_core_set_configured_default_sink(c, NULL);
1043     else if ((s = pa_namereg_get(c, n, PA_NAMEREG_SINK)))
1044         pa_core_set_configured_default_sink(c, s->name);
1045     else
1046         pa_strbuf_printf(buf, "Sink %s does not exist.\n", n);
1047 
1048     return 0;
1049 }
1050 
pa_cli_command_source_default(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1051 static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1052     const char *n;
1053     pa_source *s;
1054 
1055     pa_core_assert_ref(c);
1056     pa_assert(t);
1057     pa_assert(buf);
1058     pa_assert(fail);
1059 
1060     if (!(n = pa_tokenizer_get(t, 1))) {
1061         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
1062         return -1;
1063     }
1064 
1065     if (pa_streq(n, "@NONE@"))
1066         pa_core_set_configured_default_source(c, NULL);
1067     else if ((s = pa_namereg_get(c, n, PA_NAMEREG_SOURCE)))
1068         pa_core_set_configured_default_source(c, s->name);
1069     else
1070         pa_strbuf_printf(buf, "Source %s does not exist.\n", n);
1071     return 0;
1072 }
1073 
pa_cli_command_kill_client(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1074 static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1075     const char *n;
1076     pa_client *client;
1077     uint32_t idx;
1078 
1079     pa_core_assert_ref(c);
1080     pa_assert(t);
1081     pa_assert(buf);
1082     pa_assert(fail);
1083 
1084     if (!(n = pa_tokenizer_get(t, 1))) {
1085         pa_strbuf_puts(buf, "You need to specify a client by its index.\n");
1086         return -1;
1087     }
1088 
1089     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1090         pa_strbuf_puts(buf, "Failed to parse index.\n");
1091         return -1;
1092     }
1093 
1094     if (!(client = pa_idxset_get_by_index(c->clients, idx))) {
1095         pa_strbuf_puts(buf, "No client found by this index.\n");
1096         return -1;
1097     }
1098 
1099     pa_client_kill(client);
1100     return 0;
1101 }
1102 
pa_cli_command_kill_sink_input(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1103 static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1104     const char *n;
1105     pa_sink_input *sink_input;
1106     uint32_t idx;
1107 
1108     pa_core_assert_ref(c);
1109     pa_assert(t);
1110     pa_assert(buf);
1111     pa_assert(fail);
1112 
1113     if (!(n = pa_tokenizer_get(t, 1))) {
1114         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
1115         return -1;
1116     }
1117 
1118     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1119         pa_strbuf_puts(buf, "Failed to parse index.\n");
1120         return -1;
1121     }
1122 
1123     if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, idx))) {
1124         pa_strbuf_puts(buf, "No sink input found by this index.\n");
1125         return -1;
1126     }
1127 
1128     pa_sink_input_kill(sink_input);
1129     return 0;
1130 }
1131 
pa_cli_command_kill_source_output(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1132 static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1133     const char *n;
1134     pa_source_output *source_output;
1135     uint32_t idx;
1136 
1137     pa_core_assert_ref(c);
1138     pa_assert(t);
1139     pa_assert(buf);
1140     pa_assert(fail);
1141 
1142     if (!(n = pa_tokenizer_get(t, 1))) {
1143         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
1144         return -1;
1145     }
1146 
1147     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1148         pa_strbuf_puts(buf, "Failed to parse index.\n");
1149         return -1;
1150     }
1151 
1152     if (!(source_output = pa_idxset_get_by_index(c->source_outputs, idx))) {
1153         pa_strbuf_puts(buf, "No source output found by this index.\n");
1154         return -1;
1155     }
1156 
1157     pa_source_output_kill(source_output);
1158     return 0;
1159 }
1160 
pa_cli_command_scache_list(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1161 static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1162     char *s;
1163 
1164     pa_core_assert_ref(c);
1165     pa_assert(t);
1166     pa_assert(buf);
1167     pa_assert(fail);
1168 
1169     pa_assert_se(s = pa_scache_list_to_string(c));
1170     pa_strbuf_puts(buf, s);
1171     pa_xfree(s);
1172 
1173     return 0;
1174 }
1175 
pa_cli_command_scache_play(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1176 static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1177     const char *n, *sink_name;
1178     pa_sink *sink;
1179     uint32_t idx;
1180 
1181     pa_core_assert_ref(c);
1182     pa_assert(t);
1183     pa_assert(buf);
1184     pa_assert(fail);
1185 
1186     if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
1187         pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n");
1188         return -1;
1189     }
1190 
1191     if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) {
1192         pa_strbuf_puts(buf, "No sink by that name.\n");
1193         return -1;
1194     }
1195 
1196     if (pa_scache_play_item(c, n, sink, PA_VOLUME_NORM, NULL, &idx) < 0) {
1197         pa_strbuf_puts(buf, "Failed to play sample.\n");
1198         return -1;
1199     }
1200 
1201     pa_strbuf_printf(buf, "Playing on sink input #%i\n", idx);
1202 
1203     return 0;
1204 }
1205 
pa_cli_command_scache_remove(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1206 static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1207     const char *n;
1208 
1209     pa_core_assert_ref(c);
1210     pa_assert(t);
1211     pa_assert(buf);
1212     pa_assert(fail);
1213 
1214     if (!(n = pa_tokenizer_get(t, 1))) {
1215         pa_strbuf_puts(buf, "You need to specify a sample name.\n");
1216         return -1;
1217     }
1218 
1219     if (pa_scache_remove_item(c, n) < 0) {
1220         pa_strbuf_puts(buf, "Failed to remove sample.\n");
1221         return -1;
1222     }
1223 
1224     return 0;
1225 }
1226 
pa_cli_command_scache_load(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1227 static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1228     const char *fname, *n;
1229     int r;
1230 
1231     pa_core_assert_ref(c);
1232     pa_assert(t);
1233     pa_assert(buf);
1234     pa_assert(fail);
1235 
1236     if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) {
1237         pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n");
1238         return -1;
1239     }
1240 
1241     if (strstr(pa_tokenizer_get(t, 0), "lazy"))
1242         r = pa_scache_add_file_lazy(c, n, fname, NULL);
1243     else
1244         r = pa_scache_add_file(c, n, fname, NULL);
1245 
1246     if (r < 0)
1247         pa_strbuf_puts(buf, "Failed to load sound file.\n");
1248 
1249     return 0;
1250 }
1251 
pa_cli_command_scache_load_dir(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1252 static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1253     const char *pname;
1254 
1255     pa_core_assert_ref(c);
1256     pa_assert(t);
1257     pa_assert(buf);
1258     pa_assert(fail);
1259 
1260     if (!(pname = pa_tokenizer_get(t, 1))) {
1261         pa_strbuf_puts(buf, "You need to specify a path name.\n");
1262         return -1;
1263     }
1264 
1265     if (pa_scache_add_directory_lazy(c, pname) < 0) {
1266         pa_strbuf_puts(buf, "Failed to load directory.\n");
1267         return -1;
1268     }
1269 
1270     return 0;
1271 }
1272 
pa_cli_command_play_file(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1273 static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1274     const char *fname, *sink_name;
1275     pa_sink *sink;
1276 
1277     pa_core_assert_ref(c);
1278     pa_assert(t);
1279     pa_assert(buf);
1280     pa_assert(fail);
1281 
1282     if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
1283         pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n");
1284         return -1;
1285     }
1286 
1287     if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) {
1288         pa_strbuf_puts(buf, "No sink by that name.\n");
1289         return -1;
1290     }
1291 #ifdef SNDFILE_ENABLE
1292     if (pa_play_file(sink, fname, NULL) < 0) {
1293         pa_strbuf_puts(buf, "Failed to play sound file.\n");
1294         return -1;
1295     }
1296 #else
1297     return -1;
1298 #endif
1299     return 0;
1300 }
1301 
pa_cli_command_list_shared_props(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1302 static int pa_cli_command_list_shared_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1303     pa_core_assert_ref(c);
1304     pa_assert(t);
1305     pa_assert(buf);
1306     pa_assert(fail);
1307 
1308     pa_shared_dump(c, buf);
1309     return 0;
1310 }
1311 
pa_cli_command_vacuum(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1312 static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1313     pa_core_assert_ref(c);
1314     pa_assert(t);
1315     pa_assert(buf);
1316     pa_assert(fail);
1317 
1318     pa_mempool_vacuum(c->mempool);
1319 
1320     return 0;
1321 }
1322 
pa_cli_command_move_sink_input(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1323 static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1324     const char *n, *k;
1325     pa_sink_input *si;
1326     pa_sink *sink;
1327     uint32_t idx;
1328 
1329     pa_core_assert_ref(c);
1330     pa_assert(t);
1331     pa_assert(buf);
1332     pa_assert(fail);
1333 
1334     if (!(n = pa_tokenizer_get(t, 1))) {
1335         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
1336         return -1;
1337     }
1338 
1339     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1340         pa_strbuf_puts(buf, "Failed to parse index.\n");
1341         return -1;
1342     }
1343 
1344     if (!(k = pa_tokenizer_get(t, 2))) {
1345         pa_strbuf_puts(buf, "You need to specify a sink.\n");
1346         return -1;
1347     }
1348 
1349     if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
1350         pa_strbuf_puts(buf, "No sink input found with this index.\n");
1351         return -1;
1352     }
1353 
1354     if (!(sink = pa_namereg_get(c, k, PA_NAMEREG_SINK))) {
1355         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
1356         return -1;
1357     }
1358 
1359     if (pa_sink_input_move_to(si, sink, true) < 0) {
1360         pa_strbuf_puts(buf, "Moved failed.\n");
1361         return -1;
1362     }
1363     return 0;
1364 }
1365 
pa_cli_command_move_source_output(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1366 static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1367     const char *n, *k;
1368     pa_source_output *so;
1369     pa_source *source;
1370     uint32_t idx;
1371 
1372     pa_core_assert_ref(c);
1373     pa_assert(t);
1374     pa_assert(buf);
1375     pa_assert(fail);
1376 
1377     if (!(n = pa_tokenizer_get(t, 1))) {
1378         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
1379         return -1;
1380     }
1381 
1382     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1383         pa_strbuf_puts(buf, "Failed to parse index.\n");
1384         return -1;
1385     }
1386 
1387     if (!(k = pa_tokenizer_get(t, 2))) {
1388         pa_strbuf_puts(buf, "You need to specify a source.\n");
1389         return -1;
1390     }
1391 
1392     if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) {
1393         pa_strbuf_puts(buf, "No source output found with this index.\n");
1394         return -1;
1395     }
1396 
1397     if (!(source = pa_namereg_get(c, k, PA_NAMEREG_SOURCE))) {
1398         pa_strbuf_puts(buf, "No source found by this name or index.\n");
1399         return -1;
1400     }
1401 
1402     if (pa_source_output_move_to(so, source, true) < 0) {
1403         pa_strbuf_puts(buf, "Moved failed.\n");
1404         return -1;
1405     }
1406     return 0;
1407 }
1408 
pa_cli_command_suspend_sink(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1409 static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1410     const char *n, *m;
1411     pa_sink *sink;
1412     int suspend, r;
1413 
1414     pa_core_assert_ref(c);
1415     pa_assert(t);
1416     pa_assert(buf);
1417     pa_assert(fail);
1418 
1419     if (!(n = pa_tokenizer_get(t, 1))) {
1420         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
1421         return -1;
1422     }
1423 
1424     if (!(m = pa_tokenizer_get(t, 2))) {
1425         pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
1426         return -1;
1427     }
1428 
1429     if ((suspend = pa_parse_boolean(m)) < 0) {
1430         pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
1431         return -1;
1432     }
1433 
1434     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
1435         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
1436         return -1;
1437     }
1438 
1439     pa_log_debug("%s of sink %s requested via CLI.", suspend ? "Suspending" : "Resuming", sink->name);
1440 
1441     if ((r = pa_sink_suspend(sink, suspend, PA_SUSPEND_USER)) < 0)
1442         pa_strbuf_printf(buf, "Failed to resume/suspend sink: %s\n", pa_strerror(r));
1443 
1444     return 0;
1445 }
1446 
pa_cli_command_suspend_source(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1447 static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1448     const char *n, *m;
1449     pa_source *source;
1450     int suspend, r;
1451 
1452     pa_core_assert_ref(c);
1453     pa_assert(t);
1454     pa_assert(buf);
1455     pa_assert(fail);
1456 
1457     if (!(n = pa_tokenizer_get(t, 1))) {
1458         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
1459         return -1;
1460     }
1461 
1462     if (!(m = pa_tokenizer_get(t, 2))) {
1463         pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
1464         return -1;
1465     }
1466 
1467     if ((suspend = pa_parse_boolean(m)) < 0) {
1468         pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
1469         return -1;
1470     }
1471 
1472     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
1473         pa_strbuf_puts(buf, "No source found by this name or index.\n");
1474         return -1;
1475     }
1476 
1477     pa_log_debug("%s of source %s requested via CLI.", suspend ? "Suspending" : "Resuming", source->name);
1478 
1479     if ((r = pa_source_suspend(source, suspend, PA_SUSPEND_USER)) < 0)
1480         pa_strbuf_printf(buf, "Failed to resume/suspend source: %s\n", pa_strerror(r));
1481 
1482     return 0;
1483 }
1484 
pa_cli_command_suspend(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1485 static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1486     const char *m;
1487     int suspend, r;
1488 
1489     pa_core_assert_ref(c);
1490     pa_assert(t);
1491     pa_assert(buf);
1492     pa_assert(fail);
1493 
1494     if (!(m = pa_tokenizer_get(t, 1))) {
1495         pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
1496         return -1;
1497     }
1498 
1499     if ((suspend = pa_parse_boolean(m)) < 0) {
1500         pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
1501         return -1;
1502     }
1503 
1504     pa_log_debug("%s of all sinks and sources requested via CLI.", suspend ? "Suspending" : "Resuming");
1505 
1506     if ((r = pa_sink_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0)
1507         pa_strbuf_printf(buf, "Failed to resume/suspend all sinks: %s\n", pa_strerror(r));
1508 
1509     if ((r = pa_source_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0)
1510         pa_strbuf_printf(buf, "Failed to resume/suspend all sources: %s\n", pa_strerror(r));
1511 
1512     return 0;
1513 }
1514 
pa_cli_command_log_target(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1515 static int pa_cli_command_log_target(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1516     const char *m;
1517     pa_log_target *log_target = NULL;
1518 
1519     pa_core_assert_ref(c);
1520     pa_assert(t);
1521     pa_assert(buf);
1522     pa_assert(fail);
1523 
1524     if (!(m = pa_tokenizer_get(t, 1))) {
1525         pa_strbuf_puts(buf, "You need to specify a log target (null|auto|syslog|stderr|file:PATH|newfile:PATH).\n");
1526         return -1;
1527     }
1528 
1529     /* 'auto' is actually the effect with 'stderr' */
1530     if (pa_streq(m, "auto"))
1531         log_target = pa_log_target_new(PA_LOG_STDERR, NULL);
1532     else {
1533         log_target = pa_log_parse_target(m);
1534 
1535         if (!log_target) {
1536             pa_strbuf_puts(buf, "Invalid log target.\n");
1537             return -1;
1538         }
1539     }
1540 
1541     if (pa_log_set_target(log_target) < 0) {
1542         pa_strbuf_puts(buf, "Failed to set log target.\n");
1543         pa_log_target_free(log_target);
1544         return -1;
1545     }
1546 
1547     pa_log_target_free(log_target);
1548 
1549     return 0;
1550 }
1551 
pa_cli_command_log_level(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1552 static int pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1553     const char *m;
1554     uint32_t level;
1555 
1556     pa_core_assert_ref(c);
1557     pa_assert(t);
1558     pa_assert(buf);
1559     pa_assert(fail);
1560 
1561     if (!(m = pa_tokenizer_get(t, 1))) {
1562         pa_strbuf_puts(buf, "You need to specify a log level (0..4).\n");
1563         return -1;
1564     }
1565 
1566     if (pa_atou(m, &level) < 0 || level >= PA_LOG_LEVEL_MAX) {
1567         pa_strbuf_puts(buf, "Failed to parse log level.\n");
1568         return -1;
1569     }
1570 
1571     pa_log_set_level(level);
1572 
1573     return 0;
1574 }
1575 
pa_cli_command_log_meta(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1576 static int pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1577     const char *m;
1578     int b;
1579 
1580     pa_core_assert_ref(c);
1581     pa_assert(t);
1582     pa_assert(buf);
1583     pa_assert(fail);
1584 
1585     if (!(m = pa_tokenizer_get(t, 1))) {
1586         pa_strbuf_puts(buf, "You need to specify a boolean.\n");
1587         return -1;
1588     }
1589 
1590     if ((b = pa_parse_boolean(m)) < 0) {
1591         pa_strbuf_puts(buf, "Failed to parse log meta switch.\n");
1592         return -1;
1593     }
1594 
1595     pa_log_set_flags(PA_LOG_PRINT_META, b ? PA_LOG_SET : PA_LOG_UNSET);
1596 
1597     return 0;
1598 }
1599 
pa_cli_command_log_time(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1600 static int pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1601     const char *m;
1602     int b;
1603 
1604     pa_core_assert_ref(c);
1605     pa_assert(t);
1606     pa_assert(buf);
1607     pa_assert(fail);
1608 
1609     if (!(m = pa_tokenizer_get(t, 1))) {
1610         pa_strbuf_puts(buf, "You need to specify a boolean.\n");
1611         return -1;
1612     }
1613 
1614     if ((b = pa_parse_boolean(m)) < 0) {
1615         pa_strbuf_puts(buf, "Failed to parse log meta switch.\n");
1616         return -1;
1617     }
1618 
1619     pa_log_set_flags(PA_LOG_PRINT_TIME, b ? PA_LOG_SET : PA_LOG_UNSET);
1620 
1621     return 0;
1622 }
1623 
pa_cli_command_log_backtrace(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1624 static int pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1625     const char *m;
1626     uint32_t nframes;
1627 
1628     pa_core_assert_ref(c);
1629     pa_assert(t);
1630     pa_assert(buf);
1631     pa_assert(fail);
1632 
1633     if (!(m = pa_tokenizer_get(t, 1))) {
1634         pa_strbuf_puts(buf, "You need to specify a backtrace level.\n");
1635         return -1;
1636     }
1637 
1638     if (pa_atou(m, &nframes) < 0 || nframes >= 1000) {
1639         pa_strbuf_puts(buf, "Failed to parse backtrace level.\n");
1640         return -1;
1641     }
1642 
1643     pa_log_set_show_backtrace(nframes);
1644 
1645     return 0;
1646 }
1647 
pa_cli_command_card_profile(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1648 static int pa_cli_command_card_profile(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1649     const char *n, *p;
1650     pa_card *card;
1651     pa_card_profile *profile;
1652 
1653     pa_core_assert_ref(c);
1654     pa_assert(t);
1655     pa_assert(buf);
1656     pa_assert(fail);
1657 
1658     if (!(n = pa_tokenizer_get(t, 1))) {
1659         pa_strbuf_puts(buf, "You need to specify a card either by its name or its index.\n");
1660         return -1;
1661     }
1662 
1663     if (!(p = pa_tokenizer_get(t, 2))) {
1664         pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
1665         return -1;
1666     }
1667 
1668     if (!(card = pa_namereg_get(c, n, PA_NAMEREG_CARD))) {
1669         pa_strbuf_puts(buf, "No card found by this name or index.\n");
1670         return -1;
1671     }
1672 
1673     if (!(profile = pa_hashmap_get(card->profiles, p))) {
1674         pa_strbuf_printf(buf, "No such profile: %s\n", p);
1675         return -1;
1676     }
1677 
1678     if (pa_card_set_profile(card, profile, true) < 0) {
1679         pa_strbuf_printf(buf, "Failed to set card profile to '%s'.\n", p);
1680         return -1;
1681     }
1682 
1683     return 0;
1684 }
1685 
pa_cli_command_sink_port(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1686 static int pa_cli_command_sink_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1687     const char *n, *p;
1688     pa_sink *sink;
1689 
1690     pa_core_assert_ref(c);
1691     pa_assert(t);
1692     pa_assert(buf);
1693     pa_assert(fail);
1694 
1695     if (!(n = pa_tokenizer_get(t, 1))) {
1696         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
1697         return -1;
1698     }
1699 
1700     if (!(p = pa_tokenizer_get(t, 2))) {
1701         pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
1702         return -1;
1703     }
1704 
1705     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
1706         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
1707         return -1;
1708     }
1709 
1710     if (pa_sink_set_port(sink, p, true) < 0) {
1711         pa_strbuf_printf(buf, "Failed to set sink port to '%s'.\n", p);
1712         return -1;
1713     }
1714 
1715     return 0;
1716 }
1717 
pa_cli_command_source_port(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1718 static int pa_cli_command_source_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1719     const char *n, *p;
1720     pa_source *source;
1721 
1722     pa_core_assert_ref(c);
1723     pa_assert(t);
1724     pa_assert(buf);
1725     pa_assert(fail);
1726 
1727     if (!(n = pa_tokenizer_get(t, 1))) {
1728         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
1729         return -1;
1730     }
1731 
1732     if (!(p = pa_tokenizer_get(t, 2))) {
1733         pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
1734         return -1;
1735     }
1736 
1737     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
1738         pa_strbuf_puts(buf, "No source found by this name or index.\n");
1739         return -1;
1740     }
1741 
1742     if (pa_source_set_port(source, p, true) < 0) {
1743         pa_strbuf_printf(buf, "Failed to set source port to '%s'.\n", p);
1744         return -1;
1745     }
1746 
1747     return 0;
1748 }
1749 
pa_cli_command_port_offset(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1750 static int pa_cli_command_port_offset(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1751     const char *n, *p, *l;
1752     pa_device_port *port;
1753     pa_card *card;
1754     int32_t offset;
1755 
1756     pa_core_assert_ref(c);
1757     pa_assert(t);
1758     pa_assert(buf);
1759     pa_assert(fail);
1760 
1761     if (!(n = pa_tokenizer_get(t, 1))) {
1762         pa_strbuf_puts(buf, "You need to specify a card either by its name or its index.\n");
1763         return -1;
1764     }
1765 
1766     if (!(p = pa_tokenizer_get(t, 2))) {
1767         pa_strbuf_puts(buf, "You need to specify a port by its name.\n");
1768         return -1;
1769     }
1770 
1771     if (!(l = pa_tokenizer_get(t, 3))) {
1772         pa_strbuf_puts(buf, "You need to specify a latency offset.\n");
1773         return -1;
1774     }
1775 
1776     if (pa_atoi(l, &offset) < 0) {
1777         pa_strbuf_puts(buf, "Failed to parse the latency offset.\n");
1778         return -1;
1779     }
1780 
1781     if (!(card = pa_namereg_get(c, n, PA_NAMEREG_CARD))) {
1782         pa_strbuf_puts(buf, "No card found by this name or index.\n");
1783         return -1;
1784     }
1785 
1786     if (!(port = pa_hashmap_get(card->ports, p))) {
1787         pa_strbuf_puts(buf, "No port found by this name.\n");
1788         return -1;
1789     }
1790 
1791     pa_device_port_set_latency_offset(port, offset);
1792 
1793     return 0;
1794 }
1795 
pa_cli_command_send_message_to_object(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1796 static int pa_cli_command_send_message_to_object(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1797     const char *object_path, *message, *message_parameters;
1798     char *response = NULL;
1799     int ret;
1800 
1801     pa_core_assert_ref(c);
1802     pa_assert(t);
1803     pa_assert(buf);
1804     pa_assert(fail);
1805 
1806 
1807     if (!(object_path = pa_tokenizer_get(t, 1))) {
1808         pa_strbuf_puts(buf, "You need to specify an object path as recipient for the message.\n");
1809            return -1;
1810     }
1811 
1812     if (!(message = pa_tokenizer_get(t, 2))) {
1813         pa_strbuf_puts(buf, "You need to specify a message name.\n");
1814         return -1;
1815     }
1816 
1817     /* parameters may be NULL */
1818     message_parameters = pa_tokenizer_get(t, 3);
1819 
1820     ret = pa_message_handler_send_message(c, object_path, message, message_parameters, &response);
1821 
1822     if (ret < 0) {
1823         pa_strbuf_printf(buf, "Send message failed: %s\n", pa_strerror(ret));
1824         ret = -1;
1825 
1826     } else {
1827         if (response)
1828             pa_strbuf_puts(buf, response);
1829         pa_strbuf_puts(buf, "\n");
1830         ret = 0;
1831     }
1832 
1833     pa_xfree(response);
1834     return ret;
1835 }
1836 
pa_cli_command_dump(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1837 static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1838     pa_module *m;
1839     pa_sink *sink;
1840     pa_source *source;
1841     pa_card *card;
1842     bool nl;
1843     uint32_t idx;
1844     time_t now;
1845 #ifdef HAVE_CTIME_R
1846     char txt[256];
1847 #endif
1848 
1849     pa_core_assert_ref(c);
1850     pa_assert(t);
1851     pa_assert(buf);
1852     pa_assert(fail);
1853 
1854     time(&now);
1855 
1856 #ifdef HAVE_CTIME_R
1857     pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt));
1858 #else
1859     pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now));
1860 #endif
1861 
1862     PA_IDXSET_FOREACH(m, c->modules, idx) {
1863 
1864         pa_strbuf_printf(buf, "load-module %s", m->name);
1865 
1866         if (m->argument)
1867             pa_strbuf_printf(buf, " %s", m->argument);
1868 
1869         pa_strbuf_puts(buf, "\n");
1870     }
1871 
1872     nl = false;
1873     PA_IDXSET_FOREACH(sink, c->sinks, idx) {
1874 
1875         if (!nl) {
1876             pa_strbuf_puts(buf, "\n");
1877             nl = true;
1878         }
1879 
1880         pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_max(pa_sink_get_volume(sink, false)));
1881         pa_strbuf_printf(buf, "set-sink-mute %s %s\n", sink->name, pa_yes_no(pa_sink_get_mute(sink, false)));
1882         pa_strbuf_printf(buf, "suspend-sink %s %s\n", sink->name, pa_yes_no(sink->state == PA_SINK_SUSPENDED));
1883     }
1884 
1885     nl = false;
1886     PA_IDXSET_FOREACH(source, c->sources, idx) {
1887 
1888         if (!nl) {
1889             pa_strbuf_puts(buf, "\n");
1890             nl = true;
1891         }
1892 
1893         pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_max(pa_source_get_volume(source, false)));
1894         pa_strbuf_printf(buf, "set-source-mute %s %s\n", source->name, pa_yes_no(pa_source_get_mute(source, false)));
1895         pa_strbuf_printf(buf, "suspend-source %s %s\n", source->name, pa_yes_no(source->state == PA_SOURCE_SUSPENDED));
1896     }
1897 
1898     nl = false;
1899     PA_IDXSET_FOREACH(card, c->cards, idx) {
1900 
1901         if (!nl) {
1902             pa_strbuf_puts(buf, "\n");
1903             nl = true;
1904         }
1905 
1906         pa_strbuf_printf(buf, "set-card-profile %s %s\n", card->name, card->active_profile->name);
1907     }
1908 
1909     nl = false;
1910     if (c->default_sink) {
1911         if (!nl) {
1912             pa_strbuf_puts(buf, "\n");
1913             nl = true;
1914         }
1915 
1916         pa_strbuf_printf(buf, "set-default-sink %s\n", c->default_sink->name);
1917     }
1918 
1919     if (c->default_source) {
1920         if (!nl)
1921             pa_strbuf_puts(buf, "\n");
1922 
1923         pa_strbuf_printf(buf, "set-default-source %s\n", c->default_source->name);
1924     }
1925 
1926     pa_strbuf_puts(buf, "\n### EOF\n");
1927 
1928     return 0;
1929 }
1930 
pa_cli_command_dump_volumes(pa_core * c,pa_tokenizer * t,pa_strbuf * buf,bool * fail)1931 static int pa_cli_command_dump_volumes(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
1932     pa_sink *s;
1933     pa_source *so;
1934     pa_sink_input *i;
1935     pa_source_output *o;
1936     uint32_t s_idx, i_idx;
1937     char v_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
1938     pa_channel_map *map;
1939 
1940     pa_core_assert_ref(c);
1941     pa_assert(t);
1942     pa_assert(buf);
1943     pa_assert(fail);
1944 
1945     PA_IDXSET_FOREACH(s, c->sinks, s_idx) {
1946         map = &s->channel_map;
1947         pa_strbuf_printf(buf, "Sink %d: ", s_idx);
1948         pa_strbuf_printf(buf,
1949                          "reference = %s, ",
1950                          pa_cvolume_snprint_verbose(v_str,
1951                                                     sizeof(v_str),
1952                                                     &s->reference_volume,
1953                                                     map,
1954                                                     s->flags & PA_SINK_DECIBEL_VOLUME));
1955         pa_strbuf_printf(buf,
1956                          "real = %s, ",
1957                          pa_cvolume_snprint_verbose(v_str,
1958                                                     sizeof(v_str),
1959                                                     &s->real_volume,
1960                                                     &s->channel_map,
1961                                                     s->flags & PA_SINK_DECIBEL_VOLUME));
1962         pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &s->soft_volume, map, true));
1963         pa_strbuf_printf(buf,
1964                          "current_hw = %s, ",
1965                          pa_cvolume_snprint_verbose(v_str,
1966                                                     sizeof(v_str),
1967                                                     &s->thread_info.current_hw_volume,
1968                                                     map,
1969                                                     s->flags & PA_SINK_DECIBEL_VOLUME));
1970         pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(s->save_volume));
1971 
1972         PA_IDXSET_FOREACH(i, s->inputs, i_idx) {
1973             map = &i->channel_map;
1974             pa_strbuf_printf(buf, "\tInput %d: ", i_idx);
1975             pa_strbuf_printf(buf, "volume = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->volume, map, true));
1976             pa_strbuf_printf(buf,
1977                              "reference_ratio = %s, ",
1978                              pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->reference_ratio, map, true));
1979             pa_strbuf_printf(buf,
1980                              "real_ratio = %s, ",
1981                              pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->real_ratio, map, true));
1982             pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->soft_volume, map, true));
1983             pa_strbuf_printf(buf,
1984                              "volume_factor = %s, ",
1985                              pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->volume_factor, map, true));
1986             pa_strbuf_printf(buf,
1987                              "volume_factor_sink = %s, ",
1988                              pa_cvolume_snprint_verbose(v_str,
1989                                                         sizeof(v_str),
1990                                                         &i->volume_factor_sink,
1991                                                         &i->sink->channel_map,
1992                                                         true));
1993             pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(i->save_volume));
1994         }
1995     }
1996 
1997     PA_IDXSET_FOREACH(so, c->sources, s_idx) {
1998         map = &so->channel_map;
1999         pa_strbuf_printf(buf, "Source %d: ", s_idx);
2000         pa_strbuf_printf(buf,
2001                          "reference = %s, ",
2002                          pa_cvolume_snprint_verbose(v_str,
2003                                                     sizeof(v_str),
2004                                                     &so->reference_volume,
2005                                                     map,
2006                                                     so->flags & PA_SOURCE_DECIBEL_VOLUME));
2007         pa_strbuf_printf(buf,
2008                          "real = %s, ",
2009                          pa_cvolume_snprint_verbose(v_str,
2010                                                     sizeof(v_str),
2011                                                     &so->real_volume,
2012                                                     map,
2013                                                     so->flags & PA_SOURCE_DECIBEL_VOLUME));
2014         pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &so->soft_volume, map, true));
2015         pa_strbuf_printf(buf,
2016                          "current_hw = %s, ",
2017                          pa_cvolume_snprint_verbose(v_str,
2018                                                     sizeof(v_str),
2019                                                     &so->thread_info.current_hw_volume,
2020                                                     map,
2021                                                     so->flags & PA_SOURCE_DECIBEL_VOLUME));
2022         pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(so->save_volume));
2023 
2024         PA_IDXSET_FOREACH(o, so->outputs, i_idx) {
2025             map = &o->channel_map;
2026             pa_strbuf_printf(buf, "\tOutput %d: ", i_idx);
2027             pa_strbuf_printf(buf, "volume = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->volume, map, true));
2028             pa_strbuf_printf(buf,
2029                              "reference_ratio = %s, ",
2030                              pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->reference_ratio, map, true));
2031             pa_strbuf_printf(buf,
2032                              "real_ratio = %s, ",
2033                              pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->real_ratio, map, true));
2034             pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->soft_volume, map, true));
2035             pa_strbuf_printf(buf,
2036                              "volume_factor = %s, ",
2037                              pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->volume_factor, map, true));
2038             pa_strbuf_printf(buf,
2039                              "volume_factor_source = %s, ",
2040                              pa_cvolume_snprint_verbose(v_str,
2041                                                         sizeof(v_str),
2042                                                         &o->volume_factor_source,
2043                                                         &o->source->channel_map,
2044                                                         true));
2045             pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(o->save_volume));
2046         }
2047     }
2048 
2049     return 0;
2050 }
2051 
pa_cli_command_execute_line_stateful(pa_core * c,const char * s,pa_strbuf * buf,bool * fail,int * ifstate)2052 int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, bool *fail, int *ifstate) {
2053     const char *cs;
2054 
2055     pa_assert(c);
2056     pa_assert(s);
2057     pa_assert(buf);
2058 
2059     cs = s+strspn(s, whitespace);
2060 
2061     if (*cs == '#' || !*cs)
2062         return 0;
2063     else if (*cs == '.') {
2064         if (!strcmp(cs, META_ELSE)) {
2065             if (!ifstate || *ifstate == IFSTATE_NONE) {
2066                 pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
2067                 return -1;
2068             } else if (*ifstate == IFSTATE_TRUE)
2069                 *ifstate = IFSTATE_FALSE;
2070             else
2071                 *ifstate = IFSTATE_TRUE;
2072             return 0;
2073         } else if (!strcmp(cs, META_ENDIF)) {
2074             if (!ifstate || *ifstate == IFSTATE_NONE) {
2075                 pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
2076                 return -1;
2077             } else
2078                 *ifstate = IFSTATE_NONE;
2079             return 0;
2080         }
2081         if (ifstate && *ifstate == IFSTATE_FALSE)
2082             return 0;
2083         if (!strcmp(cs, META_FAIL))
2084             *fail = true;
2085         else if (!strcmp(cs, META_NOFAIL))
2086             *fail = false;
2087         else {
2088             size_t l;
2089             l = strcspn(cs, whitespace);
2090 
2091             if (l == sizeof(META_INCLUDE)-1 && !strncmp(cs, META_INCLUDE, l)) {
2092                 struct stat st;
2093                 const char *fn = cs+l+strspn(cs+l, whitespace);
2094 
2095                 char *filename;
2096 #ifdef OS_IS_WIN32
2097                 if (strncmp(fn, PA_DEFAULT_CONFIG_DIR, strlen(PA_DEFAULT_CONFIG_DIR)) == 0)
2098                     filename = pa_sprintf_malloc("%s" PA_PATH_SEP "etc" PA_PATH_SEP "pulse" PA_PATH_SEP "%s",
2099                                             pa_win32_get_toplevel(NULL),
2100                                             fn + strlen(PA_DEFAULT_CONFIG_DIR));
2101                 else
2102 #endif
2103                 filename = pa_xstrdup(fn);
2104 
2105                 if (stat(filename, &st) < 0) {
2106                     pa_log_warn("stat('%s'): %s", filename, pa_cstrerror(errno));
2107                     if (*fail) {
2108                         pa_xfree(filename);
2109                         return -1;
2110                     }
2111                 } else {
2112                     if (S_ISDIR(st.st_mode)) {
2113                         DIR *d;
2114 
2115                         if (!(d = opendir(filename))) {
2116                             pa_log_warn("Failed to read '%s': %s", filename, pa_cstrerror(errno));
2117                             if (*fail) {
2118                                 pa_xfree(filename);
2119                                 return -1;
2120                             }
2121                         } else {
2122                             unsigned i, count;
2123                             char **sorted_files;
2124                             struct dirent *de;
2125                             bool failed = false;
2126                             pa_dynarray *files = pa_dynarray_new(NULL);
2127 
2128                             while ((de = readdir(d))) {
2129                                 char *extn;
2130                                 size_t flen = strlen(de->d_name);
2131 
2132                                 if (flen < 4)
2133                                     continue;
2134 
2135                                 extn = &de->d_name[flen-3];
2136                                 if (strncmp(extn, ".pa", 3) == 0)
2137                                     pa_dynarray_append(files, pa_sprintf_malloc("%s" PA_PATH_SEP "%s", filename, de->d_name));
2138                             }
2139 
2140                             closedir(d);
2141                             if ((count = pa_dynarray_size(files))) {
2142                                 sorted_files = pa_xnew(char*, count);
2143                                 for (i = 0; i < count; ++i)
2144                                     sorted_files[i] = pa_dynarray_get(files, i);
2145                                 pa_dynarray_free(files);
2146 
2147                                 for (i = 0; i < count; ++i) {
2148                                     for (unsigned j = 0; j < count; ++j) {
2149                                         if (strcmp(sorted_files[i], sorted_files[j]) < 0) {
2150                                             char *tmp = sorted_files[i];
2151                                             sorted_files[i] = sorted_files[j];
2152                                             sorted_files[j] = tmp;
2153                                         }
2154                                     }
2155                                 }
2156 
2157                                 for (i = 0; i < count; ++i) {
2158                                     if (!failed) {
2159                                         if (pa_cli_command_execute_file(c, sorted_files[i], buf, fail) < 0 && *fail)
2160                                             failed = true;
2161                                     }
2162 
2163                                     pa_xfree(sorted_files[i]);
2164                                 }
2165                                 pa_xfree(sorted_files);
2166                                 if (failed) {
2167                                     pa_xfree(filename);
2168                                     return -1;
2169                                 }
2170                             }
2171                         }
2172                     } else if (pa_cli_command_execute_file(c, filename, buf, fail) < 0 && *fail) {
2173                         pa_xfree(filename);
2174                         return -1;
2175                     }
2176                 }
2177                 pa_xfree(filename);
2178             } else if (l == sizeof(META_IFEXISTS)-1 && !strncmp(cs, META_IFEXISTS, l)) {
2179                 if (!ifstate) {
2180                     pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
2181                     return -1;
2182                 } else if (*ifstate != IFSTATE_NONE) {
2183                     pa_strbuf_printf(buf, "Nested %s commands not supported\n", cs);
2184                     return -1;
2185                 } else {
2186                     const char *filename = cs+l+strspn(cs+l, whitespace);
2187                     *ifstate = pa_module_exists(filename) ? IFSTATE_TRUE : IFSTATE_FALSE;
2188                 }
2189             } else {
2190                 pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs);
2191                 if (*fail) return -1;
2192             }
2193         }
2194     } else {
2195         const struct command*command;
2196         int unknown = 1;
2197         size_t l;
2198 
2199         if (ifstate && *ifstate == IFSTATE_FALSE)
2200             return 0;
2201 
2202         l = strcspn(cs, whitespace);
2203 
2204         for (command = commands; command->name; command++)
2205             if (strlen(command->name) == l && !strncmp(cs, command->name, l)) {
2206                 int ret;
2207                 pa_tokenizer *t = pa_tokenizer_new(cs, command->args);
2208                 pa_assert(t);
2209                 ret = command->proc(c, t, buf, fail);
2210                 pa_tokenizer_free(t);
2211                 unknown = 0;
2212 
2213                 if (ret < 0 && *fail)
2214                     return -1;
2215 
2216                 break;
2217             }
2218 
2219         if (unknown) {
2220             pa_strbuf_printf(buf, "Unknown command: %s\n", cs);
2221             if (*fail)
2222                 return -1;
2223         }
2224     }
2225 
2226     return 0;
2227 }
2228 
pa_cli_command_execute_line(pa_core * c,const char * s,pa_strbuf * buf,bool * fail)2229 int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, bool *fail) {
2230     return pa_cli_command_execute_line_stateful(c, s, buf, fail, NULL);
2231 }
2232 
pa_cli_command_execute_file_stream(pa_core * c,FILE * f,pa_strbuf * buf,bool * fail)2233 int pa_cli_command_execute_file_stream(pa_core *c, FILE *f, pa_strbuf *buf, bool *fail) {
2234     char line[2048];
2235     int ifstate = IFSTATE_NONE;
2236     int ret = -1;
2237     bool _fail = true;
2238 
2239     pa_assert(c);
2240     pa_assert(f);
2241     pa_assert(buf);
2242 
2243     if (!fail)
2244         fail = &_fail;
2245 
2246     while (fgets(line, sizeof(line), f)) {
2247         pa_strip_nl(line);
2248 
2249         if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail)
2250             goto fail;
2251     }
2252 
2253     ret = 0;
2254 
2255 fail:
2256 
2257     return ret;
2258 }
2259 
pa_cli_command_execute_file(pa_core * c,const char * fn,pa_strbuf * buf,bool * fail)2260 int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, bool *fail) {
2261     FILE *f = NULL;
2262     int ret = -1;
2263     bool _fail = true;
2264 
2265     pa_assert(c);
2266     pa_assert(fn);
2267     pa_assert(buf);
2268 
2269     if (!fail)
2270         fail = &_fail;
2271 
2272     if (!(f = pa_fopen_cloexec(fn, "r"))) {
2273         pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, pa_cstrerror(errno));
2274         if (!*fail)
2275             ret = 0;
2276         goto fail;
2277     }
2278 
2279     pa_log_debug("Parsing script '%s'", fn);
2280     ret = pa_cli_command_execute_file_stream(c, f, buf, fail);
2281 
2282 fail:
2283     if (f)
2284         fclose(f);
2285 
2286     return ret;
2287 }
2288 
pa_cli_command_execute(pa_core * c,const char * s,pa_strbuf * buf,bool * fail)2289 int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, bool *fail) {
2290     const char *p;
2291     int ifstate = IFSTATE_NONE;
2292     bool _fail = true;
2293 
2294     pa_assert(c);
2295     pa_assert(s);
2296     pa_assert(buf);
2297 
2298     if (!fail)
2299         fail = &_fail;
2300 
2301     p = s;
2302     while (*p) {
2303         size_t l = strcspn(p, linebreak);
2304         char *line = pa_xstrndup(p, l);
2305 
2306         if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail) {
2307             pa_xfree(line);
2308             return -1;
2309         }
2310         pa_xfree(line);
2311 
2312         p += l;
2313         p += strspn(p, linebreak);
2314     }
2315 
2316     return 0;
2317 }
2318