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