(root)/
glib-2.79.0/
gio/
gio-tool-monitor.c
       1  /*
       2   * Copyright 2015 Red Hat, Inc.
       3   *
       4   * SPDX-License-Identifier: LGPL-2.1-or-later
       5   *
       6   * This library is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   *
      11   * This library is distributed in the hope that it will be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14   * Lesser General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU Lesser General Public
      17   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18   *
      19   * Author: Matthias Clasen <mclasen@redhat.com>
      20   */
      21  
      22  #include "config.h"
      23  
      24  #include <gio/gio.h>
      25  #include <gi18n.h>
      26  
      27  #include "gio-tool.h"
      28  
      29  static gchar **watch_dirs;
      30  static gchar **watch_files;
      31  static gchar **watch_direct;
      32  static gchar **watch_silent;
      33  static gchar **watch_default;
      34  static gboolean no_moves;
      35  static gboolean mounts;
      36  
      37  static const GOptionEntry entries[] = {
      38    { "dir", 'd', 0, G_OPTION_ARG_FILENAME_ARRAY, &watch_dirs,
      39        N_("Monitor a directory (default: depends on type)"), N_("LOCATION") },
      40    { "file", 'f', 0, G_OPTION_ARG_FILENAME_ARRAY, &watch_files,
      41        N_("Monitor a file (default: depends on type)"), N_("LOCATION") },
      42    { "direct", 'D', 0, G_OPTION_ARG_FILENAME_ARRAY, &watch_direct,
      43        N_("Monitor a file directly (notices changes made via hardlinks)"), N_("LOCATION") },
      44    { "silent", 's', 0, G_OPTION_ARG_FILENAME_ARRAY, &watch_silent,
      45        N_("Monitors a file directly, but doesn’t report changes"), N_("LOCATION") },
      46    { "no-moves", 'n', 0, G_OPTION_ARG_NONE, &no_moves,
      47        N_("Report moves and renames as simple deleted/created events"), NULL },
      48    { "mounts", 'm', 0, G_OPTION_ARG_NONE, &mounts,
      49        N_("Watch for mount events"), NULL },
      50    { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &watch_default,
      51        NULL, NULL },
      52    G_OPTION_ENTRY_NULL
      53  };
      54  
      55  static void
      56  watch_callback (GFileMonitor      *monitor,
      57                  GFile             *child,
      58                  GFile             *other,
      59                  GFileMonitorEvent  event_type,
      60                  gpointer           user_data)
      61  {
      62    gchar *child_str;
      63    gchar *other_str;
      64  
      65    g_assert (child);
      66  
      67    if (g_file_is_native (child))
      68      child_str = g_file_get_path (child);
      69    else
      70      child_str = g_file_get_uri (child);
      71  
      72    if (other)
      73      {
      74        if (g_file_is_native (other))
      75          other_str = g_file_get_path (other);
      76        else
      77          other_str = g_file_get_uri (other);
      78      }
      79    else
      80      other_str = g_strdup ("(none)");
      81  
      82    g_print ("%s: ", (gchar *) user_data);
      83    switch (event_type)
      84      {
      85      case G_FILE_MONITOR_EVENT_CHANGED:
      86        g_assert (!other);
      87        g_print ("%s: changed", child_str);
      88        break;
      89      case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
      90        g_assert (!other);
      91        g_print ("%s: changes done", child_str);
      92        break;
      93      case G_FILE_MONITOR_EVENT_DELETED:
      94        g_assert (!other);
      95        g_print ("%s: deleted", child_str);
      96        break;
      97      case G_FILE_MONITOR_EVENT_CREATED:
      98        g_assert (!other);
      99        g_print ("%s: created", child_str);
     100        break;
     101      case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
     102        g_assert (!other);
     103        g_print ("%s: attributes changed", child_str);
     104        break;
     105      case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
     106        g_assert (!other);
     107        g_print ("%s: pre-unmount", child_str);
     108        break;
     109      case G_FILE_MONITOR_EVENT_UNMOUNTED:
     110        g_assert (!other);
     111        g_print ("%s: unmounted", child_str);
     112        break;
     113      case G_FILE_MONITOR_EVENT_MOVED_IN:
     114        g_print ("%s: moved in", child_str);
     115        if (other)
     116          g_print (" (from %s)", other_str);
     117        break;
     118      case G_FILE_MONITOR_EVENT_MOVED_OUT:
     119        g_print ("%s: moved out", child_str);
     120        if (other)
     121          g_print (" (to %s)", other_str);
     122        break;
     123      case G_FILE_MONITOR_EVENT_RENAMED:
     124        g_assert (other);
     125        g_print ("%s: renamed to %s\n", child_str, other_str);
     126        break;
     127  
     128      case G_FILE_MONITOR_EVENT_MOVED:
     129      default:
     130        g_assert_not_reached ();
     131      }
     132  
     133    g_free (child_str);
     134    g_free (other_str);
     135    g_print ("\n");
     136  }
     137  
     138  typedef enum
     139  {
     140    WATCH_DIR,
     141    WATCH_FILE,
     142    WATCH_AUTO
     143  } WatchType;
     144  
     145  static gboolean
     146  add_watch (const gchar       *cmdline,
     147             WatchType          watch_type,
     148             GFileMonitorFlags  flags,
     149             gboolean           connect_handler)
     150  {
     151    GFileMonitor *monitor = NULL;
     152    GError *error = NULL;
     153    GFile *file;
     154  
     155    file = g_file_new_for_commandline_arg (cmdline);
     156  
     157    if (watch_type == WATCH_AUTO)
     158      {
     159        GFileInfo *info;
     160        guint32 type;
     161  
     162        info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, &error);
     163        if (!info)
     164          goto err;
     165  
     166        type = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE);
     167        watch_type = (type == G_FILE_TYPE_DIRECTORY) ? WATCH_DIR : WATCH_FILE;
     168      }
     169  
     170    if (watch_type == WATCH_DIR)
     171      monitor = g_file_monitor_directory (file, flags, NULL, &error);
     172    else
     173      monitor = g_file_monitor (file, flags, NULL, &error);
     174  
     175    if (!monitor)
     176      goto err;
     177  
     178    if (connect_handler)
     179      g_signal_connect (monitor, "changed", G_CALLBACK (watch_callback), g_strdup (cmdline));
     180  
     181    monitor = NULL; /* leak */
     182    g_object_unref (file);
     183  
     184    return TRUE;
     185  
     186  err:
     187    print_file_error (file, error->message);
     188    g_error_free (error);
     189    g_object_unref (file);
     190  
     191    return FALSE;
     192  }
     193  
     194  int
     195  handle_monitor (int argc, gchar *argv[], gboolean do_help)
     196  {
     197    GOptionContext *context;
     198    gchar *param;
     199    GError *error = NULL;
     200    GFileMonitorFlags flags;
     201    guint i;
     202  
     203    g_set_prgname ("gio monitor");
     204  
     205    /* Translators: commandline placeholder */
     206    param = g_strdup_printf ("%s", _("LOCATION"));
     207    context = g_option_context_new (param);
     208    g_free (param);
     209    g_option_context_set_help_enabled (context, FALSE);
     210    g_option_context_set_summary (context,
     211      _("Monitor files or directories for changes."));
     212    g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
     213  
     214    if (do_help)
     215      {
     216        show_help (context, NULL);
     217        g_option_context_free (context);
     218        return 0;
     219      }
     220  
     221    if (!g_option_context_parse (context, &argc, &argv, &error))
     222      {
     223        show_help (context, error->message);
     224        g_error_free (error);
     225        g_option_context_free (context);
     226        return 1;
     227      }
     228  
     229    if (!watch_dirs && !watch_files && !watch_direct && !watch_silent && !watch_default)
     230      {
     231        show_help (context, _("No locations given"));
     232        g_option_context_free (context);
     233        return 1;
     234      }
     235  
     236    g_option_context_free (context);
     237  
     238    flags = (no_moves ? 0 : G_FILE_MONITOR_WATCH_MOVES) |
     239            (mounts ? G_FILE_MONITOR_WATCH_MOUNTS : 0);
     240  
     241    if (watch_dirs)
     242      {
     243        for (i = 0; watch_dirs[i]; i++)
     244          if (!add_watch (watch_dirs[i], WATCH_DIR, flags, TRUE))
     245            return 1;
     246      }
     247  
     248    if (watch_files)
     249      {
     250        for (i = 0; watch_files[i]; i++)
     251          if (!add_watch (watch_files[i], WATCH_FILE, flags, TRUE))
     252            return 1;
     253      }
     254  
     255    if (watch_direct)
     256      {
     257        for (i = 0; watch_direct[i]; i++)
     258          if (!add_watch (watch_direct[i], WATCH_FILE, flags | G_FILE_MONITOR_WATCH_HARD_LINKS, TRUE))
     259            return 1;
     260      }
     261  
     262    if (watch_silent)
     263      {
     264        for (i = 0; watch_silent[i]; i++)
     265          if (!add_watch (watch_silent[i], WATCH_FILE, flags | G_FILE_MONITOR_WATCH_HARD_LINKS, FALSE))
     266            return 1;
     267      }
     268  
     269    if (watch_default)
     270      {
     271        for (i = 0; watch_default[i]; i++)
     272          if (!add_watch (watch_default[i], WATCH_AUTO, flags, TRUE))
     273            return 1;
     274      }
     275  
     276    while (TRUE)
     277      g_main_context_iteration (NULL, TRUE);
     278  
     279    return 0;
     280  }