Git init
[framework/multimedia/pulseaudio.git] / src / modules / gconf / module-gconf.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2006 Lennart Poettering
5
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include <sys/types.h>
32 #include <sys/wait.h>
33 #include <fcntl.h>
34
35 #include <pulse/xmalloc.h>
36 #include <pulsecore/module.h>
37 #include <pulsecore/core.h>
38 #include <pulsecore/llist.h>
39 #include <pulsecore/core-util.h>
40 #include <pulsecore/log.h>
41 #include <pulse/mainloop-api.h>
42 #include <pulsecore/core-error.h>
43 #include <pulsecore/start-child.h>
44
45 #include "module-gconf-symdef.h"
46
47 PA_MODULE_AUTHOR("Lennart Poettering");
48 PA_MODULE_DESCRIPTION("GConf Adapter");
49 PA_MODULE_VERSION(PACKAGE_VERSION);
50 PA_MODULE_LOAD_ONCE(TRUE);
51
52 #define MAX_MODULES 10
53 #define BUF_MAX 2048
54
55 struct module_item {
56     char *name;
57     char *args;
58     uint32_t index;
59 };
60
61 struct module_info {
62     char *name;
63
64     struct module_item items[MAX_MODULES];
65     unsigned n_items;
66 };
67
68 struct userdata {
69     pa_core *core;
70     pa_module *module;
71
72     pa_hashmap *module_infos;
73
74     pid_t pid;
75
76     int fd;
77     int fd_type;
78     pa_io_event *io_event;
79
80     char buf[BUF_MAX];
81     size_t buf_fill;
82 };
83
84 static int fill_buf(struct userdata *u) {
85     ssize_t r;
86     pa_assert(u);
87
88     if (u->buf_fill >= BUF_MAX) {
89         pa_log("read buffer overflow");
90         return -1;
91     }
92
93     if ((r = pa_read(u->fd, u->buf + u->buf_fill, BUF_MAX - u->buf_fill, &u->fd_type)) <= 0)
94         return -1;
95
96     u->buf_fill += (size_t) r;
97     return 0;
98 }
99
100 static int read_byte(struct userdata *u) {
101     int ret;
102     pa_assert(u);
103
104     if (u->buf_fill < 1)
105         if (fill_buf(u) < 0)
106             return -1;
107
108     ret = u->buf[0];
109     pa_assert(u->buf_fill > 0);
110     u->buf_fill--;
111     memmove(u->buf, u->buf+1, u->buf_fill);
112     return ret;
113 }
114
115 static char *read_string(struct userdata *u) {
116     pa_assert(u);
117
118     for (;;) {
119         char *e;
120
121         if ((e = memchr(u->buf, 0, u->buf_fill))) {
122             char *ret = pa_xstrdup(u->buf);
123             u->buf_fill -= (size_t) (e - u->buf +1);
124             memmove(u->buf, e+1, u->buf_fill);
125             return ret;
126         }
127
128         if (fill_buf(u) < 0)
129             return NULL;
130     }
131 }
132
133 static void unload_one_module(struct userdata *u, struct module_info*m, unsigned i) {
134     pa_assert(u);
135     pa_assert(m);
136     pa_assert(i < m->n_items);
137
138     if (m->items[i].index == PA_INVALID_INDEX)
139         return;
140
141     pa_log_debug("Unloading module #%i", m->items[i].index);
142     pa_module_unload_by_index(u->core, m->items[i].index, TRUE);
143     m->items[i].index = PA_INVALID_INDEX;
144     pa_xfree(m->items[i].name);
145     pa_xfree(m->items[i].args);
146     m->items[i].name = m->items[i].args = NULL;
147 }
148
149 static void unload_all_modules(struct userdata *u, struct module_info*m) {
150     unsigned i;
151
152     pa_assert(u);
153     pa_assert(m);
154
155     for (i = 0; i < m->n_items; i++)
156         unload_one_module(u, m, i);
157
158     m->n_items = 0;
159 }
160
161 static void load_module(
162         struct userdata *u,
163         struct module_info *m,
164         unsigned i,
165         const char *name,
166         const char *args,
167         pa_bool_t is_new) {
168
169     pa_module *mod;
170
171     pa_assert(u);
172     pa_assert(m);
173     pa_assert(name);
174     pa_assert(args);
175
176     if (!is_new) {
177         if (m->items[i].index != PA_INVALID_INDEX &&
178             strcmp(m->items[i].name, name) == 0 &&
179             strcmp(m->items[i].args, args) == 0)
180             return;
181
182         unload_one_module(u, m, i);
183     }
184
185     pa_log_debug("Loading module '%s' with args '%s' due to GConf configuration.", name, args);
186
187     m->items[i].name = pa_xstrdup(name);
188     m->items[i].args = pa_xstrdup(args);
189     m->items[i].index = PA_INVALID_INDEX;
190
191     if (!(mod = pa_module_load(u->core, name, args))) {
192         pa_log("pa_module_load() failed");
193         return;
194     }
195
196     m->items[i].index = mod->index;
197 }
198
199 static void module_info_free(void *p, void *userdata) {
200     struct module_info *m = p;
201     struct userdata *u = userdata;
202
203     pa_assert(m);
204     pa_assert(u);
205
206     unload_all_modules(u, m);
207     pa_xfree(m->name);
208     pa_xfree(m);
209 }
210
211 static int handle_event(struct userdata *u) {
212     int opcode;
213     int ret = 0;
214
215     do {
216         if ((opcode = read_byte(u)) < 0){
217             if (errno == EINTR || errno == EAGAIN)
218                 break;
219             goto fail;
220         }
221
222         switch (opcode) {
223             case '!':
224                 /* The helper tool is now initialized */
225                 ret = 1;
226                 break;
227
228             case '+': {
229                 char *name;
230                 struct module_info *m;
231                 unsigned i, j;
232
233                 if (!(name = read_string(u)))
234                     goto fail;
235
236                 if (!(m = pa_hashmap_get(u->module_infos, name))) {
237                     m = pa_xnew(struct module_info, 1);
238                     m->name = name;
239                     m->n_items = 0;
240                     pa_hashmap_put(u->module_infos, m->name, m);
241                 } else
242                     pa_xfree(name);
243
244                 i = 0;
245                 while (i < MAX_MODULES) {
246                     char *module, *args;
247
248                     if (!(module = read_string(u))) {
249                         if (i > m->n_items) m->n_items = i;
250                         goto fail;
251                     }
252
253                     if (!*module) {
254                         pa_xfree(module);
255                         break;
256                     }
257
258                     if (!(args = read_string(u))) {
259                         pa_xfree(module);
260
261                         if (i > m->n_items) m->n_items = i;
262                         goto fail;
263                     }
264
265                     load_module(u, m, i, module, args, i >= m->n_items);
266
267                     i++;
268
269                     pa_xfree(module);
270                     pa_xfree(args);
271                 }
272
273                 /* Unload all removed modules */
274                 for (j = i; j < m->n_items; j++)
275                     unload_one_module(u, m, j);
276
277                 m->n_items = i;
278
279                 break;
280             }
281
282             case '-': {
283                 char *name;
284                 struct module_info *m;
285
286                 if (!(name = read_string(u)))
287                     goto fail;
288
289                 if ((m = pa_hashmap_get(u->module_infos, name))) {
290                     pa_hashmap_remove(u->module_infos, name);
291                     module_info_free(m, u);
292                 }
293
294                 pa_xfree(name);
295
296                 break;
297             }
298         }
299     } while (u->buf_fill > 0 && ret == 0);
300
301     return ret;
302
303 fail:
304     pa_log("Unable to read or parse data from client.");
305     return -1;
306 }
307
308 static void io_event_cb(
309         pa_mainloop_api*a,
310         pa_io_event* e,
311         int fd,
312         pa_io_event_flags_t events,
313         void *userdata) {
314
315     struct userdata *u = userdata;
316
317     if (handle_event(u) < 0) {
318
319         if (u->io_event) {
320             u->core->mainloop->io_free(u->io_event);
321             u->io_event = NULL;
322         }
323
324         pa_module_unload_request(u->module, TRUE);
325     }
326 }
327
328 int pa__init(pa_module*m) {
329     struct userdata *u;
330     int r;
331
332     u = pa_xnew(struct userdata, 1);
333     u->core = m->core;
334     u->module = m;
335     m->userdata = u;
336     u->module_infos = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
337     u->pid = (pid_t) -1;
338     u->fd = -1;
339     u->fd_type = 0;
340     u->io_event = NULL;
341     u->buf_fill = 0;
342
343     if ((u->fd = pa_start_child_for_read(
344 #if defined(__linux__) && !defined(__OPTIMIZE__)
345                               pa_run_from_build_tree() ? PA_BUILDDIR "/gconf-helper" :
346 #endif
347                  PA_GCONF_HELPER, NULL, &u->pid)) < 0)
348         goto fail;
349
350     u->io_event = m->core->mainloop->io_new(
351             m->core->mainloop,
352             u->fd,
353             PA_IO_EVENT_INPUT,
354             io_event_cb,
355             u);
356
357     do {
358         if ((r = handle_event(u)) < 0)
359             goto fail;
360
361         /* Read until the client signalled us that it is ready with
362          * initialization */
363     } while (r != 1);
364
365     return 0;
366
367 fail:
368     pa__done(m);
369     return -1;
370 }
371
372 void pa__done(pa_module*m) {
373     struct userdata *u;
374
375     pa_assert(m);
376
377     if (!(u = m->userdata))
378         return;
379
380     if (u->pid != (pid_t) -1) {
381         kill(u->pid, SIGTERM);
382
383         for (;;) {
384             if (waitpid(u->pid, NULL, 0) >= 0)
385                 break;
386
387             if (errno != EINTR) {
388                 pa_log("waitpid() failed: %s", pa_cstrerror(errno));
389                 break;
390             }
391         }
392     }
393
394     if (u->io_event)
395         m->core->mainloop->io_free(u->io_event);
396
397     if (u->fd >= 0)
398         pa_close(u->fd);
399
400     if (u->module_infos)
401         pa_hashmap_free(u->module_infos, module_info_free, u);
402
403     pa_xfree(u);
404 }