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