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