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