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