gsettings-tool: warn if setting a value fails
[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 gsettings_writable (GSettings   *settings,
362                     const gchar *key,
363                     const gchar *value)
364 {
365   g_print ("%s\n",
366            g_settings_is_writable (settings, key) ?
367            "true" : "false");
368 }
369
370 static void
371 value_changed (GSettings   *settings,
372                const gchar *key,
373                gpointer     user_data)
374 {
375   GVariant *value;
376   gchar *printed;
377
378   value = g_settings_get_value (settings, key);
379   printed = g_variant_print (value, TRUE);
380   g_print ("%s: %s\n", key, printed);
381   g_variant_unref (value);
382   g_free (printed);
383 }
384
385 static void
386 gsettings_monitor (GSettings   *settings,
387                    const gchar *key,
388                    const gchar *value)
389 {
390   if (key)
391     {
392       gchar *name;
393
394       name = g_strdup_printf ("changed::%s", key);
395       g_signal_connect (settings, name, G_CALLBACK (value_changed), NULL);
396     }
397   else
398     g_signal_connect (settings, "changed", G_CALLBACK (value_changed), NULL);
399
400   g_main_loop_run (g_main_loop_new (NULL, FALSE));
401 }
402
403 static void
404 gsettings_set (GSettings   *settings,
405                const gchar *key,
406                const gchar *value)
407 {
408   const GVariantType *type;
409   GError *error = NULL;
410   GVariant *existing;
411   GVariant *new;
412   GVariant *stored;
413   gchar *freeme = NULL;
414
415   existing = g_settings_get_value (settings, key);
416   type = g_variant_get_type (existing);
417
418   new = g_variant_parse (type, value, NULL, NULL, &error);
419
420   /* A common error is to specify a string with single quotes
421    * (or use completion for that), and forget that the shell
422    * will eat one level of quoting, resulting in 'unknown keyword'
423    * error from the gvariant parser.
424    * To handle this case, try to parse again with an extra level
425    * of quotes.
426    */
427   if (new == NULL &&
428       g_error_matches (error, G_VARIANT_PARSE_ERROR,
429                        G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD))
430     {
431       value = freeme = g_strdup_printf ("\"%s\"", value);
432       new = g_variant_parse (type, value, NULL, NULL, NULL);
433       if (new != NULL)
434         g_clear_error (&error);
435     }
436
437   if (new == NULL)
438     {
439       g_printerr ("%s\n", error->message);
440       exit (1);
441     }
442
443   if (!g_settings_range_check (settings, key, new))
444     {
445       g_printerr (_("The provided value is outside of the valid range\n"));
446       exit (1);
447     }
448
449   g_settings_set_value (settings, key, new);
450   g_settings_sync ();
451
452   stored = g_settings_get_value (settings, key);
453   if (g_variant_equal (stored, existing))
454     {
455       g_printerr (_("Failed to set value\n"));
456       exit (1);
457     }
458
459   g_variant_unref (stored);
460   g_variant_unref (existing);
461   g_variant_unref (new);
462
463   g_free (freeme);
464 }
465
466 static int
467 gsettings_help (gboolean     requested,
468                 const gchar *command)
469 {
470   const gchar *description;
471   const gchar *synopsis;
472   GString *string;
473
474   string = g_string_new (NULL);
475
476   if (command == NULL)
477     ;
478
479   else if (strcmp (command, "help") == 0)
480     {
481       description = _("Print help");
482       synopsis = "[COMMAND]";
483     }
484
485   else if (strcmp (command, "list-schemas") == 0)
486     {
487       description = _("List the installed (non-relocatable) schemas");
488       synopsis = "";
489     }
490
491   else if (strcmp (command, "list-relocatable-schemas") == 0)
492     {
493       description = _("List the installed relocatable schemas");
494       synopsis = "";
495     }
496
497   else if (strcmp (command, "list-keys") == 0)
498     {
499       description = _("List the keys in SCHEMA");
500       synopsis = N_("SCHEMA[:PATH]");
501     }
502
503   else if (strcmp (command, "list-children") == 0)
504     {
505       description = _("List the children of SCHEMA");
506       synopsis = N_("SCHEMA[:PATH]");
507     }
508
509   else if (strcmp (command, "list-recursively") == 0)
510     {
511       description = _("List keys and values, recursively\n"
512                       "If no SCHEMA is given, list all keys\n");
513       synopsis = N_("[SCHEMA[:PATH]]");
514     }
515
516   else if (strcmp (command, "get") == 0)
517     {
518       description = _("Get the value of KEY");
519       synopsis = N_("SCHEMA[:PATH] KEY");
520     }
521
522   else if (strcmp (command, "range") == 0)
523     {
524       description = _("Query the range of valid values for KEY");
525       synopsis = N_("SCHEMA[:PATH] KEY");
526     }
527
528   else if (strcmp (command, "set") == 0)
529     {
530       description = _("Set the value of KEY to VALUE");
531       synopsis = N_("SCHEMA[:PATH] KEY VALUE");
532     }
533
534   else if (strcmp (command, "reset") == 0)
535     {
536       description = _("Reset KEY to its default value");
537       synopsis = N_("SCHEMA[:PATH] KEY");
538     }
539
540   else if (strcmp (command, "writable") == 0)
541     {
542       description = _("Check if KEY is writable");
543       synopsis = N_("SCHEMA[:PATH] KEY");
544     }
545
546   else if (strcmp (command, "monitor") == 0)
547     {
548       description = _("Monitor KEY for changes.\n"
549                     "If no KEY is specified, monitor all keys in SCHEMA.\n"
550                     "Use ^C to stop monitoring.\n");
551       synopsis = N_("SCHEMA[:PATH] [KEY]");
552     }
553   else
554     {
555       g_string_printf (string, _("Unknown command %s\n\n"), command);
556       requested = FALSE;
557       command = NULL;
558     }
559
560   if (command == NULL)
561     {
562       g_string_append (string,
563       _("Usage:\n"
564         "  gsettings COMMAND [ARGS...]\n"
565         "\n"
566         "Commands:\n"
567         "  help                      Show this information\n"
568         "  list-schemas              List installed schemas\n"
569         "  list-relocatable-schemas  List relocatable schemas\n"
570         "  list-keys                 List keys in a schema\n"
571         "  list-children             List children of a schema\n"
572         "  list-recursively          List keys and values, recursively\n"
573         "  range                     Queries the range of a key\n"
574         "  get                       Get the value of a key\n"
575         "  set                       Set the value of a key\n"
576         "  reset                     Reset the value of a key\n"
577         "  writable                  Check if a key is writable\n"
578         "  monitor                   Watch for changes\n"
579         "\n"
580         "Use 'gsettings help COMMAND' to get detailed help.\n\n"));
581     }
582   else
583     {
584       g_string_append_printf (string, _("Usage:\n  gsettings %s %s\n\n%s\n\n"),
585                               command, synopsis[0] ? _(synopsis) : "", description);
586
587       if (synopsis[0])
588         {
589           g_string_append (string, _("Arguments:\n"));
590
591           if (strstr (synopsis, "[COMMAND]"))
592             g_string_append (string,
593                            _("  COMMAND   The (optional) command to explain\n"));
594
595           else if (strstr (synopsis, "SCHEMA"))
596             g_string_append (string,
597                            _("  SCHEMA    The name of the schema\n"
598                              "  PATH      The path, for relocatable schemas\n"));
599
600           if (strstr (synopsis, "[KEY]"))
601             g_string_append (string,
602                            _("  KEY       The (optional) key within the schema\n"));
603
604           else if (strstr (synopsis, "KEY"))
605             g_string_append (string,
606                            _("  KEY       The key within the schema\n"));
607
608           if (strstr (synopsis, "VALUE"))
609             g_string_append (string,
610                            _("  VALUE     The value to set\n"));
611
612           g_string_append (string, "\n");
613         }
614     }
615
616   if (requested)
617     g_print ("%s", string->str);
618   else
619     g_printerr ("%s\n", string->str);
620
621   g_string_free (string, TRUE);
622
623   return requested ? 0 : 1;
624 }
625
626
627 int
628 main (int argc, char **argv)
629 {
630   void (* function) (GSettings *, const gchar *, const gchar *);
631   GSettings *settings;
632   const gchar *key;
633
634   setlocale (LC_ALL, "");
635   textdomain (GETTEXT_PACKAGE);
636
637 #ifdef G_OS_WIN32
638   gchar *tmp = _glib_get_locale_dir ();
639   bindtextdomain (GETTEXT_PACKAGE, tmp);
640   g_free (tmp);
641 #else
642   bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
643 #endif
644
645 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
646   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
647 #endif
648
649   if (argc < 2)
650     return gsettings_help (FALSE, NULL);
651
652   else if (strcmp (argv[1], "help") == 0)
653     return gsettings_help (TRUE, argv[2]);
654
655   else if (argc == 2 && strcmp (argv[1], "list-schemas") == 0)
656     function = gsettings_list_schemas;
657
658   else if (argc == 2 && strcmp (argv[1], "list-relocatable-schemas") == 0)
659     function = gsettings_list_relocatable_schemas;
660
661   else if (argc == 3 && strcmp (argv[1], "list-keys") == 0)
662     function = gsettings_list_keys;
663
664   else if (argc == 3 && strcmp (argv[1], "list-children") == 0)
665     function = gsettings_list_children;
666
667   else if ((argc == 2 || argc == 3) && strcmp (argv[1], "list-recursively") == 0)
668     function = gsettings_list_recursively;
669
670   else if (argc == 4 && strcmp (argv[1], "range") == 0)
671     function = gsettings_range;
672
673   else if (argc == 4 && strcmp (argv[1], "get") == 0)
674     function = gsettings_get;
675
676   else if (argc == 5 && strcmp (argv[1], "set") == 0)
677     function = gsettings_set;
678
679   else if (argc == 4 && strcmp (argv[1], "reset") == 0)
680     function = gsettings_reset;
681
682   else if (argc == 4 && strcmp (argv[1], "writable") == 0)
683     function = gsettings_writable;
684
685   else if ((argc == 3 || argc == 4) && strcmp (argv[1], "monitor") == 0)
686     function = gsettings_monitor;
687
688   else
689     return gsettings_help (FALSE, argv[1]);
690
691   g_type_init ();
692
693   if (argc > 2)
694     {
695       gchar **parts;
696
697       if (argv[2][0] == '\0')
698         {
699           g_printerr (_("Empty schema name given\n"));
700           return 1;
701         }
702
703       parts = g_strsplit (argv[2], ":", 2);
704
705       if (parts[1])
706         {
707           if (!check_relocatable_schema (parts[0]) || !check_path (parts[1]))
708             return 1;
709
710           settings = g_settings_new_with_path (parts[0], parts[1]);
711         }
712       else
713         {
714           if (!check_schema (parts[0]))
715             return 1;
716
717           settings = g_settings_new (parts[0]);
718         }
719
720       g_strfreev (parts);
721     }
722   else
723     settings = NULL;
724
725   if (argc > 3)
726     {
727       if (!check_key (settings, argv[3]))
728         return 1;
729
730       key = argv[3];
731     }
732   else
733     key = NULL;
734
735   (* function) (settings, key, argc > 4 ? argv[4] : NULL);
736
737   if (settings != NULL)
738     g_object_unref (settings);
739
740   return 0;
741 }