From c9dded413c4cd7d5bb0732dcd3a681008c54a83f Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Thu, 14 Apr 2011 14:00:29 -0700 Subject: [PATCH] corewatcher-config: add command line tool for editing the config file Simple tool using the glib keyfile support to get and set key/value pairs. Intended to be used to script configuration changes, such as. # corewatcher-config --set allow-submit=yes Default config file changes add a required group header for glib and whitespace changes to reflect what happens when the glib keyfile routines read and then write back the file. Signed-off-by: Chris Leech --- Makefile | 11 ++- configfile.c | 8 +- corewatcher-config.c | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++ corewatcher.conf | 15 ++-- 4 files changed, 245 insertions(+), 13 deletions(-) create mode 100644 corewatcher-config.c diff --git a/Makefile b/Makefile index 3242094..319e1e3 100644 --- a/Makefile +++ b/Makefile @@ -19,12 +19,13 @@ MY_CFLAGS := `pkg-config --cflags libnotify gtk+-2.0` # and that makes the applet load faster and use less memory. # LDF_A := -Wl,--as-needed `pkg-config --libs libnotify gtk+-2.0` +LDF_C := -Wl,--as-needed `pkg-config --libs glib-2.0` LDF_D := -Wl,--as-needed `pkg-config --libs glib-2.0 dbus-glib-1` `curl-config --libs` -Wl,"-z relro" -Wl,"-z now" -all: corewatcher corewatcher-applet corewatcher.8.gz +all: corewatcher corewatcher-config corewatcher-applet corewatcher.8.gz @(cd po/ && $(MAKE) $@) -noui: corewatcher corewatcher.8.gz +noui: corewatcher corewatcher-config corewatcher.8.gz .c.o: $(CC) $(CFLAGS) $(MY_CFLAGS) -c -o $@ $< @@ -34,6 +35,9 @@ corewatcher: corewatcher.o submit.o coredump.o configfile.o find_file.o corewatc gcc corewatcher.o submit.o coredump.o configfile.o find_file.o $(LDF_D) -o corewatcher @(cd po/ && $(MAKE)) +corewatcher-config: corewatcher-config.o + gcc corewatcher-config.o $(LDF_C)-o corewatcher-config + corewatcher-applet: corewatcher-applet.o gcc corewatcher-applet.o $(LDF_A)-o corewatcher-applet @@ -41,7 +45,7 @@ corewatcher.8.gz: corewatcher.8 gzip -9 -c $< > $@ clean: - rm -f *~ *.o *.ko DEADJOE corewatcher corewatcher-applet *.out */*~ corewatcher.8.gz + rm -f *~ *.o *.ko DEADJOE corewatcher corewatcher-config corewatcher-applet *.out */*~ corewatcher.8.gz @(cd po/ && $(MAKE) $@) @@ -62,6 +66,7 @@ install-system: corewatcher.8.gz install-corewatcher: corewatcher -mkdir -p $(DESTDIR)$(SBINDIR) install -m 0755 corewatcher $(DESTDIR)$(SBINDIR)/ + install -m 0755 corewatcher-config $(DESTDIR)$(SBINDIR)/ install-applet: corewatcher-applet -mkdir -p $(DESTDIR)$(BINDIR) diff --git a/configfile.c b/configfile.c index 958a915..fca0c47 100644 --- a/configfile.c +++ b/configfile.c @@ -68,7 +68,7 @@ void read_config_file(char *filename) n = strchr(line, '\n'); if (n) *n = 0; - c = strstr(line, "allow-submit "); + c = strstr(line, "allow-submit"); if (c) { c += 13; if (strstr(c, "yes")) @@ -76,18 +76,18 @@ void read_config_file(char *filename) if (strstr(c, "ask")) opted_in = 1; } - c = strstr(line, "allow-pass-on "); + c = strstr(line, "allow-pass-on"); if (c) { c += 14; if (strstr(c, "yes")) allow_distro_to_pass_on = 1; } - c = strstr(line, "unlink "); + c = strstr(line, "unlink"); if (c) { if (strstr(c, "yes")) do_unlink = 1; } - c = strstr(line, "submit-url "); + c = strstr(line, "submit-url"); if (c && url_count <= MAX_URLS) { c += 11; c = strstr(c, "http:"); diff --git a/corewatcher-config.c b/corewatcher-config.c new file mode 100644 index 0000000..51de997 --- /dev/null +++ b/corewatcher-config.c @@ -0,0 +1,224 @@ +#include +#include + +#define DEFAULT_FILE "/etc/corewatcher.conf" +#define DEFAULT_GROUP "corewatcher" + +int parse_arg(gchar *arg, gchar **group, gchar **key, gchar **value) +{ + gchar **group_key_value = NULL; + gchar **group_key = NULL; + + if (!arg) + goto err; + group_key_value = g_strsplit(arg, "=", -1); + if (!group_key_value) + goto err; + switch (g_strv_length(group_key_value)) { + case 2: + *value = g_strdup(group_key_value[1]); + /* intentional fall through */ + case 1: + group_key = g_strsplit(group_key_value[0], ".", -1); + if (!group_key) + goto err; + switch (g_strv_length(group_key)) { + case 1: + *key = g_strdup(group_key[0]); + break; + case 2: + *group = g_strdup(group_key[0]); + *key = g_strdup(group_key[1]); + break; + default: + goto err; + } + break; + default: + goto err; + } + g_strfreev(group_key); + g_strfreev(group_key_value); + return 0; +err: + g_free(*group); *group = NULL; + g_free(*key); *key = NULL; + g_free(*value); *value = NULL; + g_strfreev(group_key); + g_strfreev(group_key_value); + return -1; +} + +int do_set(GKeyFile *keyfile, gchar *arg) +{ + gchar *group = NULL; + gchar *key = NULL; + gchar *value = NULL; + int ret = 0; + + parse_arg(arg, &group, &key, &value); + if (!key) { + ret = -1; + goto out; + } + if (!group) + group = g_strdup(DEFAULT_GROUP); + if (!value) { + fprintf(stderr, "missing value in set command\n"); + ret = -1; + goto out; + } + g_key_file_set_value(keyfile, group, key, value); +out: + g_free(group); + g_free(key); + g_free(value); + return ret; +} + +int do_get(GKeyFile *keyfile, gchar *arg) +{ + GError *error = NULL; + gchar *group = NULL; + gchar *key = NULL; + gchar *value = NULL; + int ret = 0; + + parse_arg(arg, &group, &key, &value); + if (!key) { + ret = -1; + goto out; + } + if (!group) + group = g_strdup(DEFAULT_GROUP); + if (value) { + fprintf(stderr, "ingoring value (%s) in get command\n", value); + g_free(value); + } + value = g_key_file_get_value(keyfile, group, key, &error); + if (error) { + fprintf(stderr, "%s\n", error->message); + g_clear_error(&error); + goto out; + } + printf("%s\n", value); +out: + g_free(group); + g_free(key); + g_free(value); + return ret; +} + +int do_get_all(GKeyFile *keyfile) +{ + gchar *group = NULL; + gchar *key = NULL; + gchar *value = NULL; + gchar **groups; + gchar **keys; + gsize group_count; + gsize key_count; + gsize i, j; + + groups = g_key_file_get_groups(keyfile, &group_count); + for (i = 0; i < group_count; i++) { + group = groups[i]; + keys = g_key_file_get_keys(keyfile, group, &key_count, NULL); + for (j = 0; j < key_count; j++) { + key = keys[j]; + value = g_key_file_get_value(keyfile, group, key, NULL); + printf("%s.%s=%s\n", group, key, value); + g_free(value); + } + g_strfreev(keys); + } + g_strfreev(groups); + return 0; +} + +#define CMD_SET (1<<0) +#define CMD_GET (1<<1) +#define CMD_GET_ALL (1<<2) + +#define HAS_MULTIPLE_BITS(i) ((i) & ((i) -1)) + +/* global settings from command line argument parsing */ +struct { + gint cmd; + gchar *file; + gchar *arg; +} settings = { 0, DEFAULT_FILE, NULL }; + +#define __unused __attribute__ ((__unused__)) + +gboolean set_cmd_option(const gchar *option_name, const gchar *value, gpointer __unused data, GError __unused **Error) +{ + if (!g_strcmp0(option_name, "--set")) { + settings.cmd |= CMD_SET; + settings.arg = g_strdup(value); + } + else if (!g_strcmp0(option_name, "--get")) { + settings.cmd |= CMD_GET; + settings.arg = g_strdup(value); + } + else if (!g_strcmp0(option_name, "--get-all")) { + settings.cmd |= CMD_GET_ALL; + } + return TRUE; +} + +static GOptionEntry entries[] = { + { "file", 'f', 0, G_OPTION_ARG_FILENAME, &settings.file, "file", NULL }, + { "set", '\0', 0, G_OPTION_ARG_CALLBACK, &set_cmd_option, "set", NULL }, + { "get", '\0', 0, G_OPTION_ARG_CALLBACK, &set_cmd_option, "get", NULL }, + { "get-all", '\0', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, &set_cmd_option, "get-all", NULL }, + { NULL, 0, 0, 0, NULL, NULL, NULL } +}; + +int main(int argc, char **argv) +{ + GError *error = NULL; + GOptionContext *context; + GKeyFile *keyfile; + GKeyFileFlags flags; + int ret = 0; + + context = g_option_context_new(""); + g_option_context_add_main_entries(context, entries, NULL); + if (!g_option_context_parse(context, &argc, &argv, &error)) { + fprintf(stderr, "%s\n", error->message); + return -1; + } + if (!settings.cmd) { + fprintf(stderr, "%s", g_option_context_get_help(context, TRUE, NULL)); + return -1; + } + if (HAS_MULTIPLE_BITS(settings.cmd)) { + fprintf(stderr, "only one command allowed at a time\n"); + fprintf(stderr, "%s", g_option_context_get_help(context, TRUE, NULL)); + return -1; + } + + keyfile = g_key_file_new(); + flags = G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS; + if (!g_key_file_load_from_file (keyfile, settings.file, flags, &error)) { + fprintf(stderr, "%s\n", error->message); + return -1; + } + switch(settings.cmd) { + case CMD_SET: + ret = do_set(keyfile, settings.arg); + g_file_set_contents(settings.file, g_key_file_to_data(keyfile, NULL, NULL), -1, NULL); + break; + case CMD_GET: + ret = do_get(keyfile, settings.arg); + break; + case CMD_GET_ALL: + ret = do_get_all(keyfile); + break; + } + g_key_file_free(keyfile); + + return ret; +} + diff --git a/corewatcher.conf b/corewatcher.conf index 00e726d..d5c5e4e 100644 --- a/corewatcher.conf +++ b/corewatcher.conf @@ -2,6 +2,8 @@ # Configuration file for the corewatcher.org crash collector # +[corewatcher] + # # Set the following variable to "yes" if you want to automatically # submit your bactraces to the database for use by your distribution or the @@ -19,19 +21,19 @@ # # Default is "ask" which uses a UI application t ask the user for permission # -allow-submit = ask +allow-submit=ask # # Set the following variable to "yes" if you want to allow your # Linux distribution vendor to pass the backtraces on to the central corewatcher.org # database as used by the MeeGo developers # -allow-pass-on = yes +allow-pass-on=yes # # Delete the coredumps after processing # -unlink = no +unlink=no # # URL for submitting the backtraces @@ -41,16 +43,17 @@ unlink = no # submit-url = http://url2.com/submitbug.php # -submit-url = http://crashdb.meego.com/submitbug.php +submit-url=http://crashdb.meego.com/submitbug.php # # Location for the MeeGo build release file # -release-info = /etc/meego-release +release-info=/etc/meego-release # # Location to store meego coredumps after they are processed # -core-folder = /tmp/corewatcher/ \ No newline at end of file +core-folder=/tmp/corewatcher/ + -- 2.7.4