04a1954f59905a322015946b192515e70bf5394d
[platform/upstream/glib.git] / gio / gsettings-tool.c
1 /*
2  * Copyright © 2010 Codethink Limited
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the licence, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  *
19  * Author: Ryan Lortie <desrt@desrt.ca>
20  */
21
22 #include "config.h"
23
24 #include <gio/gio.h>
25 #include <gi18n.h>
26 #include <locale.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 static gboolean
31 contained (const gchar * const *items,
32            const gchar         *item)
33 {
34   while (*items)
35     if (strcmp (*items++, item) == 0)
36       return TRUE;
37
38   return FALSE;
39 }
40
41 static gboolean
42 is_schema (const gchar *schema)
43 {
44   return contained (g_settings_list_schemas (), schema);
45 }
46
47 static gboolean
48 is_relocatable_schema (const gchar *schema)
49 {
50   return contained (g_settings_list_relocatable_schemas (), schema);
51 }
52
53 static gboolean
54 check_relocatable_schema (const gchar *schema)
55 {
56   if (is_relocatable_schema (schema))
57     return TRUE;
58
59   if (is_schema (schema))
60     g_printerr (_("Schema '%s' is not relocatable "
61                   "(path must not be specified)\n"),
62                 schema);
63
64   else
65     g_printerr (_("No such schema '%s'\n"), schema);
66
67   return FALSE;
68 }
69
70 static gboolean
71 check_schema (const gchar *schema)
72 {
73   if (is_schema (schema))
74     return TRUE;
75
76   if (is_relocatable_schema (schema))
77     g_printerr (_("Schema '%s' is relocatable "
78                   "(path must be specified)\n"),
79                 schema);
80
81   else
82     g_printerr (_("No such schema '%s'\n"), schema);
83
84   return FALSE;
85 }
86
87 static gboolean
88 check_path (const gchar *path)
89 {
90   if (path[0] == '\0')
91     {
92       g_printerr (_("Empty path given.\n"));
93       return FALSE;
94     }
95
96   if (path[0] != '/')
97     {
98       g_printerr (_("Path must begin with a slash (/)\n"));
99       return FALSE;
100     }
101
102   if (!g_str_has_suffix (path, "/"))
103     {
104       g_printerr (_("Path must end with a slash (/)\n"));
105       return FALSE;
106     }
107
108   if (strstr (path, "//"))
109     {
110       g_printerr (_("Path must not contain two adjacent slashes (//)\n"));
111       return FALSE;
112     }
113
114   return TRUE;
115 }
116
117 static gboolean
118 check_key (GSettings   *settings,
119            const gchar *key)
120 {
121   gboolean good;
122   gchar **keys;
123
124   keys = g_settings_list_keys (settings);
125   good = contained ((const gchar **) keys, key);
126   g_strfreev (keys);
127
128   if (good)
129     return TRUE;
130
131   g_printerr (_("No such key '%s'\n"), key);
132
133   return FALSE;
134 }
135
136 static void
137 output_list (const gchar * const *list)
138 {
139   gint i;
140
141   for (i = 0; list[i]; i++)
142     g_print ("%s\n", list[i]);
143 }
144
145 static void
146 gsettings_list_schemas (GSettings   *settings,
147                         const gchar *key,
148                         const gchar *value)
149 {
150   output_list (g_settings_list_schemas ());
151 }
152
153 static void
154 gsettings_list_relocatable_schemas (GSettings   *settings,
155                                     const gchar *key,
156                                     const gchar *value)
157 {
158   output_list (g_settings_list_relocatable_schemas ());
159 }
160
161 static void
162 gsettings_list_keys (GSettings   *settings,
163                      const gchar *key,
164                      const gchar *value)
165 {
166   gchar **keys;
167
168   keys = g_settings_list_keys (settings);
169   output_list ((const gchar **) keys);
170   g_strfreev (keys);
171 }
172
173 static void
174 gsettings_list_children (GSettings   *settings,
175                          const gchar *key,
176                          const gchar *value)
177 {
178   gchar **children;
179   gint max = 0;
180   gint i;
181
182   children = g_settings_list_children (settings);
183   for (i = 0; children[i]; i++)
184     if (strlen (children[i]) > max)
185       max = strlen (children[i]);
186
187   for (i = 0; children[i]; i++)
188     {
189       GSettings *child;
190       gchar *schema;
191       gchar *path;
192
193       child = g_settings_get_child (settings, children[i]);
194       g_object_get (child,
195                     "schema", &schema,
196                     "path", &path,
197                     NULL);
198
199       if (is_schema (schema))
200         g_print ("%-*s   %s\n", max, children[i], schema);
201       else
202         g_print ("%-*s   %s:%s\n", max, children[i], schema, path);
203
204       g_object_unref (child);
205       g_free (schema);
206       g_free (path);
207     }
208
209   g_strfreev (children);
210 }
211
212 static void
213 enumerate (GSettings *settings)
214 {
215   gchar **keys;
216   gchar *schema;
217   gint i;
218
219   g_object_get (settings, "schema", &schema, NULL);
220
221   keys = g_settings_list_keys (settings);
222   for (i = 0; keys[i]; i++)
223     {
224       GVariant *value;
225       gchar *printed;
226
227       value = g_settings_get_value (settings, keys[i]);
228       printed = g_variant_print (value, TRUE);
229       g_print ("%s %s %s\n", schema, keys[i], printed);
230       g_variant_unref (value);
231       g_free (printed);
232     }
233
234   g_free (schema);
235   g_strfreev (keys);
236 }
237
238 static void
239 gsettings_list_recursively (GSettings   *settings,
240                             const gchar *key,
241                             const gchar *value)
242 {
243   if (settings)
244     {
245       gchar **children;
246       gint i;
247
248       enumerate (settings);
249       children = g_settings_list_children (settings);
250       for (i = 0; children[i]; i++)
251         {
252           GSettings *child;
253           gchar *schema;
254
255           child = g_settings_get_child (settings, children[i]);
256           g_object_get (child, "schema", &schema, NULL);
257
258           if (is_schema (schema))
259             enumerate (child);
260
261           g_object_unref (child);
262           g_free (schema);
263         }
264
265       g_strfreev (children);
266     }
267   else
268     {
269       const gchar * const *schemas;
270       gint i;
271
272       schemas = g_settings_list_schemas ();
273
274       for (i = 0; schemas[i]; i++)
275         {
276           settings = g_settings_new (schemas[i]);
277           enumerate (settings);
278           g_object_unref (settings);
279         }
280     }
281 }
282
283 static void
284 gsettings_range (GSettings   *settings,
285                  const gchar *key,
286                  const gchar *value)
287 {
288   GVariant *range, *detail;
289   const gchar *type;
290
291   range = g_settings_get_range (settings, key);
292   g_variant_get (range, "(&sv)", &type, &detail);
293
294   if (strcmp (type, "type") == 0)
295     g_print ("type %s\n", g_variant_get_type_string (detail) + 1);
296
297   else if (strcmp (type, "range") == 0)
298     {
299       GVariant *min, *max;
300       gchar *smin, *smax;
301
302       g_variant_get (detail, "(**)", &min, &max);
303       smin = g_variant_print (min, FALSE);
304       smax = g_variant_print (max, FALSE);
305
306       g_print ("range %s %s %s\n",
307                g_variant_get_type_string (min), smin, smax);
308       g_variant_unref (min);
309       g_variant_unref (max);
310       g_free (smin);
311       g_free (smax);
312     }
313
314   else if (strcmp (type, "enum") == 0 || strcmp (type, "flags") == 0)
315     {
316       GVariantIter iter;
317       GVariant *item;
318
319       g_print ("%s\n", type);
320
321       g_variant_iter_init (&iter, detail);
322       while (g_variant_iter_loop (&iter, "*", &item))
323         {
324           gchar *printed;
325
326           printed = g_variant_print (item, FALSE);
327           g_print ("%s\n", printed);
328           g_free (printed);
329         }
330     }
331
332   g_variant_unref (detail);
333   g_variant_unref (range);
334 }
335
336 static void
337 gsettings_get (GSettings   *settings,
338                const gchar *key,
339                const gchar *value_)
340 {
341   GVariant *value;
342   gchar *printed;
343
344   value = g_settings_get_value (settings, key);
345   printed = g_variant_print (value, TRUE);
346   g_print ("%s\n", printed);
347   g_variant_unref (value);
348   g_free (printed);
349 }
350
351 static void
352 gsettings_reset (GSettings   *settings,
353                  const gchar *key,
354                  const gchar *value)
355 {
356   g_settings_reset (settings, key);
357   g_settings_sync ();
358 }
359
360 static void
361 reset_all_keys (GSettings   *settings)
362 {
363   gchar **keys;
364   gint i;
365
366   keys = g_settings_list_keys (settings);
367   for (i = 0; keys[i]; i++)
368     {
369       g_settings_reset (settings, keys[i]);
370     }
371
372   g_strfreev (keys);
373 }
374
375 static void
376 gsettings_reset_recursively (GSettings   *settings,
377                              const gchar *key,
378                              const gchar *value)
379 {
380   gchar **children;
381   gint i;
382
383   g_settings_delay (settings);
384
385   reset_all_keys (settings);
386   children = g_settings_list_children (settings);
387   for (i = 0; children[i]; i++)
388     {
389       GSettings *child;
390       gchar *schema;
391
392       child = g_settings_get_child (settings, children[i]);
393       g_object_get (child, "schema", &schema, NULL);
394
395       if (is_schema (schema))
396         reset_all_keys (child);
397
398       g_object_unref (child);
399       g_free (schema);
400     }
401
402   g_strfreev (children);
403
404   g_settings_apply (settings);
405   g_settings_sync ();
406 }
407
408 static void
409 gsettings_writable (GSettings   *settings,
410                     const gchar *key,
411                     const gchar *value)
412 {
413   g_print ("%s\n",
414            g_settings_is_writable (settings, key) ?
415            "true" : "false");
416 }
417
418 static void
419 value_changed (GSettings   *settings,
420                const gchar *key,
421                gpointer     user_data)
422 {
423   GVariant *value;
424   gchar *printed;
425
426   value = g_settings_get_value (settings, key);
427   printed = g_variant_print (value, TRUE);
428   g_print ("%s: %s\n", key, printed);
429   g_variant_unref (value);
430   g_free (printed);
431 }
432
433 static void
434 gsettings_monitor (GSettings   *settings,
435                    const gchar *key,
436                    const gchar *value)
437 {
438   if (key)
439     {
440       gchar *name;
441
442       name = g_strdup_printf ("changed::%s", key);
443       g_signal_connect (settings, name, G_CALLBACK (value_changed), NULL);
444     }
445   else
446     g_signal_connect (settings, "changed", G_CALLBACK (value_changed), NULL);
447
448   g_main_loop_run (g_main_loop_new (NULL, FALSE));
449 }
450
451 static void
452 gsettings_set (GSettings   *settings,
453                const gchar *key,
454                const gchar *value)
455 {
456   const GVariantType *type;
457   GError *error = NULL;
458   GVariant *existing;
459   GVariant *new;
460   gchar *freeme = NULL;
461
462   existing = g_settings_get_value (settings, key);
463   type = g_variant_get_type (existing);
464
465   new = g_variant_parse (type, value, NULL, NULL, &error);
466
467   /* If that didn't work and the type is string then we should assume
468    * that the user is just trying to set a string directly and forgot
469    * the quotes (or had them consumed by the shell).
470    *
471    * If the user started with a quote then we assume that some deeper
472    * problem is at play and we want the failure in that case.
473    *
474    * Consider:
475    *
476    *   gsettings set x.y.z key "'i don't expect this to work'"
477    *
478    * Note that we should not just add quotes and try parsing again, but
479    * rather assume that the user is providing us with a bare string.
480    * Assume we added single quotes, then consider this case:
481    *
482    *   gsettings set x.y.z key "i'd expect this to work"
483    *
484    * A similar example could be given for double quotes.
485    *
486    * Avoid that whole mess by just using g_variant_new_string().
487    */
488   if (new == NULL &&
489       g_variant_type_equal (type, G_VARIANT_TYPE_STRING) &&
490       value[0] != '\'' && value[0] != '"')
491     {
492       g_clear_error (&error);
493       new = g_variant_new_string (value);
494     }
495
496   if (new == NULL)
497     {
498       g_printerr ("%s\n", error->message);
499       exit (1);
500     }
501
502   if (!g_settings_range_check (settings, key, new))
503     {
504       g_printerr (_("The provided value is outside of the valid range\n"));
505       g_variant_unref (new);
506       exit (1);
507     }
508
509   g_settings_set_value (settings, key, new);
510   g_variant_unref (existing);
511   g_variant_unref (new);
512
513   g_settings_sync ();
514
515   g_free (freeme);
516 }
517
518 static int
519 gsettings_help (gboolean     requested,
520                 const gchar *command)
521 {
522   const gchar *description;
523   const gchar *synopsis;
524   GString *string;
525
526   string = g_string_new (NULL);
527
528   if (command == NULL)
529     ;
530
531   else if (strcmp (command, "help") == 0)
532     {
533       description = _("Print help");
534       synopsis = "[COMMAND]";
535     }
536
537   else if (strcmp (command, "list-schemas") == 0)
538     {
539       description = _("List the installed (non-relocatable) schemas");
540       synopsis = "";
541     }
542
543   else if (strcmp (command, "list-relocatable-schemas") == 0)
544     {
545       description = _("List the installed relocatable schemas");
546       synopsis = "";
547     }
548
549   else if (strcmp (command, "list-keys") == 0)
550     {
551       description = _("List the keys in SCHEMA");
552       synopsis = N_("SCHEMA[:PATH]");
553     }
554
555   else if (strcmp (command, "list-children") == 0)
556     {
557       description = _("List the children of SCHEMA");
558       synopsis = N_("SCHEMA[:PATH]");
559     }
560
561   else if (strcmp (command, "list-recursively") == 0)
562     {
563       description = _("List keys and values, recursively\n"
564                       "If no SCHEMA is given, list all keys\n");
565       synopsis = N_("[SCHEMA[:PATH]]");
566     }
567
568   else if (strcmp (command, "get") == 0)
569     {
570       description = _("Get the value of KEY");
571       synopsis = N_("SCHEMA[:PATH] KEY");
572     }
573
574   else if (strcmp (command, "range") == 0)
575     {
576       description = _("Query the range of valid values for KEY");
577       synopsis = N_("SCHEMA[:PATH] KEY");
578     }
579
580   else if (strcmp (command, "set") == 0)
581     {
582       description = _("Set the value of KEY to VALUE");
583       synopsis = N_("SCHEMA[:PATH] KEY VALUE");
584     }
585
586   else if (strcmp (command, "reset") == 0)
587     {
588       description = _("Reset KEY to its default value");
589       synopsis = N_("SCHEMA[:PATH] KEY");
590     }
591
592   else if (strcmp (command, "reset-recursively") == 0)
593     {
594       description = _("Reset all keys in SCHEMA to their defaults");
595       synopsis = N_("SCHEMA[:PATH]");
596     }
597
598   else if (strcmp (command, "writable") == 0)
599     {
600       description = _("Check if KEY is writable");
601       synopsis = N_("SCHEMA[:PATH] KEY");
602     }
603
604   else if (strcmp (command, "monitor") == 0)
605     {
606       description = _("Monitor KEY for changes.\n"
607                     "If no KEY is specified, monitor all keys in SCHEMA.\n"
608                     "Use ^C to stop monitoring.\n");
609       synopsis = N_("SCHEMA[:PATH] [KEY]");
610     }
611   else
612     {
613       g_string_printf (string, _("Unknown command %s\n\n"), command);
614       requested = FALSE;
615       command = NULL;
616     }
617
618   if (command == NULL)
619     {
620       g_string_append (string,
621       _("Usage:\n"
622         "  gsettings COMMAND [ARGS...]\n"
623         "\n"
624         "Commands:\n"
625         "  help                      Show this information\n"
626         "  list-schemas              List installed schemas\n"
627         "  list-relocatable-schemas  List relocatable schemas\n"
628         "  list-keys                 List keys in a schema\n"
629         "  list-children             List children of a schema\n"
630         "  list-recursively          List keys and values, recursively\n"
631         "  range                     Queries the range of a key\n"
632         "  get                       Get the value of a key\n"
633         "  set                       Set the value of a key\n"
634         "  reset                     Reset the value of a key\n"
635         "  reset-recursively         Reset all values in a given schema\n"
636         "  writable                  Check if a key is writable\n"
637         "  monitor                   Watch for changes\n"
638         "\n"
639         "Use 'gsettings help COMMAND' to get detailed help.\n\n"));
640     }
641   else
642     {
643       g_string_append_printf (string, _("Usage:\n  gsettings %s %s\n\n%s\n\n"),
644                               command, synopsis[0] ? _(synopsis) : "", description);
645
646       if (synopsis[0])
647         {
648           g_string_append (string, _("Arguments:\n"));
649
650           if (strstr (synopsis, "[COMMAND]"))
651             g_string_append (string,
652                            _("  COMMAND   The (optional) command to explain\n"));
653
654           else if (strstr (synopsis, "SCHEMA"))
655             g_string_append (string,
656                            _("  SCHEMA    The name of the schema\n"
657                              "  PATH      The path, for relocatable schemas\n"));
658
659           if (strstr (synopsis, "[KEY]"))
660             g_string_append (string,
661                            _("  KEY       The (optional) key within the schema\n"));
662
663           else if (strstr (synopsis, "KEY"))
664             g_string_append (string,
665                            _("  KEY       The key within the schema\n"));
666
667           if (strstr (synopsis, "VALUE"))
668             g_string_append (string,
669                            _("  VALUE     The value to set\n"));
670
671           g_string_append (string, "\n");
672         }
673     }
674
675   if (requested)
676     g_print ("%s", string->str);
677   else
678     g_printerr ("%s\n", string->str);
679
680   g_string_free (string, TRUE);
681
682   return requested ? 0 : 1;
683 }
684
685
686 int
687 main (int argc, char **argv)
688 {
689   void (* function) (GSettings *, const gchar *, const gchar *);
690   GSettings *settings;
691   const gchar *key;
692
693   setlocale (LC_ALL, "");
694   textdomain (GETTEXT_PACKAGE);
695
696 #ifdef G_OS_WIN32
697   gchar *tmp = _glib_get_locale_dir ();
698   bindtextdomain (GETTEXT_PACKAGE, tmp);
699   g_free (tmp);
700 #else
701   bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
702 #endif
703
704 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
705   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
706 #endif
707
708   if (argc < 2)
709     return gsettings_help (FALSE, NULL);
710
711   else if (strcmp (argv[1], "help") == 0)
712     return gsettings_help (TRUE, argv[2]);
713
714   else if (argc == 2 && strcmp (argv[1], "list-schemas") == 0)
715     function = gsettings_list_schemas;
716
717   else if (argc == 2 && strcmp (argv[1], "list-relocatable-schemas") == 0)
718     function = gsettings_list_relocatable_schemas;
719
720   else if (argc == 3 && strcmp (argv[1], "list-keys") == 0)
721     function = gsettings_list_keys;
722
723   else if (argc == 3 && strcmp (argv[1], "list-children") == 0)
724     function = gsettings_list_children;
725
726   else if ((argc == 2 || argc == 3) && strcmp (argv[1], "list-recursively") == 0)
727     function = gsettings_list_recursively;
728
729   else if (argc == 4 && strcmp (argv[1], "range") == 0)
730     function = gsettings_range;
731
732   else if (argc == 4 && strcmp (argv[1], "get") == 0)
733     function = gsettings_get;
734
735   else if (argc == 5 && strcmp (argv[1], "set") == 0)
736     function = gsettings_set;
737
738   else if (argc == 4 && strcmp (argv[1], "reset") == 0)
739     function = gsettings_reset;
740
741   else if (argc == 3 && strcmp (argv[1], "reset-recursively") == 0)
742     function = gsettings_reset_recursively;
743
744   else if (argc == 4 && strcmp (argv[1], "writable") == 0)
745     function = gsettings_writable;
746
747   else if ((argc == 3 || argc == 4) && strcmp (argv[1], "monitor") == 0)
748     function = gsettings_monitor;
749
750   else
751     return gsettings_help (FALSE, argv[1]);
752
753   g_type_init ();
754
755   if (argc > 2)
756     {
757       gchar **parts;
758
759       if (argv[2][0] == '\0')
760         {
761           g_printerr (_("Empty schema name given\n"));
762           return 1;
763         }
764
765       parts = g_strsplit (argv[2], ":", 2);
766
767       if (parts[1])
768         {
769           if (!check_relocatable_schema (parts[0]) || !check_path (parts[1]))
770             return 1;
771
772           settings = g_settings_new_with_path (parts[0], parts[1]);
773         }
774       else
775         {
776           if (!check_schema (parts[0]))
777             return 1;
778
779           settings = g_settings_new (parts[0]);
780         }
781
782       g_strfreev (parts);
783     }
784   else
785     settings = NULL;
786
787   if (argc > 3)
788     {
789       if (!check_key (settings, argv[3]))
790         return 1;
791
792       key = argv[3];
793     }
794   else
795     key = NULL;
796
797   (* function) (settings, key, argc > 4 ? argv[4] : NULL);
798
799   if (settings != NULL)
800     g_object_unref (settings);
801
802   return 0;
803 }