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