No issues found
1 /*
2 * Copyright (C) 2010, Nokia <ivan.frade@nokia.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 <errno.h>
23
24 #include <glib.h>
25 #include <glib/gi18n.h>
26
27 #ifdef __sun
28 #include <procfs.h>
29 #endif
30
31 #include <libtracker-common/tracker-common.h>
32 #include <libtracker-data/tracker-data.h>
33 #include <libtracker-miner/tracker-miner.h>
34
35 #include "tracker-control.h"
36
37 #define OPTION_TERM_ALL "all"
38 #define OPTION_TERM_STORE "store"
39 #define OPTION_TERM_MINERS "miners"
40
41 typedef enum {
42 TERM_NONE,
43 TERM_ALL,
44 TERM_STORE,
45 TERM_MINERS
46 } TermOption;
47
48 /* Note:
49 * Every time a new option is added, make sure it is considered in the
50 * 'GENERAL_OPTIONS_ENABLED' macro below
51 */
52 static gboolean list_processes;
53 static TermOption kill_option = TERM_NONE;
54 static TermOption terminate_option = TERM_NONE;
55 static gboolean hard_reset;
56 static gboolean soft_reset;
57 static gboolean remove_config;
58 static gchar *set_log_verbosity;
59 static gboolean get_log_verbosity;
60 static gboolean start;
61 static gchar *backup;
62 static gchar *restore;
63
64 #define GENERAL_OPTIONS_ENABLED() \
65 (list_processes || \
66 kill_option != TERM_NONE || \
67 terminate_option != TERM_NONE || \
68 hard_reset || \
69 soft_reset || \
70 remove_config || \
71 get_log_verbosity || \
72 set_log_verbosity || \
73 start || \
74 backup || \
75 restore)
76
77 static gboolean term_option_arg_func (const gchar *option_value,
78 const gchar *value,
79 gpointer data,
80 GError **error);
81
82 static GOptionEntry entries[] = {
83 { "list-processes", 'p', 0, G_OPTION_ARG_NONE, &list_processes,
84 N_("List all Tracker processes") },
85 { "kill", 'k', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, term_option_arg_func,
86 N_("Use SIGKILL to stop all matching processes, either \"store\", \"miners\" or \"all\" may be used, no parameter equals \"all\""),
87 N_("APPS") },
88 { "terminate", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, term_option_arg_func,
89 N_("Use SIGTERM to stop all matching processes, either \"store\", \"miners\" or \"all\" may be used, no parameter equals \"all\""),
90 N_("APPS") },
91 { "hard-reset", 'r', 0, G_OPTION_ARG_NONE, &hard_reset,
92 N_("Kill all Tracker processes and remove all databases"),
93 NULL },
94 { "soft-reset", 'e', 0, G_OPTION_ARG_NONE, &soft_reset,
95 N_("Same as --hard-reset but the backup & journal are restored after restart"),
96 NULL },
97 { "remove-config", 'c', 0, G_OPTION_ARG_NONE, &remove_config,
98 N_("Remove all configuration files so they are re-generated on next start"),
99 NULL },
100 { "set-log-verbosity", 0, 0, G_OPTION_ARG_STRING, &set_log_verbosity,
101 N_("Sets the logging verbosity to LEVEL ('debug', 'detailed', 'minimal', 'errors') for all processes"),
102 N_("LEVEL") },
103 { "get-log-verbosity", 0, 0, G_OPTION_ARG_NONE, &get_log_verbosity,
104 N_("Show logging values in terms of log verbosity for each process"),
105 NULL },
106 { "start", 's', 0, G_OPTION_ARG_NONE, &start,
107 N_("Starts miners (which indirectly starts tracker-store too)"),
108 NULL },
109 { "backup", 'b', 0, G_OPTION_ARG_FILENAME, &backup,
110 N_("Backup databases to the file provided"),
111 N_("FILE") },
112 { "restore", 'o', 0, G_OPTION_ARG_FILENAME, &restore,
113 N_("Restore databases from the file provided"),
114 N_("FILE") },
115 { NULL }
116 };
117
118 gboolean
119 tracker_control_general_options_enabled (void)
120 {
121 return GENERAL_OPTIONS_ENABLED ();
122 }
123
124 static GSList *
125 get_pids (void)
126 {
127 GError *error = NULL;
128 GDir *dir;
129 GSList *pids = NULL;
130 const gchar *name;
131
132 dir = g_dir_open ("/proc", 0, &error);
133 if (error) {
134 g_printerr ("%s, %s\n",
135 _("Could not open /proc"),
136 error ? error->message : _("no error given"));
137 g_clear_error (&error);
138 return NULL;
139 }
140
141 while ((name = g_dir_read_name (dir)) != NULL) {
142 gchar c;
143 gboolean is_pid = TRUE;
144
145 for (c = *name; c && c != ':' && is_pid; c++) {
146 is_pid &= g_ascii_isdigit (c);
147 }
148
149 if (!is_pid) {
150 continue;
151 }
152
153 pids = g_slist_prepend (pids, g_strdup (name));
154 }
155
156 g_dir_close (dir);
157
158 return g_slist_reverse (pids);
159 }
160
161 static void
162 log_handler (const gchar *domain,
163 GLogLevelFlags log_level,
164 const gchar *message,
165 gpointer user_data)
166 {
167 switch (log_level) {
168 case G_LOG_LEVEL_WARNING:
169 case G_LOG_LEVEL_CRITICAL:
170 case G_LOG_LEVEL_ERROR:
171 case G_LOG_FLAG_RECURSION:
172 case G_LOG_FLAG_FATAL:
173 g_fprintf (stderr, "%s\n", message);
174 fflush (stderr);
175 break;
176 case G_LOG_LEVEL_MESSAGE:
177 case G_LOG_LEVEL_INFO:
178 case G_LOG_LEVEL_DEBUG:
179 case G_LOG_LEVEL_MASK:
180 default:
181 g_fprintf (stdout, "%s\n", message);
182 fflush (stdout);
183 break;
184 }
185 }
186
187 static gboolean
188 crawler_check_file_cb (TrackerCrawler *crawler,
189 GFile *file,
190 gpointer user_data)
191 {
192 const gchar **suffix;
193 gchar *path;
194 gboolean should_remove;
195
196 suffix = user_data;
197 path = g_file_get_path (file);
198
199 if (suffix) {
200 should_remove = g_str_has_suffix (path, *suffix);
201 } else {
202 should_remove = TRUE;
203 }
204
205 if (!should_remove) {
206 g_free (path);
207 return FALSE;
208 }
209
210 /* Remove file */
211 if (g_unlink (path) == 0) {
212 g_print (" %s\n", path);
213 }
214
215 g_free (path);
216
217 return should_remove;
218 }
219
220 static void
221 crawler_finished_cb (TrackerCrawler *crawler,
222 gboolean was_interrupted,
223 gpointer user_data)
224 {
225 g_main_loop_quit (user_data);
226 }
227
228 typedef struct {
229 gchar *name;
230 GSettings *settings;
231 gboolean is_miner;
232 } ComponentGSettings;
233
234 inline static const gchar *
235 verbosity_to_string (TrackerVerbosity verbosity)
236 {
237 GType type;
238 GEnumClass *enum_class;
239 GEnumValue *enum_value;
240
241 type = tracker_verbosity_get_type ();
242 enum_class = G_ENUM_CLASS (g_type_class_peek (type));
243 enum_value = g_enum_get_value (enum_class, verbosity);
244
245 if (!enum_value) {
246 return "unknown";
247 }
248
249 return enum_value->value_nick;
250 }
251
252 inline static void
253 tracker_gsettings_print_verbosity (GSList *all,
254 gint longest,
255 gboolean miners)
256 {
257 GSList *l;
258
259 for (l = all; l; l = l->next) {
260 ComponentGSettings *c;
261 TrackerVerbosity v;
262
263 c = l->data;
264
265 if (c->is_miner == miners) {
266 continue;
267 }
268
269 v = g_settings_get_enum (c->settings, "verbosity");
270
271 g_print (" %-*.*s: %s\n",
272 longest,
273 longest,
274 c->name,
275 verbosity_to_string (v));
276 }
277 }
278
279 static gboolean
280 tracker_gsettings_set_all (GSList *all,
281 TrackerVerbosity verbosity)
282 {
283 GSList *l;
284 gboolean success = TRUE;
285
286 for (l = all; l && success; l = l->next) {
287 ComponentGSettings *c = l->data;
288
289 if (!c) {
290 continue;
291 }
292
293 success &= g_settings_set_enum (c->settings, "verbosity", verbosity);
294 g_settings_apply (c->settings);
295 }
296
297 g_settings_sync ();
298
299 return success;
300 }
301
302 static GSList *
303 tracker_gsettings_get_all (gint *longest_name_length)
304 {
305 typedef struct {
306 const gchar *schema;
307 const gchar *path;
308 } SchemaWithPath;
309
310 TrackerMinerManager *manager;
311 GError *error = NULL;
312 GSettings *settings;
313 GSList *all = NULL;
314 GSList *l;
315 GSList *miners_available;
316 GSList *valid_schemas = NULL;
317 const gchar * const *schema;
318 gint len = 0;
319 SchemaWithPath components[] = {
320 { "Store", "store" },
321 { "Extract", "extract" },
322 { "Writeback", "writeback" },
323 { 0 }
324 };
325 SchemaWithPath *swp;
326
327 /* Don't auto-start the miners here */
328 manager = tracker_miner_manager_new_full (FALSE, &error);
329 if (!manager) {
330 g_printerr (_("Could not get GSettings for miners, manager could not be created, %s"),
331 error ? error->message : "unknown error");
332 g_printerr ("\n");
333 g_clear_error (&error);
334 return NULL;
335 }
336
337 miners_available = tracker_miner_manager_get_available (manager);
338
339 /* Get valid schemas so we don't try to load invalid ones */
340 for (schema = g_settings_list_schemas (); schema && *schema; schema++) {
341 if (!g_str_has_prefix (*schema, "org.freedesktop.Tracker.")) {
342 continue;
343 }
344
345 valid_schemas = g_slist_prepend (valid_schemas, g_strdup (*schema));
346 }
347
348 /* Store / General */
349 for (swp = components; swp && swp->schema; swp++) {
350 gchar *schema;
351 gchar *path;
352
353 schema = g_strdup_printf ("org.freedesktop.Tracker.%s", swp->schema);
354 path = g_strdup_printf ("/org/freedesktop/tracker/%s/", swp->path);
355
356 /* If miner doesn't have a schema, no point in getting config */
357 if (!tracker_string_in_gslist (schema, valid_schemas)) {
358 g_free (path);
359 g_free (schema);
360 continue;
361 }
362
363 len = MAX (len, strlen (swp->schema));
364
365 settings = g_settings_new_with_path (schema, path);
366 if (settings) {
367 ComponentGSettings *c = g_slice_new (ComponentGSettings);
368
369 c->name = g_strdup (swp->schema);
370 c->settings = settings;
371 c->is_miner = FALSE;
372
373 all = g_slist_prepend (all, c);
374 }
375 }
376
377 /* Miners */
378 for (l = miners_available; l; l = l->next) {
379 const gchar *name;
380 gchar *schema;
381 gchar *name_lowercase;
382 gchar *path;
383 gchar *miner;
384
385 miner = l->data;
386 if (!miner) {
387 continue;
388 }
389
390 name = g_utf8_strrchr (miner, -1, '.');
391 if (!name) {
392 continue;
393 }
394
395 name++;
396 name_lowercase = g_utf8_strdown (name, -1);
397
398 schema = g_strdup_printf ("org.freedesktop.Tracker.Miner.%s", name);
399 path = g_strdup_printf ("/org/freedesktop/tracker/miner/%s/", name_lowercase);
400 g_free (name_lowercase);
401
402 /* If miner doesn't have a schema, no point in getting config */
403 if (!tracker_string_in_gslist (schema, valid_schemas)) {
404 g_free (path);
405 g_free (schema);
406 continue;
407 }
408
409 settings = g_settings_new_with_path (schema, path);
410 g_free (path);
411 g_free (schema);
412
413 if (settings) {
414 ComponentGSettings *c = g_slice_new (ComponentGSettings);
415
416 c->name = g_strdup (name);
417 c->settings = settings;
418 c->is_miner = TRUE;
419
420 all = g_slist_prepend (all, c);
421 len = MAX (len, strlen (name));
422 }
423 }
424
425 g_slist_foreach (valid_schemas, (GFunc) g_free, NULL);
426 g_slist_free (valid_schemas);
427 g_slist_foreach (miners_available, (GFunc) g_free, NULL);
428 g_slist_free (miners_available);
429 g_object_unref (manager);
430
431 if (longest_name_length) {
432 *longest_name_length = len;
433 }
434
435 return g_slist_reverse (all);
436 }
437
438 static void
439 tracker_gsettings_free (GSList *all)
440 {
441 GSList *l;
442
443 /* Clean up */
444 for (l = all; l; l = l->next) {
445 ComponentGSettings *c = l->data;
446
447 g_free (c->name);
448 g_object_unref (c->settings);
449 g_slice_free (ComponentGSettings, c);
450 }
451 }
452
453 static gboolean
454 term_option_arg_func (const gchar *option_value,
455 const gchar *value,
456 gpointer data,
457 GError **error)
458 {
459 TermOption option;
460
461 if (!value) {
462 value = OPTION_TERM_ALL;
463 }
464
465 if (strcmp (value, OPTION_TERM_ALL) == 0) {
466 option = TERM_ALL;
467 } else if (strcmp (value, OPTION_TERM_STORE) == 0) {
468 option = TERM_STORE;
469 } else if (strcmp (value, OPTION_TERM_MINERS) == 0) {
470 option = TERM_MINERS;
471 } else {
472 g_set_error_literal (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
473 "Only one of 'all', 'store' and 'miners' are allowed");
474 return FALSE;
475 }
476
477 if (strcmp (option_value, "-k") == 0 ||
478 strcmp (option_value, "--kill") == 0) {
479 kill_option = option;
480 } else if (strcmp (option_value, "-t") == 0 ||
481 strcmp (option_value, "--terminate") == 0) {
482 terminate_option = option;
483 }
484
485 return TRUE;
486 }
487
488 static gboolean
489 has_valid_uri_scheme (const gchar *uri)
490 {
491 const gchar *s;
492
493 s = uri;
494
495 if (!g_ascii_isalpha (*s)) {
496 return FALSE;
497 }
498
499 do {
500 s++;
501 } while (g_ascii_isalnum (*s) || *s == '+' || *s == '.' || *s == '-');
502
503 return (*s == ':');
504 }
505
506 static gchar *
507 get_uri_from_arg (const gchar *arg)
508 {
509 gchar *uri;
510
511 /* support both, URIs and local file paths */
512 if (has_valid_uri_scheme (arg)) {
513 uri = g_strdup (arg);
514 } else {
515 GFile *file;
516
517 file = g_file_new_for_commandline_arg (arg);
518 uri = g_file_get_uri (file);
519 g_object_unref (file);
520 }
521
522 return uri;
523 }
524
525 static inline guint32
526 get_uid_for_pid (const gchar *pid_as_string,
527 gchar **filename)
528 {
529 GFile *f;
530 GFileInfo *info;
531 GError *error = NULL;
532 gchar *fn;
533 guint uid;
534
535 #ifdef __sun /* Solaris */
536 fn = g_build_filename ("/proc", pid_as_string, "psinfo", NULL);
537 #else
538 fn = g_build_filename ("/proc", pid_as_string, "cmdline", NULL);
539 #endif
540
541 f = g_file_new_for_path (fn);
542 info = g_file_query_info (f,
543 G_FILE_ATTRIBUTE_UNIX_UID,
544 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
545 NULL,
546 &error);
547
548 if (error) {
549 g_printerr ("Could not stat() file:'%s', %s", fn, error->message);
550 g_error_free (error);
551 uid = 0;
552 } else {
553 uid = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID);
554 g_object_unref (info);
555 }
556
557 if (filename) {
558 *filename = fn;
559 } else {
560 g_free (fn);
561 }
562
563 g_object_unref (f);
564
565 return uid;
566 }
567
568 void
569 tracker_control_general_run_default (void)
570 {
571 /* Enable list processes in the default run */
572 list_processes = TRUE;
573
574 tracker_control_general_run ();
575 }
576
577 gint
578 tracker_control_general_run (void)
579 {
580 GError *error = NULL;
581 GSList *pids;
582 GSList *l;
583 gchar *str;
584 gpointer verbosity_type_enum_class_pointer = NULL;
585 TrackerVerbosity set_log_verbosity_value = TRACKER_VERBOSITY_ERRORS;
586
587 /* Constraints */
588
589 if (kill_option != TERM_NONE && terminate_option != TERM_NONE) {
590 g_printerr ("%s\n",
591 _("You can not use the --kill and --terminate arguments together"));
592 return EXIT_FAILURE;
593 }
594
595 if ((hard_reset || soft_reset) && terminate_option != TERM_NONE) {
596 g_printerr ("%s\n",
597 _("You can not use the --terminate with --hard-reset or --soft-reset, --kill is implied"));
598 return EXIT_FAILURE;
599 }
600
601 if (hard_reset && soft_reset) {
602 g_printerr ("%s\n",
603 _("You can not use the --hard-reset and --soft-reset arguments together"));
604 return EXIT_FAILURE;
605 }
606
607 if (get_log_verbosity && set_log_verbosity) {
608 g_printerr ("%s\n",
609 _("You can not use the --get-logging and --set-logging arguments together"));
610 return EXIT_FAILURE;
611 }
612
613 if (set_log_verbosity) {
614 if (g_ascii_strcasecmp (set_log_verbosity, "debug") == 0) {
615 set_log_verbosity_value = TRACKER_VERBOSITY_DEBUG;
616 } else if (g_ascii_strcasecmp (set_log_verbosity, "detailed") == 0) {
617 set_log_verbosity_value = TRACKER_VERBOSITY_DETAILED;
618 } else if (g_ascii_strcasecmp (set_log_verbosity, "minimal") == 0) {
619 set_log_verbosity_value = TRACKER_VERBOSITY_MINIMAL;
620 } else if (g_ascii_strcasecmp (set_log_verbosity, "errors") == 0) {
621 set_log_verbosity_value = TRACKER_VERBOSITY_ERRORS;
622 } else {
623 g_printerr ("%s\n",
624 _("Invalid log verbosity, try 'debug', 'detailed', 'minimal' or 'errors'"));
625 return EXIT_FAILURE;
626 }
627 }
628
629 if (hard_reset || soft_reset) {
630 /* Imply --kill */
631 kill_option = TERM_ALL;
632 }
633
634 if (get_log_verbosity || set_log_verbosity) {
635 GType etype;
636
637 /* Since we don't reference this enum anywhere, we do
638 * it here to make sure it exists when we call
639 * g_type_class_peek(). This wouldn't be necessary if
640 * it was a param in a GObject for example.
641 *
642 * This does mean that we are leaking by 1 reference
643 * here and should clean it up, but it doesn't grow so
644 * this is acceptable.
645 */
646 etype = tracker_verbosity_get_type ();
647 verbosity_type_enum_class_pointer = g_type_class_ref (etype);
648 }
649
650 /* Unless we are stopping processes or listing processes,
651 * don't iterate them.
652 */
653 if (kill_option != TERM_NONE ||
654 terminate_option != TERM_NONE ||
655 list_processes) {
656 guint32 own_pid;
657 guint32 own_uid;
658 gchar *own_pid_str;
659
660 pids = get_pids ();
661 str = g_strdup_printf (g_dngettext (NULL,
662 "Found %d PID…",
663 "Found %d PIDs…",
664 g_slist_length (pids)),
665 g_slist_length (pids));
666 g_print ("%s\n", str);
667 g_free (str);
668
669 /* Establish own uid/pid */
670 own_pid = (guint32) getpid ();
671 own_pid_str = g_strdup_printf ("%d", own_pid);
672 own_uid = get_uid_for_pid (own_pid_str, NULL);
673 g_free (own_pid_str);
674
675 for (l = pids; l; l = l->next) {
676 GError *error = NULL;
677 gchar *filename;
678 #ifdef __sun /* Solaris */
679 psinfo_t psinfo = { 0 };
680 #endif
681 gchar *contents = NULL;
682
683 gchar **strv;
684 guint uid;
685
686 uid = get_uid_for_pid (l->data, &filename);
687
688 /* Stat the file and make sure current user == file owner */
689 if (uid != own_uid) {
690 continue;
691 }
692
693 /* Get contents to determine basename */
694 if (!g_file_get_contents (filename, &contents, NULL, &error)) {
695 str = g_strdup_printf (_("Could not open '%s'"), filename);
696 g_printerr ("%s, %s\n",
697 str,
698 error ? error->message : _("no error given"));
699 g_free (str);
700 g_clear_error (&error);
701 g_free (contents);
702 g_free (filename);
703
704 continue;
705 }
706 #ifdef __sun /* Solaris */
707 memcpy (&psinfo, contents, sizeof (psinfo));
708
709 /* won't work with paths containing spaces :( */
710 strv = g_strsplit (psinfo.pr_psargs, " ", 2);
711 #else
712 strv = g_strsplit (contents, "^@", 2);
713 #endif
714 if (strv && strv[0]) {
715 gchar *basename;
716
717 basename = g_path_get_basename (strv[0]);
718
719 if ((g_str_has_prefix (basename, "tracker") == TRUE ||
720 g_str_has_prefix (basename, "lt-tracker") == TRUE) &&
721 g_str_has_suffix (basename, "-control") == FALSE &&
722 g_str_has_suffix (basename, "-status-icon") == FALSE) {
723 pid_t pid;
724
725 pid = atoi (l->data);
726 str = g_strdup_printf (_("Found process ID %d for '%s'"), pid, basename);
727 g_print ("%s\n", str);
728 g_free (str);
729
730 if (terminate_option != TERM_NONE) {
731 if ((terminate_option == TERM_STORE &&
732 !g_str_has_suffix (basename, "tracker-store")) ||
733 (terminate_option == TERM_MINERS &&
734 !strstr (basename, "tracker-miner"))) {
735 continue;
736 }
737
738 if (kill (pid, SIGTERM) == -1) {
739 const gchar *errstr = g_strerror (errno);
740
741 str = g_strdup_printf (_("Could not terminate process %d"), pid);
742 g_printerr (" %s, %s\n",
743 str,
744 errstr ? errstr : _("no error given"));
745 g_free (str);
746 } else {
747 str = g_strdup_printf (_("Terminated process %d"), pid);
748 g_print (" %s\n", str);
749 g_free (str);
750 }
751 } else if (kill_option != TERM_NONE) {
752 if ((kill_option == TERM_STORE &&
753 !g_str_has_suffix (basename, "tracker-store")) ||
754 (kill_option == TERM_MINERS &&
755 !strstr (basename, "tracker-miner"))) {
756 continue;
757 }
758
759 if (kill (pid, SIGKILL) == -1) {
760 const gchar *errstr = g_strerror (errno);
761
762 str = g_strdup_printf (_("Could not kill process %d"), pid);
763 g_printerr (" %s, %s\n",
764 str,
765 errstr ? errstr : _("no error given"));
766 g_free (str);
767 } else {
768 str = g_strdup_printf (_("Killed process %d"), pid);
769 g_print (" %s\n", str);
770 g_free (str);
771 }
772 }
773 }
774
775 g_free (basename);
776 }
777
778 g_strfreev (strv);
779 g_free (contents);
780 g_free (filename);
781 }
782
783 g_slist_foreach (pids, (GFunc) g_free, NULL);
784 g_slist_free (pids);
785
786 /* If we just wanted to list processes, all done */
787 if (list_processes &&
788 terminate_option == TERM_NONE &&
789 kill_option == TERM_NONE) {
790 return EXIT_SUCCESS;
791 }
792 }
793
794 if (hard_reset || soft_reset) {
795 guint log_handler_id;
796 #ifndef DISABLE_JOURNAL
797 gchar *rotate_to;
798 TrackerDBConfig *db_config;
799 gsize chunk_size;
800 gint chunk_size_mb;
801 #endif /* DISABLE_JOURNAL */
802
803 /* Set log handler for library messages */
804 log_handler_id = g_log_set_handler (NULL,
805 G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL,
806 log_handler,
807 NULL);
808
809 g_log_set_default_handler (log_handler, NULL);
810
811 #ifndef DISABLE_JOURNAL
812 db_config = tracker_db_config_new ();
813
814 chunk_size_mb = tracker_db_config_get_journal_chunk_size (db_config);
815 chunk_size = (gsize) ((gsize) chunk_size_mb * (gsize) 1024 * (gsize) 1024);
816 rotate_to = tracker_db_config_get_journal_rotate_destination (db_config);
817
818 /* This call is needed to set the journal's filename */
819 tracker_db_journal_set_rotating ((chunk_size_mb != -1),
820 chunk_size, rotate_to);
821
822 g_free (rotate_to);
823 g_object_unref (db_config);
824
825 #endif /* DISABLE_JOURNAL */
826
827 /* Clean up (select_cache_size and update_cache_size don't matter here) */
828 if (!tracker_db_manager_init (TRACKER_DB_MANAGER_REMOVE_ALL,
829 NULL,
830 FALSE,
831 FALSE,
832 100,
833 100,
834 NULL,
835 NULL,
836 NULL,
837 &error)) {
838
839 g_message ("Error initializing database: %s", error->message);
840 g_free (error);
841
842 return EXIT_FAILURE;
843 }
844 #ifndef DISABLE_JOURNAL
845 tracker_db_journal_init (NULL, FALSE, NULL);
846 #endif /* DISABLE_JOURNAL */
847
848 tracker_db_manager_remove_all (hard_reset);
849 tracker_db_manager_shutdown ();
850 #ifndef DISABLE_JOURNAL
851 tracker_db_journal_shutdown (NULL);
852 #endif /* DISABLE_JOURNAL */
853
854 /* Unset log handler */
855 g_log_remove_handler (NULL, log_handler_id);
856 }
857
858 if (remove_config) {
859 GMainLoop *main_loop;
860 GFile *file;
861 TrackerCrawler *crawler;
862 const gchar *suffix = ".cfg";
863 const gchar *home_conf_dir;
864 gchar *path;
865 GSList *all, *l;
866
867 crawler = tracker_crawler_new ();
868 main_loop = g_main_loop_new (NULL, FALSE);
869
870 g_signal_connect (crawler, "check-file",
871 G_CALLBACK (crawler_check_file_cb),
872 &suffix);
873 g_signal_connect (crawler, "finished",
874 G_CALLBACK (crawler_finished_cb),
875 main_loop);
876
877 /* Go through service files */
878
879 /* Check the default XDG_DATA_HOME location */
880 home_conf_dir = g_getenv ("XDG_CONFIG_HOME");
881
882 if (home_conf_dir && tracker_path_has_write_access_or_was_created (home_conf_dir)) {
883 path = g_build_path (G_DIR_SEPARATOR_S, home_conf_dir, "tracker", NULL);
884 } else {
885 home_conf_dir = g_getenv ("HOME");
886
887 if (!home_conf_dir || !tracker_path_has_write_access_or_was_created (home_conf_dir)) {
888 home_conf_dir = g_get_home_dir ();
889 }
890 path = g_build_path (G_DIR_SEPARATOR_S, home_conf_dir, ".config", "tracker", NULL);
891 }
892
893 file = g_file_new_for_path (path);
894 g_free (path);
895
896 g_print ("%s\n", _("Removing configuration files…"));
897
898 tracker_crawler_start (crawler, file, FALSE);
899 g_object_unref (file);
900
901 g_main_loop_run (main_loop);
902 g_object_unref (crawler);
903
904 g_print ("%s\n", _("Resetting existing configuration…"));
905
906 all = tracker_gsettings_get_all (NULL);
907
908 if (!all) {
909 return EXIT_FAILURE;
910 }
911
912 for (l = all; l; l = l->next) {
913 ComponentGSettings *c = l->data;
914 gchar **keys, **p;
915
916 if (!c) {
917 continue;
918 }
919
920 g_print (" %s\n", c->name);
921
922 keys = g_settings_list_keys (c->settings);
923 for (p = keys; p && *p; p++) {
924 g_print (" %s\n", *p);
925 g_settings_reset (c->settings, *p);
926 }
927
928 if (keys) {
929 g_strfreev (keys);
930 }
931
932 g_settings_apply (c->settings);
933 }
934
935 g_settings_sync ();
936
937 tracker_gsettings_free (all);
938 }
939
940 /* Deal with logging changes AFTER the config may have been
941 * reset, this way users can actually use --remove-config with
942 * the --set-logging switch.
943 */
944 if (get_log_verbosity) {
945 GSList *all;
946 gint longest = 0;
947
948 all = tracker_gsettings_get_all (&longest);
949
950 if (!all) {
951 return EXIT_FAILURE;
952 }
953
954 g_print ("%s:\n", _("Components"));
955 tracker_gsettings_print_verbosity (all, longest, TRUE);
956 g_print ("\n");
957
958 /* Miners */
959 g_print ("%s (%s):\n",
960 _("Miners"),
961 _("Only those with config listed"));
962 tracker_gsettings_print_verbosity (all, longest, FALSE);
963 g_print ("\n");
964
965 tracker_gsettings_free (all);
966 }
967
968 if (set_log_verbosity) {
969 GSList *all;
970 gchar *str;
971 gint longest = 0;
972
973 all = tracker_gsettings_get_all (&longest);
974
975 if (!all) {
976 return EXIT_FAILURE;
977 }
978
979 str = g_strdup_printf (_("Setting log verbosity for all components to '%s'…"), set_log_verbosity);
980 g_print ("%s\n", str);
981 g_print ("\n");
982 g_free (str);
983
984 tracker_gsettings_set_all (all, set_log_verbosity_value);
985 tracker_gsettings_free (all);
986
987 /* We free to make sure we get new settings and that
988 * they're saved properly.
989 */
990 all = tracker_gsettings_get_all (&longest);
991
992 if (!all) {
993 return EXIT_FAILURE;
994 }
995
996 g_print ("%s:\n", _("Components"));
997 tracker_gsettings_print_verbosity (all, longest, TRUE);
998 g_print ("\n");
999
1000 /* Miners */
1001 g_print ("%s (%s):\n",
1002 _("Miners"),
1003 _("Only those with config listed"));
1004 tracker_gsettings_print_verbosity (all, longest, FALSE);
1005 g_print ("\n");
1006
1007 tracker_gsettings_free (all);
1008 }
1009
1010 if (verbosity_type_enum_class_pointer) {
1011 g_type_class_unref (verbosity_type_enum_class_pointer);
1012 }
1013
1014 if (start) {
1015 TrackerMinerManager *manager;
1016 GSList *miners, *l;
1017
1018 if (hard_reset || soft_reset) {
1019 g_print ("%s\n", _("Waiting one second before starting miners…"));
1020
1021 /* Give a second's grace to avoid race conditions */
1022 g_usleep (G_USEC_PER_SEC);
1023 }
1024
1025 g_print ("%s\n", _("Starting miners…"));
1026
1027
1028 /* Auto-start the miners here */
1029 manager = tracker_miner_manager_new_full (TRUE, &error);
1030 if (!manager) {
1031 g_printerr (_("Could not start miners, manager could not be created, %s"),
1032 error ? error->message : "unknown error");
1033 g_printerr ("\n");
1034 g_clear_error (&error);
1035 return EXIT_FAILURE;
1036 }
1037
1038 miners = tracker_miner_manager_get_available (manager);
1039
1040 /* Get the status of all miners, this will start all
1041 * miners not already running.
1042 */
1043 for (l = miners; l; l = l->next) {
1044 const gchar *display_name;
1045 gdouble progress = 0.0;
1046
1047 display_name = tracker_miner_manager_get_display_name (manager, l->data);
1048
1049 if (!tracker_miner_manager_get_status (manager,
1050 l->data,
1051 NULL,
1052 &progress,
1053 NULL)) {
1054 g_printerr (" ✗ %s (%s)\n",
1055 display_name,
1056 _("perhaps a disabled plugin?"));
1057 } else {
1058 g_print (" ✓ %s\n",
1059 display_name);
1060 }
1061
1062 g_free (l->data);
1063 }
1064
1065 g_slist_free (miners);
1066 g_object_unref (manager);
1067 }
1068
1069 if (backup) {
1070 GDBusConnection *connection;
1071 GDBusProxy *proxy;
1072 GError *error = NULL;
1073 GVariant *v;
1074 gchar *uri;
1075
1076 uri = get_uri_from_arg (backup);
1077
1078 g_print ("%s\n", _("Backing up database"));
1079 g_print (" %s\n", uri);
1080
1081 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
1082
1083 if (!connection) {
1084 g_critical ("Could not connect to the D-Bus session bus, %s",
1085 error ? error->message : "no error given.");
1086 g_clear_error (&error);
1087 g_free (uri);
1088
1089 return EXIT_FAILURE;
1090 }
1091
1092 proxy = g_dbus_proxy_new_sync (connection,
1093 G_DBUS_PROXY_FLAGS_NONE,
1094 NULL,
1095 "org.freedesktop.Tracker1",
1096 "/org/freedesktop/Tracker1/Backup",
1097 "org.freedesktop.Tracker1.Backup",
1098 NULL,
1099 &error);
1100
1101 if (error) {
1102 g_critical ("Could not create proxy on the D-Bus session bus, %s",
1103 error ? error->message : "no error given.");
1104 g_clear_error (&error);
1105 g_free (uri);
1106
1107 return EXIT_FAILURE;
1108 }
1109
1110 /* Backup/Restore can take some time */
1111 g_dbus_proxy_set_default_timeout (proxy, G_MAXINT);
1112
1113 v = g_dbus_proxy_call_sync (proxy,
1114 "Save",
1115 g_variant_new ("(s)", uri),
1116 G_DBUS_CALL_FLAGS_NONE,
1117 -1,
1118 NULL,
1119 &error);
1120
1121 if (proxy) {
1122 g_object_unref (proxy);
1123 }
1124
1125 if (error) {
1126 g_critical ("Could not backup database, %s",
1127 error ? error->message : "no error given.");
1128 g_clear_error (&error);
1129 g_free (uri);
1130
1131 return EXIT_FAILURE;
1132 }
1133
1134 if (v) {
1135 g_variant_unref (v);
1136 }
1137
1138 g_free (uri);
1139 }
1140
1141 if (restore) {
1142 GDBusConnection *connection;
1143 GDBusProxy *proxy;
1144 GError *error = NULL;
1145 GVariant *v;
1146 gchar *uri;
1147
1148 uri = get_uri_from_arg (restore);
1149
1150 g_print ("%s\n", _("Restoring database from backup"));
1151 g_print (" %s\n", uri);
1152
1153 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
1154
1155 if (!connection) {
1156 g_critical ("Could not connect to the D-Bus session bus, %s",
1157 error ? error->message : "no error given.");
1158 g_clear_error (&error);
1159 g_free (uri);
1160
1161 return EXIT_FAILURE;
1162 }
1163
1164 proxy = g_dbus_proxy_new_sync (connection,
1165 G_DBUS_PROXY_FLAGS_NONE,
1166 NULL,
1167 "org.freedesktop.Tracker1",
1168 "/org/freedesktop/Tracker1/Backup",
1169 "org.freedesktop.Tracker1.Backup",
1170 NULL,
1171 &error);
1172
1173 if (error) {
1174 g_critical ("Could not create proxy on the D-Bus session bus, %s",
1175 error ? error->message : "no error given.");
1176 g_clear_error (&error);
1177 g_free (uri);
1178
1179 return EXIT_FAILURE;
1180 }
1181
1182 /* Backup/Restore can take some time */
1183 g_dbus_proxy_set_default_timeout (proxy, G_MAXINT);
1184
1185 v = g_dbus_proxy_call_sync (proxy,
1186 "Restore",
1187 g_variant_new ("(s)", uri),
1188 G_DBUS_CALL_FLAGS_NONE,
1189 -1,
1190 NULL,
1191 &error);
1192
1193 if (proxy) {
1194 g_object_unref (proxy);
1195 }
1196
1197 if (error) {
1198 g_critical ("Could not restore database, %s",
1199 error ? error->message : "no error given.");
1200 g_clear_error (&error);
1201 g_free (uri);
1202
1203 return EXIT_FAILURE;
1204 }
1205
1206 if (v) {
1207 g_variant_unref (v);
1208 }
1209
1210 g_free (uri);
1211 }
1212
1213 return EXIT_SUCCESS;
1214 }
1215
1216 GOptionGroup *
1217 tracker_control_general_get_option_group (void)
1218 {
1219 GOptionGroup *group;
1220
1221 /* Status options */
1222 group = g_option_group_new ("general",
1223 _("General options"),
1224 _("Show general options"),
1225 NULL,
1226 NULL);
1227 g_option_group_add_entries (group, entries);
1228
1229 return group;
1230 }