1 /*
2 * Copyright (C) 2014, Lanedo <martyn@lanedo.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program 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
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20 #include "config.h"
21
22 #include <stdlib.h>
23 #include <errno.h>
24
25 #ifdef __sun
26 #include <procfs.h>
27 #endif
28
29 #include <glib.h>
30 #include <glib/gi18n.h>
31 #include <gio/gio.h>
32
33 #include <libtracker-control/tracker-control.h>
34 #include <libtracker-sparql/tracker-sparql.h>
35
36 #include "tracker-index.h"
37 #include "tracker-dbus.h"
38
39 static gchar **reindex_mime_types;
40 static gboolean index_file;
41 static gboolean backup;
42 static gboolean restore;
43 static gboolean import;
44 static gchar **filenames;
45
46 #define INDEX_OPTIONS_ENABLED() \
47 ((filenames && g_strv_length (filenames) > 0) || \
48 (index_file || \
49 backup || \
50 restore || \
51 import) || \
52 reindex_mime_types)
53
54 static GOptionEntry entries[] = {
55 { "reindex-mime-type", 'm', 0, G_OPTION_ARG_STRING_ARRAY, &reindex_mime_types,
56 N_("Tell miners to reindex files which match the mime type supplied (for new extractors), use -m MIME1 -m MIME2"),
57 N_("MIME") },
58 { "file", 'f', 0, G_OPTION_ARG_NONE, &index_file,
59 N_("Tell miners to (re)index a given file"),
60 N_("FILE") },
61 { "backup", 'b', 0, G_OPTION_ARG_NONE, &backup,
62 N_("Backup current index / database to the file provided"),
63 NULL },
64 { "restore", 'o', 0, G_OPTION_ARG_NONE, &restore,
65 N_("Restore a database from a previous backup (see --backup)"),
66 NULL },
67 { "import", 'i', 0, G_OPTION_ARG_NONE, &import,
68 N_("Import a dataset from the provided file (in Turtle format)"),
69 NULL },
70 { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames,
71 N_("FILE"),
72 N_("FILE") },
73 { NULL }
74 };
75
76 static gboolean
has_valid_uri_scheme(const gchar * uri)77 has_valid_uri_scheme (const gchar *uri)
78 {
79 const gchar *s;
80
81 s = uri;
82
83 if (!g_ascii_isalpha (*s)) {
84 return FALSE;
85 }
86
87 do {
88 s++;
89 } while (g_ascii_isalnum (*s) || *s == '+' || *s == '.' || *s == '-');
90
91 return (*s == ':');
92 }
93
94 static gchar *
get_uri_from_arg(const gchar * arg)95 get_uri_from_arg (const gchar *arg)
96 {
97 gchar *uri;
98
99 /* support both, URIs and local file paths */
100 if (has_valid_uri_scheme (arg)) {
101 uri = g_strdup (arg);
102 } else {
103 GFile *file;
104
105 file = g_file_new_for_commandline_arg (arg);
106 uri = g_file_get_uri (file);
107 g_object_unref (file);
108 }
109
110 return uri;
111 }
112
113 static int
reindex_mimes(void)114 reindex_mimes (void)
115 {
116 GError *error = NULL;
117 TrackerMinerManager *manager;
118
119 /* Auto-start the miners here if we need to */
120 manager = tracker_miner_manager_new_full (TRUE, &error);
121 if (!manager) {
122 g_printerr (_("Could not reindex mimetypes, manager could not be created, %s"),
123 error ? error->message : _("No error given"));
124 g_printerr ("\n");
125 g_clear_error (&error);
126 return EXIT_FAILURE;
127 }
128
129 tracker_miner_manager_reindex_by_mimetype (manager, (GStrv) reindex_mime_types, &error);
130 if (error) {
131 g_printerr ("%s: %s\n",
132 _("Could not reindex mimetypes"),
133 error->message);
134 g_error_free (error);
135 return EXIT_FAILURE;
136 }
137
138 g_print ("%s\n", _("Reindexing mime types was successful"));
139 g_object_unref (manager);
140
141 return EXIT_SUCCESS;
142 }
143
144 static gint
index_or_reindex_file(void)145 index_or_reindex_file (void)
146 {
147 TrackerMinerManager *manager;
148 GError *error = NULL;
149 gchar **p;
150
151 /* Auto-start the miners here if we need to */
152 manager = tracker_miner_manager_new_full (TRUE, &error);
153 if (!manager) {
154 g_printerr (_("Could not (re)index file, manager could not be created, %s"),
155 error ? error->message : _("No error given"));
156 g_printerr ("\n");
157 g_clear_error (&error);
158 return EXIT_FAILURE;
159 }
160
161 for (p = filenames; *p; p++) {
162 GFile *file;
163
164 file = g_file_new_for_commandline_arg (*p);
165 tracker_miner_manager_index_file (manager, file, NULL, &error);
166
167 if (error) {
168 g_printerr ("%s: %s\n",
169 _("Could not (re)index file"),
170 error->message);
171 g_error_free (error);
172 return EXIT_FAILURE;
173 }
174
175 g_print ("%s\n", _("(Re)indexing file was successful"));
176 g_object_unref (file);
177 }
178
179 g_object_unref (manager);
180
181 return EXIT_SUCCESS;
182 }
183
184 static int
import_turtle_files(void)185 import_turtle_files (void)
186 {
187 TrackerSparqlConnection *connection;
188 GError *error = NULL;
189 gchar **p;
190
191 connection = tracker_sparql_connection_get (NULL, &error);
192
193 if (!connection) {
194 g_printerr ("%s: %s\n",
195 _("Could not establish a connection to Tracker"),
196 error ? error->message : _("No error given"));
197 g_clear_error (&error);
198 return EXIT_FAILURE;
199 }
200
201 for (p = filenames; *p; p++) {
202 GError *error = NULL;
203 GFile *file;
204
205 g_print ("%s:'%s'\n",
206 _("Importing Turtle file"),
207 *p);
208
209 file = g_file_new_for_commandline_arg (*p);
210 tracker_sparql_connection_load (connection, file, NULL, &error);
211 g_object_unref (file);
212
213 if (error) {
214 g_printerr (" %s, %s\n",
215 _("Unable to import Turtle file"),
216 error->message);
217
218 g_error_free (error);
219 continue;
220 }
221
222 g_print (" %s\n", _("Done"));
223 g_print ("\n");
224 }
225
226 g_object_unref (connection);
227
228 return EXIT_SUCCESS;
229 }
230
231 static int
backup_index(void)232 backup_index (void)
233 {
234 GDBusConnection *connection;
235 GDBusProxy *proxy;
236 GError *error = NULL;
237 GVariant *v;
238 gchar *uri;
239
240 if (!tracker_dbus_get_connection ("org.freedesktop.Tracker1",
241 "/org/freedesktop/Tracker1/Backup",
242 "org.freedesktop.Tracker1.Backup",
243 G_DBUS_PROXY_FLAGS_NONE,
244 &connection,
245 &proxy)) {
246 return EXIT_FAILURE;
247 }
248
249 uri = get_uri_from_arg (filenames[0]);
250
251 g_print ("%s\n", _("Backing up database"));
252 g_print (" %s\n", uri);
253
254 /* Backup/Restore can take some time */
255 g_dbus_proxy_set_default_timeout (proxy, G_MAXINT);
256
257 v = g_dbus_proxy_call_sync (proxy,
258 "Save",
259 g_variant_new ("(s)", uri),
260 G_DBUS_CALL_FLAGS_NONE,
261 -1,
262 NULL,
263 &error);
264
265 if (proxy) {
266 g_object_unref (proxy);
267 }
268
269 if (error) {
270 g_critical ("%s, %s",
271 _("Could not backup database"),
272 error ? error->message : _("No error given"));
273 g_clear_error (&error);
274 g_free (uri);
275
276 return EXIT_FAILURE;
277 }
278
279 if (v) {
280 g_variant_unref (v);
281 }
282
283 g_free (uri);
284
285 return EXIT_SUCCESS;
286 }
287
288 static int
restore_index(void)289 restore_index (void)
290 {
291 GDBusConnection *connection;
292 GDBusProxy *proxy;
293 GError *error = NULL;
294 GVariant *v;
295 gchar *uri;
296
297 if (!tracker_dbus_get_connection ("org.freedesktop.Tracker1",
298 "/org/freedesktop/Tracker1/Backup",
299 "org.freedesktop.Tracker1.Backup",
300 G_DBUS_PROXY_FLAGS_NONE,
301 &connection,
302 &proxy)) {
303 return EXIT_FAILURE;
304 }
305
306 uri = get_uri_from_arg (filenames[0]);
307
308 g_print ("%s\n", _("Restoring database from backup"));
309 g_print (" %s\n", uri);
310
311 /* Backup/Restore can take some time */
312 g_dbus_proxy_set_default_timeout (proxy, G_MAXINT);
313
314 v = g_dbus_proxy_call_sync (proxy,
315 "Restore",
316 g_variant_new ("(s)", uri),
317 G_DBUS_CALL_FLAGS_NONE,
318 -1,
319 NULL,
320 &error);
321
322 if (proxy) {
323 g_object_unref (proxy);
324 }
325
326 if (error) {
327 g_critical ("%s, %s",
328 _("Could not backup database"),
329 error ? error->message : _("No error given"));
330 g_clear_error (&error);
331 g_free (uri);
332
333 return EXIT_FAILURE;
334 }
335
336 if (v) {
337 g_variant_unref (v);
338 }
339
340 g_free (uri);
341
342 return EXIT_SUCCESS;
343 }
344
345 static int
index_run(void)346 index_run (void)
347 {
348 if (reindex_mime_types) {
349 return reindex_mimes ();
350 }
351
352 if (index_file) {
353 return index_or_reindex_file ();
354 }
355
356 if (import) {
357 return import_turtle_files ();
358 }
359
360 if (backup) {
361 return backup_index ();
362 }
363
364 if (restore) {
365 return restore_index ();
366 }
367
368 /* All known options have their own exit points */
369 g_printerr("Use `tracker index --file` when giving a specific file or "
370 "directory to index. See `tracker help index` for more "
371 "information.\n");
372
373 return EXIT_FAILURE;
374 }
375
376 static int
index_run_default(void)377 index_run_default (void)
378 {
379 GOptionContext *context;
380 gchar *help;
381
382 context = g_option_context_new (NULL);
383 g_option_context_add_main_entries (context, entries, NULL);
384 help = g_option_context_get_help (context, TRUE, NULL);
385 g_option_context_free (context);
386 g_printerr ("%s\n", help);
387 g_free (help);
388
389 return EXIT_FAILURE;
390 }
391
392 static gboolean
index_options_enabled(void)393 index_options_enabled (void)
394 {
395 return INDEX_OPTIONS_ENABLED ();
396 }
397
398 int
tracker_index(int argc,const char ** argv)399 tracker_index (int argc, const char **argv)
400 {
401 GOptionContext *context;
402 GError *error = NULL;
403 const gchar *failed;
404 gint actions = 0;
405
406 context = g_option_context_new (NULL);
407 g_option_context_add_main_entries (context, entries, NULL);
408
409 argv[0] = "tracker index";
410
411 if (!g_option_context_parse (context, &argc, (char***) &argv, &error)) {
412 g_printerr ("%s, %s\n", _("Unrecognized options"), error->message);
413 g_error_free (error);
414 g_option_context_free (context);
415 return EXIT_FAILURE;
416 }
417
418 g_option_context_free (context);
419
420 if (backup) {
421 actions++;
422 }
423
424 if (restore) {
425 actions++;
426 }
427
428 if (index_file) {
429 actions++;
430 }
431
432 if (import) {
433 actions++;
434 }
435
436 if (actions > 1) {
437 failed = _("Only one action (--backup, --restore, --index-file or --import) can be used at a time");
438 } else if (actions > 0 && (!filenames || g_strv_length (filenames) < 1)) {
439 failed = _("Missing one or more files which are required");
440 } else if ((backup || restore) && (filenames && g_strv_length (filenames) > 1)) {
441 failed = _("Only one file can be used with --backup and --restore");
442 } else if (actions > 0 && (reindex_mime_types && g_strv_length (reindex_mime_types) > 0)) {
443 failed = _("Actions (--backup, --restore, --index-file and --import) can not be used with --reindex-mime-type");
444 } else {
445 failed = NULL;
446 }
447
448 if (failed) {
449 g_printerr ("%s\n\n", failed);
450 return EXIT_FAILURE;
451 }
452
453 if (index_options_enabled ()) {
454 return index_run ();
455 }
456
457 return index_run_default ();
458 }
459