Branch data Line data Source code
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 : 0 : 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 : 0 : g_assert (child);
66 : :
67 [ # # ]: 0 : if (g_file_is_native (child))
68 : 0 : child_str = g_file_get_path (child);
69 : : else
70 : 0 : child_str = g_file_get_uri (child);
71 : :
72 [ # # ]: 0 : if (other)
73 : : {
74 [ # # ]: 0 : if (g_file_is_native (other))
75 : 0 : other_str = g_file_get_path (other);
76 : : else
77 : 0 : other_str = g_file_get_uri (other);
78 : : }
79 : : else
80 : 0 : other_str = g_strdup ("(none)");
81 : :
82 : 0 : g_print ("%s: ", (gchar *) user_data);
83 [ # # # # : 0 : switch (event_type)
# # # # #
# # ]
84 : : {
85 : 0 : case G_FILE_MONITOR_EVENT_CHANGED:
86 : 0 : g_assert (!other);
87 : 0 : g_print ("%s: changed", child_str);
88 : 0 : break;
89 : 0 : case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
90 : 0 : g_assert (!other);
91 : 0 : g_print ("%s: changes done", child_str);
92 : 0 : break;
93 : 0 : case G_FILE_MONITOR_EVENT_DELETED:
94 : 0 : g_assert (!other);
95 : 0 : g_print ("%s: deleted", child_str);
96 : 0 : break;
97 : 0 : case G_FILE_MONITOR_EVENT_CREATED:
98 : 0 : g_assert (!other);
99 : 0 : g_print ("%s: created", child_str);
100 : 0 : break;
101 : 0 : case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
102 : 0 : g_assert (!other);
103 : 0 : g_print ("%s: attributes changed", child_str);
104 : 0 : break;
105 : 0 : case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
106 : 0 : g_assert (!other);
107 : 0 : g_print ("%s: pre-unmount", child_str);
108 : 0 : break;
109 : 0 : case G_FILE_MONITOR_EVENT_UNMOUNTED:
110 : 0 : g_assert (!other);
111 : 0 : g_print ("%s: unmounted", child_str);
112 : 0 : break;
113 : 0 : case G_FILE_MONITOR_EVENT_MOVED_IN:
114 : 0 : g_print ("%s: moved in", child_str);
115 [ # # ]: 0 : if (other)
116 : 0 : g_print (" (from %s)", other_str);
117 : 0 : break;
118 : 0 : case G_FILE_MONITOR_EVENT_MOVED_OUT:
119 : 0 : g_print ("%s: moved out", child_str);
120 [ # # ]: 0 : if (other)
121 : 0 : g_print (" (to %s)", other_str);
122 : 0 : break;
123 : 0 : case G_FILE_MONITOR_EVENT_RENAMED:
124 : 0 : g_assert (other);
125 : 0 : g_print ("%s: renamed to %s\n", child_str, other_str);
126 : 0 : break;
127 : :
128 : 0 : case G_FILE_MONITOR_EVENT_MOVED:
129 : : default:
130 : : g_assert_not_reached ();
131 : : }
132 : :
133 : 0 : g_free (child_str);
134 : 0 : g_free (other_str);
135 : 0 : g_print ("\n");
136 : 0 : }
137 : :
138 : : typedef enum
139 : : {
140 : : WATCH_DIR,
141 : : WATCH_FILE,
142 : : WATCH_AUTO
143 : : } WatchType;
144 : :
145 : : static gboolean
146 : 0 : add_watch (const gchar *cmdline,
147 : : WatchType watch_type,
148 : : GFileMonitorFlags flags,
149 : : gboolean connect_handler)
150 : : {
151 : 0 : GFileMonitor *monitor = NULL;
152 : 0 : GError *error = NULL;
153 : : GFile *file;
154 : :
155 : 0 : file = g_file_new_for_commandline_arg (cmdline);
156 : :
157 [ # # ]: 0 : if (watch_type == WATCH_AUTO)
158 : : {
159 : : GFileInfo *info;
160 : : guint32 type;
161 : :
162 : 0 : info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, &error);
163 [ # # ]: 0 : if (!info)
164 : 0 : goto err;
165 : :
166 : 0 : type = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE);
167 : 0 : watch_type = (type == G_FILE_TYPE_DIRECTORY) ? WATCH_DIR : WATCH_FILE;
168 : : }
169 : :
170 [ # # ]: 0 : if (watch_type == WATCH_DIR)
171 : 0 : monitor = g_file_monitor_directory (file, flags, NULL, &error);
172 : : else
173 : 0 : monitor = g_file_monitor (file, flags, NULL, &error);
174 : :
175 [ # # ]: 0 : if (!monitor)
176 : 0 : goto err;
177 : :
178 [ # # ]: 0 : if (connect_handler)
179 : 0 : g_signal_connect (monitor, "changed", G_CALLBACK (watch_callback), g_strdup (cmdline));
180 : :
181 : 0 : monitor = NULL; /* leak */
182 : 0 : g_object_unref (file);
183 : :
184 : 0 : return TRUE;
185 : :
186 : 0 : err:
187 : 0 : print_file_error (file, error->message);
188 : 0 : g_error_free (error);
189 : 0 : g_object_unref (file);
190 : :
191 : 0 : return FALSE;
192 : : }
193 : :
194 : : int
195 : 0 : handle_monitor (int argc, gchar *argv[], gboolean do_help)
196 : : {
197 : : GOptionContext *context;
198 : : gchar *param;
199 : 0 : GError *error = NULL;
200 : : GFileMonitorFlags flags;
201 : : guint i;
202 : :
203 : 0 : g_set_prgname ("gio monitor");
204 : :
205 : : /* Translators: commandline placeholder */
206 : 0 : param = g_strdup_printf ("%s…", _("LOCATION"));
207 : 0 : context = g_option_context_new (param);
208 : 0 : g_free (param);
209 : 0 : g_option_context_set_help_enabled (context, FALSE);
210 : 0 : g_option_context_set_summary (context,
211 : 0 : _("Monitor files or directories for changes."));
212 : 0 : g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
213 : :
214 [ # # ]: 0 : if (do_help)
215 : : {
216 : 0 : show_help (context, NULL);
217 : 0 : g_option_context_free (context);
218 : 0 : return 0;
219 : : }
220 : :
221 [ # # ]: 0 : if (!g_option_context_parse (context, &argc, &argv, &error))
222 : : {
223 : 0 : show_help (context, error->message);
224 : 0 : g_error_free (error);
225 : 0 : g_option_context_free (context);
226 : 0 : return 1;
227 : : }
228 : :
229 [ # # # # : 0 : if (!watch_dirs && !watch_files && !watch_direct && !watch_silent && !watch_default)
# # # # #
# ]
230 : : {
231 : 0 : show_help (context, _("No locations given"));
232 : 0 : g_option_context_free (context);
233 : 0 : return 1;
234 : : }
235 : :
236 : 0 : g_option_context_free (context);
237 : :
238 [ # # ]: 0 : flags = (no_moves ? 0 : G_FILE_MONITOR_WATCH_MOVES) |
239 : 0 : (mounts ? G_FILE_MONITOR_WATCH_MOUNTS : 0);
240 : :
241 [ # # ]: 0 : if (watch_dirs)
242 : : {
243 [ # # ]: 0 : for (i = 0; watch_dirs[i]; i++)
244 [ # # ]: 0 : if (!add_watch (watch_dirs[i], WATCH_DIR, flags, TRUE))
245 : 0 : return 1;
246 : : }
247 : :
248 [ # # ]: 0 : if (watch_files)
249 : : {
250 [ # # ]: 0 : for (i = 0; watch_files[i]; i++)
251 [ # # ]: 0 : if (!add_watch (watch_files[i], WATCH_FILE, flags, TRUE))
252 : 0 : return 1;
253 : : }
254 : :
255 [ # # ]: 0 : if (watch_direct)
256 : : {
257 [ # # ]: 0 : for (i = 0; watch_direct[i]; i++)
258 [ # # ]: 0 : if (!add_watch (watch_direct[i], WATCH_FILE, flags | G_FILE_MONITOR_WATCH_HARD_LINKS, TRUE))
259 : 0 : return 1;
260 : : }
261 : :
262 [ # # ]: 0 : if (watch_silent)
263 : : {
264 [ # # ]: 0 : for (i = 0; watch_silent[i]; i++)
265 [ # # ]: 0 : if (!add_watch (watch_silent[i], WATCH_FILE, flags | G_FILE_MONITOR_WATCH_HARD_LINKS, FALSE))
266 : 0 : return 1;
267 : : }
268 : :
269 [ # # ]: 0 : if (watch_default)
270 : : {
271 [ # # ]: 0 : for (i = 0; watch_default[i]; i++)
272 [ # # ]: 0 : if (!add_watch (watch_default[i], WATCH_AUTO, flags, TRUE))
273 : 0 : return 1;
274 : : }
275 : :
276 : : while (TRUE)
277 : 0 : g_main_context_iteration (NULL, TRUE);
278 : :
279 : : return 0;
280 : : }
|