Gentoo Archives: gentoo-commits

From: Alexandre Restovtsev <tetromino@×××××.com>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/openrc-settingsd:master commit in: src/, /, data/
Date: Thu, 09 Feb 2012 08:42:20
Message-Id: 5879972108bc28629f41c56d34592642df0c4588.tetromino@gentoo
1 commit: 5879972108bc28629f41c56d34592642df0c4588
2 Author: Alexandre Rostovtsev <tetromino <AT> gentoo <DOT> org>
3 AuthorDate: Thu Feb 9 08:26:48 2012 +0000
4 Commit: Alexandre Restovtsev <tetromino <AT> gmail <DOT> com>
5 CommitDate: Thu Feb 9 08:40:24 2012 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/openrc-settingsd.git;a=commit;h=58799721
7
8 Add beginnings of localed (read-only and no xorg.conf support)
9
10 ---
11 .gitignore | 1 +
12 Makefile.am | 21 +++++-
13 README | 22 +++++
14 TODO | 2 +-
15 data/locale1.xml | 30 +++++++
16 src/localed.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++++
17 src/localed.h | 31 +++++++
18 src/main.c | 3 +
19 src/shell-utils.c | 83 ++++++++++++++++----
20 src/shell-utils.h | 5 +
21 10 files changed, 406 insertions(+), 19 deletions(-)
22
23 diff --git a/.gitignore b/.gitignore
24 index b0d689f..8fae933 100644
25 --- a/.gitignore
26 +++ b/.gitignore
27 @@ -20,6 +20,7 @@
28 /openrc-settingsd
29 /stamp-h1
30 /src/hostname1-generated.[ch]
31 +/src/locale1-generated.[ch]
32
33 # Relative rules
34 *.o
35
36 diff --git a/Makefile.am b/Makefile.am
37 index f2a770a..7ae61ed 100644
38 --- a/Makefile.am
39 +++ b/Makefile.am
40 @@ -2,6 +2,7 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
41
42 EXTRA_DIST = \
43 data/hostname1.xml \
44 + data/locale1.xml \
45 $(NULL)
46
47 AM_CPPFLAGS = \
48 @@ -22,10 +23,18 @@ hostnamed_built_sources = \
49 src/hostname1-generated.h \
50 $(NULL)
51
52 +localed_built_sources = \
53 + src/locale1-generated.c \
54 + src/locale1-generated.h \
55 + $(NULL)
56 +
57 openrc_settingsd_SOURCES = \
58 $(hostnamed_built_sources) \
59 + $(localed_built_sources) \
60 src/hostnamed.c \
61 src/hostnamed.h \
62 + src/localed.c \
63 + src/localed.h \
64 src/bus-utils.c \
65 src/bus-utils.h \
66 src/shell-utils.c \
67 @@ -41,5 +50,13 @@ $(hostnamed_built_sources) : data/hostname1.xml
68 $(srcdir)/data/hostname1.xml; \
69 mv hostname1-generated.{c,h} $(top_srcdir)/src/ )
70
71 -BUILT_SOURCES = $(hostnamed_built_sources)
72 -CLEANFILES = $(hostnamed_built_sources)
73 +$(localed_built_sources) : data/locale1.xml
74 + ( $(GDBUS_CODEGEN) \
75 + --interface-prefix org.freedesktop. \
76 + --c-namespace OpenrcSettingsdLocaled \
77 + --generate-c-code locale1-generated \
78 + $(srcdir)/data/locale1.xml; \
79 + mv locale1-generated.{c,h} $(top_srcdir)/src/ )
80 +
81 +BUILT_SOURCES = $(hostnamed_built_sources) $(localed_built_sources)
82 +CLEANFILES = $(hostnamed_built_sources) $(localed_built_sources)
83
84 diff --git a/README b/README
85 index 62bd904..bd6adac 100644
86 --- a/README
87 +++ b/README
88 @@ -16,6 +16,28 @@ Hostnamed:
89 PRETTY_HOSTNAME="Foo !"
90 ICON_NAME="computer-desktop"
91
92 +Localed:
93 +
94 + See http://www.freedesktop.org/wiki/Software/systemd/localed for the DBus
95 + protocol description.
96 +
97 + The system locale variables are set in /etc/env.d/02locale.
98 +
99 + Virtual console keymap is set in /etc/conf.d/keymaps as
100 + keymap="foo"
101 + The virtual console keymap toggle is not supported.
102 +
103 +/*
104 + Not implemented yet.
105 +
106 + X11 keyboard options are set in /etc/X11/xorg.conf.d/30-keyboard.conf
107 + (falling back to 00-keyboard.conf if it exists and 30-keyboard.conf does
108 + not) in an InputClass section.
109 + Localed will attempt to detect if multiple InputClass sections with
110 + keyboard options exist in /etc/X11/xorg.conf and /etc/X11/xorg.conf.d/,
111 + and if that is the case, will refuse to modify X11 keyboard settings.
112 +*/
113 +
114 Note that openrc-settingsd expects any shell-syntax settings files that it
115 modifies to be in UTF-8 encoding, and to consist only of comments and simple
116 scalar assignments, i.e. something like
117
118 diff --git a/TODO b/TODO
119 index e8694da..a7feb33 100644
120 --- a/TODO
121 +++ b/TODO
122 @@ -1,4 +1,4 @@
123 -Add nss-myhostname detection (and add nss-myhostnane to portage)
124 +Add nss-myhostname detection
125
126 Source /etc/rc.conf after /etc/conf.d/$service; do something intelligent
127 if the relevant variable is set in /etc/rc.conf (go to read-only mode?)
128
129 diff --git a/data/locale1.xml b/data/locale1.xml
130 new file mode 100644
131 index 0000000..dfd98d3
132 --- /dev/null
133 +++ b/data/locale1.xml
134 @@ -0,0 +1,30 @@
135 +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
136 +<node name="/org/freedesktop/locale1">
137 + <interface name="org.freedesktop.locale1">
138 + <method name="SetLocale">
139 + <arg direction="in" type="as" name="locale"/>
140 + <arg direction="in" type="b" name="user_interaction"/>
141 + </method>
142 + <method name="SetVConsoleKeyboard">
143 + <arg direction="in" type="s" name="keymap"/>
144 + <arg direction="in" type="s" name="keymap_toggle"/>
145 + <arg direction="in" type="b" name="convert"/>
146 + <arg direction="in" type="b" name="user_interaction"/>
147 + </method>
148 + <method name="SetX11Keyboard">
149 + <arg direction="in" type="s" name="layout"/>
150 + <arg direction="in" type="s" name="model"/>
151 + <arg direction="in" type="s" name="variant"/>
152 + <arg direction="in" type="s" name="options"/>
153 + <arg direction="in" type="b" name="convert"/>
154 + <arg direction="in" type="b" name="user_interaction"/>
155 + </method>
156 + <property name="Locale" type="as" access="read"/>
157 + <property name="VConsoleKeymap" type="s" access="read"/>
158 + <property name="VConsoleKeymapToggle" type="s" access="read"/>
159 + <property name="X11Layout" type="s" access="read"/>
160 + <property name="X11Model" type="s" access="read"/>
161 + <property name="X11Variant" type="s" access="read"/>
162 + <property name="X11Options" type="s" access="read"/>
163 + </interface>
164 +</node>
165
166 diff --git a/src/localed.c b/src/localed.c
167 new file mode 100644
168 index 0000000..12d9ad7
169 --- /dev/null
170 +++ b/src/localed.c
171 @@ -0,0 +1,227 @@
172 +/*
173 + Copyright 2012 Alexandre Rostovtsev
174 +
175 + This program is free software; you can redistribute it and/or modify
176 + it under the terms of the GNU General Public License as published by
177 + the Free Software Foundation; either version 2 of the License, or
178 + (at your option) any later version.
179 +
180 + This program is distributed in the hope that it will be useful,
181 + but WITHOUT ANY WARRANTY; without even the implied warranty of
182 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
183 + GNU General Public License for more details.
184 +
185 + You should have received a copy of the GNU General Public License
186 + along with this program; if not, write to the Free Software
187 + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
188 +*/
189 +
190 +#include <stdlib.h>
191 +
192 +#include <dbus/dbus-protocol.h>
193 +#include <glib.h>
194 +#include <gio/gio.h>
195 +
196 +#include "localed.h"
197 +#include "locale1-generated.h"
198 +#include "bus-utils.h"
199 +#include "shell-utils.h"
200 +
201 +#include "config.h"
202 +
203 +#define SERVICE_NAME "openrc-settingsd localed"
204 +
205 +static guint bus_id = 0;
206 +static gboolean read_only = FALSE;
207 +
208 +static OpenrcSettingsdLocaledLocale1 *locale1 = NULL;
209 +
210 +static gchar *locale_variables[] = {
211 + "LANG", "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE", "LC_MONETARY", "LC_MESSAGES", "LC_PAPER", "LC_NAME", "LC_ADDRESS", "LC_TELEPHONE", "LC_MEASUREMENT", "LC_IDENTIFICATION", NULL
212 +};
213 +
214 +static gchar **locale = NULL; /* Expected format is { "LANG=foo", "LC_TIME=bar", NULL } */
215 +static GFile *locale_file = NULL;
216 +G_LOCK_DEFINE_STATIC (locale);
217 +
218 +static gchar *vconsole_keymap = NULL;
219 +static gchar *vconsole_keymap_toggle = NULL;
220 +static GFile *keymaps_file = NULL;
221 +G_LOCK_DEFINE_STATIC (keymaps);
222 +
223 +static gchar *x11_layout = NULL;
224 +static gchar *x11_model = NULL;
225 +static gchar *x11_variant = NULL;
226 +static gchar *x11_options = NULL;
227 +G_LOCK_DEFINE_STATIC (xorg_conf);
228 +
229 +static gboolean
230 +on_handle_set_locale (OpenrcSettingsdLocaledLocale1 *locale1,
231 + GDBusMethodInvocation *invocation,
232 + const gchar * const *_locale,
233 + const gboolean user_interaction,
234 + gpointer user_data)
235 +{
236 + g_dbus_method_invocation_return_dbus_error (invocation,
237 + DBUS_ERROR_NOT_SUPPORTED,
238 + SERVICE_NAME " is in read-only mode");
239 +
240 + return TRUE;
241 +}
242 +
243 +static gboolean
244 +on_handle_set_vconsole_keyboard (OpenrcSettingsdLocaledLocale1 *locale1,
245 + GDBusMethodInvocation *invocation,
246 + const gchar *keymap,
247 + const gchar *keymap_toggle,
248 + const gboolean convert,
249 + const gboolean user_interaction,
250 + gpointer user_data)
251 +{
252 + g_dbus_method_invocation_return_dbus_error (invocation,
253 + DBUS_ERROR_NOT_SUPPORTED,
254 + SERVICE_NAME " is in read-only mode");
255 +
256 + return TRUE;
257 +}
258 +
259 +static gboolean
260 +on_handle_set_x11_keyboard (OpenrcSettingsdLocaledLocale1 *locale1,
261 + GDBusMethodInvocation *invocation,
262 + const gchar *layout,
263 + const gchar *model,
264 + const gchar *variant,
265 + const gchar *options,
266 + const gboolean convert,
267 + const gboolean user_interaction,
268 + gpointer user_data)
269 +{
270 + g_dbus_method_invocation_return_dbus_error (invocation,
271 + DBUS_ERROR_NOT_SUPPORTED,
272 + SERVICE_NAME " is in read-only mode");
273 +
274 + return TRUE;
275 +}
276 +
277 +static void
278 +on_bus_acquired (GDBusConnection *connection,
279 + const gchar *bus_name,
280 + gpointer user_data)
281 +{
282 + gchar *name;
283 + GError *err = NULL;
284 +
285 + g_debug ("Acquired a message bus connection");
286 +
287 + locale1 = openrc_settingsd_localed_locale1_skeleton_new ();
288 +
289 + openrc_settingsd_localed_locale1_set_locale (locale1, (const gchar * const *) locale);
290 + openrc_settingsd_localed_locale1_set_vconsole_keymap (locale1, vconsole_keymap);
291 + openrc_settingsd_localed_locale1_set_vconsole_keymap_toggle (locale1, vconsole_keymap_toggle);
292 + openrc_settingsd_localed_locale1_set_x11_layout (locale1, x11_layout);
293 + openrc_settingsd_localed_locale1_set_x11_model (locale1, x11_model);
294 + openrc_settingsd_localed_locale1_set_x11_variant (locale1, x11_variant);
295 + openrc_settingsd_localed_locale1_set_x11_options (locale1, x11_options);
296 +
297 + g_signal_connect (locale1, "handle-set-locale", G_CALLBACK (on_handle_set_locale), NULL);
298 + g_signal_connect (locale1, "handle-set-vconsole-keyboard", G_CALLBACK (on_handle_set_vconsole_keyboard), NULL);
299 + g_signal_connect (locale1, "handle-set-x11-keyboard", G_CALLBACK (on_handle_set_x11_keyboard), NULL);
300 +
301 + if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (locale1),
302 + connection,
303 + "/org/freedesktop/locale1",
304 + &err)) {
305 + if (err != NULL) {
306 + g_printerr ("Failed to export interface on /org/freedesktop/locale1: %s\n", err->message);
307 + g_error_free (err);
308 + }
309 + }
310 +}
311 +
312 +static void
313 +on_name_acquired (GDBusConnection *connection,
314 + const gchar *bus_name,
315 + gpointer user_data)
316 +{
317 + g_debug ("Acquired the name %s", bus_name);
318 +}
319 +
320 +static void
321 +on_name_lost (GDBusConnection *connection,
322 + const gchar *bus_name,
323 + gpointer user_data)
324 +{
325 + if (connection == NULL)
326 + g_printerr ("Failed to acquire a dbus connection\n");
327 + else
328 + g_printerr ("Failed to acquire dbus name %s\n", bus_name);
329 + exit(-1);
330 +}
331 +
332 +void
333 +localed_init (gboolean _read_only)
334 +{
335 + GError *err = NULL;
336 + gchar **locale_values = NULL;
337 +
338 + read_only = _read_only;
339 + locale_file = g_file_new_for_path (SYSCONFDIR "/env.d/02locale");
340 + keymaps_file = g_file_new_for_path (SYSCONFDIR "/conf.d/keymaps");
341 +
342 + locale = g_new0 (gchar *, g_strv_length (locale_variables) + 1);
343 + locale_values = shell_utils_trivial_source_var_list (locale_file, (const gchar * const *)locale_variables, &err);
344 + if (locale_values != NULL) {
345 + gchar **variable, **value, **loc;
346 + loc = locale;
347 + for (variable = locale_variables, value = locale_values; *variable != NULL; variable++, value++) {
348 + if (*value != NULL) {
349 + *loc = g_strdup_printf ("%s=%s", *variable, *value);
350 + loc++;
351 + }
352 + }
353 +
354 + g_strfreev (locale_values);
355 + }
356 + if (err != NULL) {
357 + g_debug ("%s", err->message);
358 + g_clear_error (&err);
359 + }
360 +
361 + vconsole_keymap = shell_utils_source_var (keymaps_file, "${keymap}", &err);
362 + if (vconsole_keymap == NULL)
363 + vconsole_keymap = g_strdup ("");
364 + if (err != NULL) {
365 + g_debug ("%s", err->message);
366 + g_clear_error (&err);
367 + }
368 +
369 + /* We don't have a good equivalent for this in openrc at the moment */
370 + vconsole_keymap_toggle = g_strdup ("");
371 +
372 + bus_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
373 + "org.freedesktop.locale1",
374 + G_BUS_NAME_OWNER_FLAGS_NONE,
375 + on_bus_acquired,
376 + on_name_acquired,
377 + on_name_lost,
378 + NULL,
379 + NULL);
380 +}
381 +
382 +void
383 +localed_destroy (void)
384 +{
385 + g_bus_unown_name (bus_id);
386 + bus_id = 0;
387 + read_only = FALSE;
388 + g_strfreev (locale);
389 + g_free (vconsole_keymap);
390 + g_free (vconsole_keymap_toggle);
391 + g_free (x11_layout);
392 + g_free (x11_model);
393 + g_free (x11_variant);
394 + g_free (x11_options);
395 +
396 + g_object_unref (locale_file);
397 + g_object_unref (keymaps_file);
398 +}
399
400 diff --git a/src/localed.h b/src/localed.h
401 new file mode 100644
402 index 0000000..dff55c6
403 --- /dev/null
404 +++ b/src/localed.h
405 @@ -0,0 +1,31 @@
406 +/*
407 + Copyright 2012 Alexandre Rostovtsev
408 +
409 + This program is free software; you can redistribute it and/or modify
410 + it under the terms of the GNU General Public License as published by
411 + the Free Software Foundation; either version 2 of the License, or
412 + (at your option) any later version.
413 +
414 + This program is distributed in the hope that it will be useful,
415 + but WITHOUT ANY WARRANTY; without even the implied warranty of
416 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
417 + GNU General Public License for more details.
418 +
419 + You should have received a copy of the GNU General Public License
420 + along with this program; if not, write to the Free Software
421 + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
422 +*/
423 +
424 +#ifndef OPENRC_LOCALED_H
425 +#define OPENRC_LOCALED_H
426 +
427 +#include <glib.h>
428 +#include <gio/gio.h>
429 +
430 +void
431 +localed_init (gboolean read_only);
432 +
433 +void
434 +localed_destroy (void);
435 +
436 +#endif
437
438 diff --git a/src/main.c b/src/main.c
439 index c7165f0..fabb96c 100644
440 --- a/src/main.c
441 +++ b/src/main.c
442 @@ -23,6 +23,7 @@
443 #include <gio/gio.h>
444
445 #include "hostnamed.h"
446 +#include "localed.h"
447 #include "shell-utils.h"
448
449 #include "config.h"
450 @@ -68,10 +69,12 @@ main (gint argc, gchar *argv[])
451
452 shell_utils_init ();
453 hostnamed_init (read_only);
454 + localed_init (read_only);
455 loop = g_main_loop_new (NULL, FALSE);
456 g_main_loop_run (loop);
457
458 g_main_loop_unref (loop);
459 + localed_destroy ();
460 hostnamed_destroy ();
461 shell_utils_destroy ();
462 return 0;
463
464 diff --git a/src/shell-utils.c b/src/shell-utils.c
465 index 30026a9..db67303 100644
466 --- a/src/shell-utils.c
467 +++ b/src/shell-utils.c
468 @@ -45,6 +45,7 @@ struct ShellEntry {
469 enum ShellEntryType type;
470 gchar *string;
471 gchar *variable; /* only relevant for assignments */
472 + gchar *unquoted_value; /* only relevant for assignments */
473 };
474
475 gchar *
476 @@ -104,10 +105,9 @@ shell_entry_free (struct ShellEntry *entry)
477 if (entry == NULL)
478 return;
479
480 - if (entry->string != NULL)
481 - g_free (entry->string);
482 - if (entry->variable != NULL)
483 - g_free (entry->variable);
484 + g_free (entry->string);
485 + g_free (entry->variable);
486 + g_free (entry->unquoted_value);
487 g_free (entry);
488 }
489
490 @@ -132,7 +132,7 @@ shell_utils_trivial_new (GFile *file,
491 {
492 gchar *filebuf = NULL;
493 ShellUtilsTrivial *ret = NULL;
494 - GError *local_err;
495 + GError *local_err = NULL;
496 gchar *s;
497
498 if (file == NULL)
499 @@ -214,6 +214,7 @@ shell_utils_trivial_new (GFile *file,
500
501 matched = g_regex_match (var_equals_regex, s, 0, &match_info);
502 if (matched) {
503 + gchar *raw_value = NULL, *temp1 = NULL, *temp2 = NULL;
504 /* If we expect a separator and get an assignment instead, fail */
505 if (want_separator)
506 goto no_match;
507 @@ -231,7 +232,6 @@ shell_utils_trivial_new (GFile *file,
508 while (*s != 0) {
509 g_debug ("Scanning string for values: ``%s''", s);
510 gboolean matched2 = FALSE;
511 - gchar *temp1 = NULL, *temp2 = NULL;
512
513 matched2 = g_regex_match (single_quoted_regex, s, 0, &match_info);
514 if (matched2)
515 @@ -256,18 +256,36 @@ shell_utils_trivial_new (GFile *file,
516
517 break;
518 append_value:
519 +
520 + if (raw_value == NULL) {
521 + raw_value = g_match_info_fetch (match_info, 0);
522 + s += strlen (raw_value);
523 + g_debug ("Scanned value: ``%s''", raw_value);
524 + } else {
525 + temp1 = raw_value;
526 + temp2 = g_match_info_fetch (match_info, 0);
527 + raw_value = g_strconcat (temp1, temp2, NULL);
528 + s += strlen (temp2);
529 + g_debug ("Scanned value: ``%s''", temp2);
530 + g_free (temp1);
531 + g_free (temp2);
532 + }
533 + g_match_info_free (match_info);
534 + match_info = NULL;
535 + }
536 +
537 + if (raw_value != NULL) {
538 + entry->unquoted_value = g_shell_unquote (raw_value, &local_err);
539 + g_debug ("Unquoted value: ``%s''", entry->unquoted_value);
540 temp1 = entry->string;
541 - temp2 = g_match_info_fetch (match_info, 0);
542 + temp2 = raw_value;
543 entry->string = g_strconcat (temp1, temp2, NULL);
544 - s += strlen (temp2);
545 - g_debug ("Scanned value: ``%s''", temp2);
546 g_free (temp1);
547 g_free (temp2);
548 - g_match_info_free (match_info);
549 - match_info = NULL;
550 + ret->entry_list = g_list_prepend (ret->entry_list, entry);
551 + if (local_err != NULL)
552 + goto no_match;
553 }
554 -
555 - ret->entry_list = g_list_prepend (ret->entry_list, entry);
556 continue;
557 }
558
559 @@ -275,9 +293,12 @@ no_match:
560 /* Nothing matches, parsing has failed! */
561 g_match_info_free (match_info);
562 match_info = NULL;
563 - g_propagate_error (error,
564 - g_error_new (G_FILE_ERROR, G_FILE_ERROR_FAILED,
565 - "Unable to parse '%s'", ret->filename));
566 + if (local_err != NULL)
567 + g_propagate_prefixed_error (error, local_err, "Unable to parse '%s':", ret->filename);
568 + else
569 + g_propagate_error (error,
570 + g_error_new (G_FILE_ERROR, G_FILE_ERROR_FAILED,
571 + "Unable to parse '%s'", ret->filename));
572 shell_utils_trivial_free (ret);
573 return NULL;
574 }
575 @@ -420,6 +441,36 @@ shell_utils_trivial_set_and_save (GFile *file,
576 return ret;
577 }
578
579 +gchar **
580 +shell_utils_trivial_source_var_list (GFile *file,
581 + const gchar * const *var_names,
582 + GError **error)
583 +{
584 + ShellUtilsTrivial *trivial;
585 + gchar **ret = NULL, **value;
586 + const gchar* const* var_name;
587 +
588 + if (var_names == NULL)
589 + return NULL;
590 +
591 + if ((trivial = shell_utils_trivial_new (file, error)) == NULL)
592 + return NULL;
593 +
594 + ret = g_new0 (gchar *, g_strv_length ((gchar **)var_names) + 1);
595 + for (var_name = var_names, value = ret; *var_name != NULL; var_name++, value++) {
596 + GList *curr;
597 + for (curr = trivial->entry_list; curr != NULL; curr = curr->next) {
598 + struct ShellEntry *entry;
599 +
600 + entry = (struct ShellEntry *)(curr->data);
601 + if (entry->type == SHELL_ENTRY_TYPE_ASSIGNMENT && g_strcmp0 (*var_name, entry->variable) == 0)
602 + *value = g_strdup (entry->unquoted_value);
603 + }
604 + }
605 + shell_utils_trivial_free (trivial);
606 + return ret;
607 +}
608 +
609 void
610 shell_utils_destroy (void)
611 {
612
613 diff --git a/src/shell-utils.h b/src/shell-utils.h
614 index 5e1863d..9ca40e9 100644
615 --- a/src/shell-utils.h
616 +++ b/src/shell-utils.h
617 @@ -66,4 +66,9 @@ shell_utils_trivial_set_and_save (GFile *file,
618 const gchar *first_alt_var_name,
619 const gchar *first_value,
620 ...);
621 +
622 +gchar **
623 +shell_utils_trivial_source_var_list (GFile *file,
624 + const gchar * const *var_names,
625 + GError **error);
626 #endif