summaryrefslogtreecommitdiff
path: root/gio/gio-tool-monitor.c
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2015-05-25 13:29:02 -0400
committerMatthias Clasen <mclasen@redhat.com>2016-07-01 16:01:34 -0400
commit9edba4e49cf84116903ca8a7c29080e7dca56607 (patch)
treed2194560208374cf5688738440903d912bce5e41 /gio/gio-tool-monitor.c
parent669a0f72a1b67dc9e3262c3a5ccf29c4aed98028 (diff)
downloadglib-9edba4e49cf84116903ca8a7c29080e7dca56607.tar.gz
Add a new gio commandline tool
This command collects the various commandline utilities that are currently shipped in gvfs, and unifies them under a single, command-style binary. The tools just use GIO APIs, so it makes sense for them to live here.
Diffstat (limited to 'gio/gio-tool-monitor.c')
-rw-r--r--gio/gio-tool-monitor.c278
1 files changed, 278 insertions, 0 deletions
diff --git a/gio/gio-tool-monitor.c b/gio/gio-tool-monitor.c
new file mode 100644
index 000000000..e137a5d16
--- /dev/null
+++ b/gio/gio-tool-monitor.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Matthias Clasen <mclasen@redhat.com>
+ */
+
+#include "config.h"
+
+#include <gio/gio.h>
+#include <gi18n.h>
+
+#include "gio-tool.h"
+
+static gchar **watch_dirs;
+static gchar **watch_files;
+static gchar **watch_direct;
+static gchar **watch_silent;
+static gchar **watch_default;
+static gboolean no_moves;
+static gboolean mounts;
+
+static const GOptionEntry entries[] = {
+ { "dir", 'd', 0, G_OPTION_ARG_FILENAME_ARRAY, &watch_dirs,
+ N_("Monitor a directory (default: depends on type)"), N_("LOCATION") },
+ { "file", 'f', 0, G_OPTION_ARG_FILENAME_ARRAY, &watch_files,
+ N_("Monitor a file (default: depends on type)"), N_("LOCATION") },
+ { "direct", 'D', 0, G_OPTION_ARG_FILENAME_ARRAY, &watch_direct,
+ N_("Monitor a file directly (notices changes made via hardlinks)"), N_("LOCATION") },
+ { "silent", 's', 0, G_OPTION_ARG_FILENAME_ARRAY, &watch_silent,
+ N_("Monitors a file directly, but doesn't report changes"), N_("LOCATION") },
+ { "no-moves", 'n', 0, G_OPTION_ARG_NONE, &no_moves,
+ N_("Report moves and renames as simple deleted/created events"), NULL },
+ { "mounts", 'm', 0, G_OPTION_ARG_NONE, &mounts,
+ N_("Watch for mount events"), NULL },
+ { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &watch_default },
+ { NULL }
+};
+
+static void
+watch_callback (GFileMonitor *monitor,
+ GFile *child,
+ GFile *other,
+ GFileMonitorEvent event_type,
+ gpointer user_data)
+{
+ gchar *child_str;
+ gchar *other_str;
+
+ g_assert (child);
+
+ if (g_file_is_native (child))
+ child_str = g_file_get_path (child);
+ else
+ child_str = g_file_get_uri (child);
+
+ if (other)
+ {
+ if (g_file_is_native (other))
+ other_str = g_file_get_path (other);
+ else
+ other_str = g_file_get_uri (other);
+ }
+ else
+ other_str = g_strdup ("(none)");
+
+ g_print ("%s: ", (gchar *) user_data);
+ switch (event_type)
+ {
+ case G_FILE_MONITOR_EVENT_CHANGED:
+ g_assert (!other);
+ g_print ("%s: changed", child_str);
+ break;
+ case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+ g_assert (!other);
+ g_print ("%s: changes done", child_str);
+ break;
+ case G_FILE_MONITOR_EVENT_DELETED:
+ g_assert (!other);
+ g_print ("%s: deleted", child_str);
+ break;
+ case G_FILE_MONITOR_EVENT_CREATED:
+ g_assert (!other);
+ g_print ("%s: created", child_str);
+ break;
+ case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
+ g_assert (!other);
+ g_print ("%s: attributes changed", child_str);
+ break;
+ case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
+ g_assert (!other);
+ g_print ("%s: pre-unmount", child_str);
+ break;
+ case G_FILE_MONITOR_EVENT_UNMOUNTED:
+ g_assert (!other);
+ g_print ("%s: unmounted", child_str);
+ break;
+ case G_FILE_MONITOR_EVENT_MOVED_IN:
+ g_print ("%s: moved in", child_str);
+ if (other)
+ g_print (" (from %s)", other_str);
+ break;
+ case G_FILE_MONITOR_EVENT_MOVED_OUT:
+ g_print ("%s: moved out", child_str);
+ if (other)
+ g_print (" (to %s)", other_str);
+ break;
+ case G_FILE_MONITOR_EVENT_RENAMED:
+ g_assert (other);
+ g_print ("%s: renamed to %s\n", child_str, other_str);
+ break;
+
+ case G_FILE_MONITOR_EVENT_MOVED:
+ default:
+ g_assert_not_reached ();
+ }
+
+ g_free (child_str);
+ g_free (other_str);
+ g_print ("\n");
+}
+
+typedef enum
+{
+ WATCH_DIR,
+ WATCH_FILE,
+ WATCH_AUTO
+} WatchType;
+
+static gboolean
+add_watch (const gchar *cmdline,
+ WatchType watch_type,
+ GFileMonitorFlags flags,
+ gboolean connect_handler)
+{
+ GFileMonitor *monitor = NULL;
+ GError *error = NULL;
+ GFile *file;
+
+ file = g_file_new_for_commandline_arg (cmdline);
+
+ if (watch_type == WATCH_AUTO)
+ {
+ GFileInfo *info;
+ guint32 type;
+
+ info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, &error);
+ if (!info)
+ goto err;
+
+ type = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE);
+ watch_type = (type == G_FILE_TYPE_DIRECTORY) ? WATCH_DIR : WATCH_FILE;
+ }
+
+ if (watch_type == WATCH_DIR)
+ monitor = g_file_monitor_directory (file, flags, NULL, &error);
+ else
+ monitor = g_file_monitor (file, flags, NULL, &error);
+
+ if (!monitor)
+ goto err;
+
+ if (connect_handler)
+ g_signal_connect (monitor, "changed", G_CALLBACK (watch_callback), g_strdup (cmdline));
+
+ monitor = NULL; /* leak */
+
+ return TRUE;
+
+err:
+ g_printerr ("error: %s: %s", cmdline, error->message);
+ g_error_free (error);
+
+ return FALSE;
+}
+
+int
+handle_monitor (int argc, gchar *argv[], gboolean do_help)
+{
+ GOptionContext *context;
+ gchar *param;
+ GError *error = NULL;
+ GFileMonitorFlags flags;
+ guint total = 0;
+ guint i;
+
+ g_set_prgname ("gio monitor");
+
+ /* Translators: commandline placeholder */
+ param = g_strdup_printf ("[%s...]", _("LOCATION"));
+ context = g_option_context_new (param);
+ g_free (param);
+ g_option_context_set_help_enabled (context, FALSE);
+ g_option_context_set_summary (context,
+ _("Monitor files or directories for changes."));
+ g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
+
+ if (do_help)
+ {
+ show_help (context, NULL);
+ return 0;
+ }
+
+ if (!g_option_context_parse (context, &argc, &argv, &error))
+ {
+ show_help (context, error->message);
+ g_error_free (error);
+ return 1;
+ }
+
+ g_option_context_free (context);
+
+ flags = (no_moves ? 0 : G_FILE_MONITOR_WATCH_MOVES) |
+ (mounts ? G_FILE_MONITOR_WATCH_MOUNTS : 0);
+
+ if (watch_dirs)
+ {
+ for (i = 0; watch_dirs[i]; i++)
+ if (!add_watch (watch_dirs[i], WATCH_DIR, flags, TRUE))
+ return 1;
+ total++;
+ }
+
+ if (watch_files)
+ {
+ for (i = 0; watch_files[i]; i++)
+ if (!add_watch (watch_files[i], WATCH_FILE, flags, TRUE))
+ return 1;
+ total++;
+ }
+
+ if (watch_direct)
+ {
+ for (i = 0; watch_direct[i]; i++)
+ if (!add_watch (watch_direct[i], WATCH_FILE, flags | G_FILE_MONITOR_WATCH_HARD_LINKS, TRUE))
+ return 1;
+ total++;
+ }
+
+ if (watch_silent)
+ {
+ for (i = 0; watch_silent[i]; i++)
+ if (!add_watch (watch_silent[i], WATCH_FILE, flags | G_FILE_MONITOR_WATCH_HARD_LINKS, FALSE))
+ return 1;
+ total++;
+ }
+
+ if (watch_default)
+ {
+ for (i = 0; watch_default[i]; i++)
+ if (!add_watch (watch_default[i], WATCH_AUTO, flags, TRUE))
+ return 1;
+ total++;
+ }
+
+ if (!total)
+ {
+ g_printerr ("gio: Must give at least one file to monitor\n");
+ return 1;
+ }
+
+ while (TRUE)
+ g_main_context_iteration (NULL, TRUE);
+
+ return 0;
+}