No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | tracker-main.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /*
2 * Copyright (C) 2008, Nokia <ivan.frade@nokia.com>
3
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 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 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21
22 #include <string.h>
23 #include <stdlib.h>
24 #include <locale.h>
25 #include <signal.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29
30 #include <glib.h>
31 #include <glib-object.h>
32 #include <glib/gi18n.h>
33
34 #include <libtracker-common/tracker-ioprio.h>
35 #include <libtracker-common/tracker-log.h>
36 #include <libtracker-common/tracker-ontologies.h>
37 #include <libtracker-common/tracker-file-utils.h>
38 #include <libtracker-common/tracker-sched.h>
39 #include <libtracker-common/tracker-enums.h>
40
41 #include <libtracker-miner/tracker-miner.h>
42
43 #include <libtracker-data/tracker-db-manager.h>
44
45 #include "tracker-config.h"
46 #include "tracker-marshal.h"
47 #include "tracker-miner-userguides.h"
48 #include "tracker-miner-applications.h"
49 #include "tracker-miner-files.h"
50 #include "tracker-miner-files-index.h"
51 #include "tracker-writeback.h"
52
53 #define ABOUT \
54 "Tracker " PACKAGE_VERSION "\n"
55
56 #define LICENSE \
57 "This program is free software and comes without any warranty.\n" \
58 "It is licensed under version 2 or later of the General Public " \
59 "License which can be viewed at:\n" \
60 "\n" \
61 " http://www.gnu.org/licenses/gpl.txt\n"
62
63 #define SECONDS_PER_DAY 60 * 60 * 24
64
65 #define OPTION_DISABLE_FILES "files"
66 #define OPTION_DISABLE_APPLICATIONS "applications"
67 #define OPTION_DISABLE_USERGUIDES "userguides"
68
69 typedef enum {
70 DISABLE_NONE,
71 DISABLE_FILES,
72 DISABLE_APPLICATIONS,
73 #ifdef HAVE_MAEMO
74 DISABLE_USERGUIDES,
75 #endif /* HAVE_MAEMO */
76 } DisableOption;
77
78 static gboolean miner_disable_option_arg_func (const gchar *option_value,
79 const gchar *value,
80 gpointer data,
81 GError **error);
82 static void miner_handle_next (void);
83
84
85 static GMainLoop *main_loop;
86 static GSList *miners;
87 static GSList *current_miner;
88 static gboolean finished_miners;
89
90 static gint verbosity = -1;
91 static gint initial_sleep = -1;
92 static gboolean no_daemon;
93 static gchar *eligible;
94 static GArray *disable_options = NULL;
95 /* static DisableOption disable_option[] = { 0 }; */
96 static gboolean version;
97 static guint miners_timeout_id = 0;
98
99 static GOptionEntry entries[] = {
100 { "verbosity", 'v', 0,
101 G_OPTION_ARG_INT, &verbosity,
102 N_("Logging, 0 = errors only, "
103 "1 = minimal, 2 = detailed and 3 = debug (default=0)"),
104 NULL },
105 { "initial-sleep", 's', 0,
106 G_OPTION_ARG_INT, &initial_sleep,
107 N_("Initial sleep time in seconds, "
108 "0->1000 (default=15)"),
109 NULL },
110 { "no-daemon", 'n', 0,
111 G_OPTION_ARG_NONE, &no_daemon,
112 N_("Runs until all configured locations are indexed and then exits"),
113 NULL },
114 { "eligible", 'e', 0,
115 G_OPTION_ARG_FILENAME, &eligible,
116 N_("Checks if FILE is eligible for being mined based on configuration"),
117 N_("FILE") },
118 { "disable-miner", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
119 G_OPTION_ARG_CALLBACK, miner_disable_option_arg_func,
120 N_("Disable miners started as part of this process, options include"
121 ": '" OPTION_DISABLE_FILES "'"
122 ", '" OPTION_DISABLE_APPLICATIONS "'"
123 #ifdef HAVE_MAEMO
124 ", '" OPTION_DISABLE_USERGUIDES "'"
125 #endif /* HAVE_MAEMO */
126 ),
127 N_("MINER") },
128 { "version", 'V', 0,
129 G_OPTION_ARG_NONE, &version,
130 N_("Displays version information"),
131 NULL },
132 { NULL }
133 };
134
135 static gboolean
136 miner_disable_option_arg_func (const gchar *option_value,
137 const gchar *value,
138 gpointer data,
139 GError **error)
140 {
141 DisableOption option;
142 gchar *value_casefold;
143 gboolean found = FALSE;
144 gint i;
145
146 if (!value || *value == '\0') {
147 /* Show help */
148 #ifdef HAVE_MAEMO
149 g_set_error_literal (error,
150 G_OPTION_ERROR,
151 G_OPTION_ERROR_FAILED,
152 "A value is required, either "
153 "'" OPTION_DISABLE_FILES "', "
154 "'" OPTION_DISABLE_APPLICATIONS "' or "
155 "'" OPTION_DISABLE_USERGUIDES "'");
156 #else /* HAVE_MAEMO */
157 g_set_error_literal (error,
158 G_OPTION_ERROR,
159 G_OPTION_ERROR_FAILED,
160 "A value is required, either "
161 "'" OPTION_DISABLE_FILES "', "
162 "'" OPTION_DISABLE_APPLICATIONS "'");
163 #endif /* HAVE_MAEMO */
164 return FALSE;
165 }
166
167 value_casefold = g_utf8_casefold (value, -1);
168
169 if (strcmp (value_casefold, OPTION_DISABLE_FILES) == 0) {
170 option = DISABLE_FILES;
171 } else if (strcmp (value_casefold, OPTION_DISABLE_APPLICATIONS) == 0) {
172 option = DISABLE_APPLICATIONS;
173 #ifdef HAVE_MAEMO
174 } else if (strcmp (value_casefold, OPTION_DISABLE_USERGUIDES) == 0) {
175 option = DISABLE_USERGUIDES;
176 #endif /* HAVE_MAEMO */
177 } else {
178 g_set_error (error,
179 G_OPTION_ERROR,
180 G_OPTION_ERROR_FAILED,
181 "Miner '%s' is not recognized",
182 value);
183 return FALSE;
184 }
185
186 g_free (value_casefold);
187
188 /* Check we didn't already disable this miner */
189 for (i = 0; i < disable_options->len; i++) {
190 if (g_array_index (disable_options, gint, i) == option) {
191 found = TRUE;
192 break;
193 }
194 }
195
196 if (!found) {
197 g_array_append_val (disable_options, option);
198 }
199
200 return TRUE;
201 }
202
203 static void
204 sanity_check_option_values (TrackerConfig *config)
205 {
206 g_message ("General options:");
207 g_message (" Verbosity ............................ %d",
208 tracker_config_get_verbosity (config));
209 g_message (" Sched Idle ........................... %d",
210 tracker_config_get_sched_idle (config));
211 g_message (" Initial Sleep ........................ %d",
212 tracker_config_get_initial_sleep (config));
213
214 g_message ("Indexer options:");
215 g_message (" Throttle level ....................... %d",
216 tracker_config_get_throttle (config));
217 g_message (" Indexing while on battery ............ %s (first time only = %s)",
218 tracker_config_get_index_on_battery (config) ? "yes" : "no",
219 tracker_config_get_index_on_battery_first_time (config) ? "yes" : "no");
220
221 if (tracker_config_get_low_disk_space_limit (config) == -1) {
222 g_message (" Low disk space limit ................. Disabled");
223 } else {
224 g_message (" Low disk space limit ................. %d%%",
225 tracker_config_get_low_disk_space_limit (config));
226 }
227 }
228
229 static void
230 signal_handler (int signo)
231 {
232 static gboolean in_loop = FALSE;
233
234 /* Die if we get re-entrant signals handler calls */
235 if (in_loop) {
236 _exit (EXIT_FAILURE);
237 }
238
239 switch (signo) {
240 case SIGTERM:
241 case SIGINT:
242 in_loop = TRUE;
243 if (main_loop != NULL) {
244 g_main_loop_quit (main_loop);
245 } else {
246 exit (0);
247 }
248 /* Fall through */
249 default:
250 if (g_strsignal (signo)) {
251 g_print ("\n");
252 g_print ("Received signal:%d->'%s'\n",
253 signo,
254 g_strsignal (signo));
255 }
256 break;
257 }
258 }
259
260 static void
261 initialize_signal_handler (void)
262 {
263 #ifndef G_OS_WIN32
264 struct sigaction act;
265 sigset_t empty_mask;
266
267 sigemptyset (&empty_mask);
268 act.sa_handler = signal_handler;
269 act.sa_mask = empty_mask;
270 act.sa_flags = 0;
271
272 sigaction (SIGTERM, &act, NULL);
273 sigaction (SIGINT, &act, NULL);
274 sigaction (SIGHUP, &act, NULL);
275 #endif /* G_OS_WIN32 */
276 }
277
278 static void
279 initialize_priority_and_scheduling (TrackerSchedIdle sched_idle,
280 gboolean first_time_index)
281 {
282 /* Set CPU priority */
283 if (sched_idle == TRACKER_SCHED_IDLE_ALWAYS ||
284 (sched_idle == TRACKER_SCHED_IDLE_FIRST_INDEX && first_time_index)) {
285 tracker_sched_idle ();
286 }
287
288 /* Set disk IO priority and scheduling */
289 tracker_ioprio_init ();
290
291 /* Set process priority:
292 * The nice() function uses attribute "warn_unused_result" and
293 * so complains if we do not check its returned value. But it
294 * seems that since glibc 2.2.4, nice() can return -1 on a
295 * successful call so we have to check value of errno too.
296 * Stupid...
297 */
298
299 g_message ("Setting priority nice level to 19");
300
301 errno = 0;
302 if (nice (19) == -1 && errno != 0) {
303 const gchar *str = g_strerror (errno);
304
305 g_message ("Couldn't set nice value to 19, %s",
306 str ? str : "no error given");
307 }
308 }
309
310 static gboolean
311 should_crawl (TrackerConfig *config,
312 gboolean *forced)
313 {
314 gint crawling_interval;
315
316 crawling_interval = tracker_config_get_crawling_interval (config);
317
318 g_message ("Checking whether to crawl file system based on configured crawling interval:");
319
320 if (crawling_interval == -2) {
321 g_message (" Disabled");
322 return FALSE;
323 } else if (crawling_interval == -1) {
324 g_message (" Maybe (depends on a clean last shutdown)");
325 return TRUE;
326 } else if (crawling_interval == 0) {
327 g_message (" Forced");
328
329 if (forced) {
330 *forced = TRUE;
331 }
332
333 return TRUE;
334 } else {
335 guint64 then, now;
336
337 then = tracker_db_manager_get_last_crawl_done ();
338
339 if (then < 1) {
340 return TRUE;
341 }
342
343 now = (guint64) time (NULL);
344
345 if (now < then + (crawling_interval * SECONDS_PER_DAY)) {
346 g_message (" Postponed");
347 return FALSE;
348 } else {
349 g_message (" (More than) %d days after last crawling, enabled", crawling_interval);
350 return FALSE;
351 }
352 }
353 }
354
355 static gboolean
356 miner_disabled_check (void)
357 {
358 gchar *name = NULL;
359 gchar *name_casefold;
360 gboolean disabled = FALSE;
361 gint i;
362
363 if (!disable_options || disable_options->len < 1) {
364 return FALSE;
365 }
366
367 g_object_get (current_miner->data, "name", &name, NULL);
368
369 if (!name || *name == '\0') {
370 g_warning ("Expected miner to have 'name' property set. "
371 "Can not disable this particular miner as a result...");
372 return FALSE;
373 }
374
375 name_casefold = g_utf8_casefold (name, -1);
376
377 for (i = 0; i < disable_options->len && !disabled; i++) {
378 DisableOption o = (gint) g_array_index (disable_options, gint, i);
379
380 switch (o) {
381 case DISABLE_FILES:
382 disabled = strcmp (name_casefold, OPTION_DISABLE_FILES) == 0;
383 break;
384 case DISABLE_APPLICATIONS:
385 disabled = strcmp (name_casefold, OPTION_DISABLE_APPLICATIONS) == 0;
386 break;
387
388 #ifdef HAVE_MAEMO
389 case DISABLE_USERGUIDES:
390 disabled = strcmp (name_casefold, OPTION_DISABLE_USERGUIDES) == 0;
391 break;
392 #endif /* HAVE_MAEMO */
393
394 default:
395 g_assert_not_reached ();
396 break;
397 }
398 }
399
400 if (disabled) {
401 g_message ("Miner '%s' was disabled on the command line, moving to next...", name);
402 miner_handle_next ();
403 }
404
405 g_free (name_casefold);
406 g_free (name);
407
408 return disabled;
409 }
410
411 static void
412 miner_handle_next (void)
413 {
414 if (finished_miners) {
415 return;
416 }
417
418 if (!current_miner) {
419 current_miner = miners;
420 } else {
421 current_miner = current_miner->next;
422 }
423
424 if (!current_miner) {
425 finished_miners = TRUE;
426
427 g_message ("All miners are now finished");
428
429 /* We're not sticking around for file updates, so stop
430 * the mainloop and exit.
431 */
432 if (no_daemon && main_loop) {
433 g_main_loop_quit (main_loop);
434 }
435
436 return;
437 }
438
439 /* Check disabled miners */
440 if (miner_disabled_check ()) {
441 return;
442 }
443
444 if (!tracker_miner_is_started (current_miner->data)) {
445 g_message ("Starting next miner...");
446 tracker_miner_start (current_miner->data);
447 }
448 }
449
450 static gboolean
451 miner_handle_first_cb (gpointer data)
452 {
453 miners_timeout_id = 0;
454 miner_handle_next ();
455 return FALSE;
456 }
457
458 static void
459 miner_handle_first (TrackerConfig *config,
460 gboolean do_mtime_checking)
461 {
462 gint initial_sleep;
463
464 if (!do_mtime_checking) {
465 g_debug ("Avoiding initial sleep, no mtime check needed");
466 miner_handle_next ();
467 return;
468 }
469
470 /* If requesting to run as no-daemon, start right away */
471 if (no_daemon) {
472 miner_handle_next ();
473 return;
474 }
475
476 /* If no need to initially sleep, start right away */
477 initial_sleep = tracker_config_get_initial_sleep (config);
478
479 if (initial_sleep <= 0) {
480 miner_handle_next ();
481 return;
482 }
483
484 g_debug ("Performing initial sleep of %d seconds",
485 initial_sleep);
486 miners_timeout_id = g_timeout_add_seconds (initial_sleep,
487 miner_handle_first_cb,
488 NULL);
489 }
490
491 static void
492 miner_finished_cb (TrackerMinerFS *fs,
493 gdouble seconds_elapsed,
494 guint total_directories_found,
495 guint total_directories_ignored,
496 guint total_files_found,
497 guint total_files_ignored,
498 gpointer user_data)
499 {
500 tracker_info ("Finished mining in seconds:%f, total directories:%d, total files:%d",
501 seconds_elapsed,
502 total_directories_found,
503 total_files_found);
504
505 if (TRACKER_IS_MINER_FILES (fs) &&
506 tracker_miner_fs_get_initial_crawling (fs)) {
507 tracker_db_manager_set_last_crawl_done (TRUE);
508 }
509
510 miner_handle_next ();
511 }
512
513 static void
514 finalize_miner (TrackerMiner *miner)
515 {
516 g_object_unref (G_OBJECT (miner));
517 }
518
519 static GList *
520 get_dir_children_as_gfiles (const gchar *path)
521 {
522 GList *children = NULL;
523 GDir *dir;
524
525 dir = g_dir_open (path, 0, NULL);
526
527 if (dir) {
528 const gchar *basename;
529
530 while ((basename = g_dir_read_name (dir)) != NULL) {
531 GFile *child;
532 gchar *str;
533
534 str = g_build_filename (path, basename, NULL);
535 child = g_file_new_for_path (str);
536 g_free (str);
537
538 children = g_list_prepend (children, child);
539 }
540
541 g_dir_close (dir);
542 }
543
544 return children;
545 }
546
547 static void
548 dummy_log_handler (const gchar *domain,
549 GLogLevelFlags log_level,
550 const gchar *message,
551 gpointer user_data)
552 {
553 return;
554 }
555
556 static void
557 check_eligible (void)
558 {
559 TrackerConfig *config;
560 GFile *file;
561 GFileInfo *info;
562 GError *error = NULL;
563 gchar *path;
564 guint log_handler_id;
565 gboolean exists = TRUE;
566 gboolean is_dir;
567 gboolean print_dir_check;
568 gboolean print_dir_check_with_content;
569 gboolean print_file_check;
570 gboolean print_monitor_check;
571 gboolean would_index = TRUE;
572 gboolean would_notice = TRUE;
573
574 /* Set log handler for library messages */
575 log_handler_id = g_log_set_handler (NULL,
576 G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL,
577 dummy_log_handler,
578 NULL);
579
580 g_log_set_default_handler (dummy_log_handler, NULL);
581
582 /* Start check */
583 file = g_file_new_for_commandline_arg (eligible);
584 info = g_file_query_info (file,
585 G_FILE_ATTRIBUTE_STANDARD_TYPE,
586 G_FILE_QUERY_INFO_NONE,
587 NULL,
588 &error);
589
590 if (error) {
591 if (error->code == G_IO_ERROR_NOT_FOUND) {
592 exists = FALSE;
593 }
594
595 g_error_free (error);
596 }
597
598 if (info) {
599 is_dir = g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY;
600 g_object_unref (info);
601 } else {
602 /* Assume not a dir */
603 is_dir = FALSE;
604 }
605
606 config = tracker_config_new ();
607 path = g_file_get_path (file);
608
609 if (exists) {
610 if (is_dir) {
611 print_dir_check = TRUE;
612 print_dir_check_with_content = TRUE;
613 print_file_check = FALSE;
614 print_monitor_check = TRUE;
615 } else {
616 print_dir_check = FALSE;
617 print_dir_check_with_content = FALSE;
618 print_file_check = TRUE;
619 print_monitor_check = TRUE;
620 }
621 } else {
622 print_dir_check = TRUE;
623 print_dir_check_with_content = FALSE;
624 print_file_check = TRUE;
625 print_monitor_check = TRUE;
626 }
627
628 g_print (exists ?
629 _("Data object '%s' currently exists") :
630 _("Data object '%s' currently does not exist"),
631 path);
632
633 g_print ("\n");
634
635 if (print_dir_check) {
636 gboolean check;
637
638 check = tracker_miner_files_check_directory (file,
639 tracker_config_get_index_recursive_directories (config),
640 tracker_config_get_index_single_directories (config),
641 tracker_config_get_ignored_directory_paths (config),
642 tracker_config_get_ignored_directory_patterns (config));
643 g_print (" %s\n",
644 check ?
645 _("Directory is eligible to be mined (based on rules)") :
646 _("Directory is NOT eligible to be mined (based on rules)"));
647
648 would_index &= check;
649 }
650
651 if (print_dir_check_with_content) {
652 GList *children;
653 gboolean check;
654
655 children = get_dir_children_as_gfiles (path);
656
657 check = tracker_miner_files_check_directory_contents (file,
658 children,
659 tracker_config_get_ignored_directories_with_content (config));
660
661 g_list_foreach (children, (GFunc) g_object_unref, NULL);
662 g_list_free (children);
663
664 g_print (" %s\n",
665 check ?
666 _("Directory is eligible to be mined (based on contents)") :
667 _("Directory is NOT eligible to be mined (based on contents)"));
668
669 would_index &= check;
670 }
671
672 if (print_monitor_check) {
673 gboolean check = TRUE;
674
675 check &= tracker_config_get_enable_monitors (config);
676
677 if (check) {
678 GSList *dirs_to_check, *l;
679 gboolean is_covered_single;
680 gboolean is_covered_recursive;
681
682 is_covered_single = FALSE;
683 dirs_to_check = tracker_config_get_index_single_directories (config);
684
685 for (l = dirs_to_check; l && !is_covered_single; l = l->next) {
686 GFile *dir;
687 GFile *parent;
688
689 parent = g_file_get_parent (file);
690 dir = g_file_new_for_path (l->data);
691 is_covered_single = g_file_equal (parent, dir) || g_file_equal (file, dir);
692
693 g_object_unref (dir);
694 g_object_unref (parent);
695 }
696
697 is_covered_recursive = FALSE;
698 dirs_to_check = tracker_config_get_index_recursive_directories (config);
699
700 for (l = dirs_to_check; l && !is_covered_recursive; l = l->next) {
701 GFile *dir;
702
703 dir = g_file_new_for_path (l->data);
704 is_covered_recursive = g_file_has_prefix (file, dir) || g_file_equal (file, dir);
705 g_object_unref (dir);
706 }
707
708 check &= is_covered_single || is_covered_recursive;
709 }
710
711 if (exists && is_dir) {
712 g_print (" %s\n",
713 check ?
714 _("Directory is eligible to be monitored (based on config)") :
715 _("Directory is NOT eligible to be monitored (based on config)"));
716 } else if (exists && !is_dir) {
717 g_print (" %s\n",
718 check ?
719 _("File is eligible to be monitored (based on config)") :
720 _("File is NOT eligible to be monitored (based on config)"));
721 } else {
722 g_print (" %s\n",
723 check ?
724 _("File or Directory is eligible to be monitored (based on config)") :
725 _("File or Directory is NOT eligible to be monitored (based on config)"));
726 }
727
728 would_notice &= check;
729 }
730
731 if (print_file_check) {
732 gboolean check;
733
734 check = tracker_miner_files_check_file (file,
735 tracker_config_get_ignored_file_paths (config),
736 tracker_config_get_ignored_file_patterns (config));
737
738 g_print (" %s\n",
739 check ?
740 _("File is eligible to be mined (based on rules)") :
741 _("File is NOT eligible to be mined (based on rules)"));
742
743 would_index &= check;
744 }
745
746 g_print ("\n"
747 "%s: %s\n"
748 "%s: %s\n"
749 "\n",
750 _("Would be indexed"),
751 would_index ? _("Yes") : _("No"),
752 _("Would be monitored"),
753 would_notice ? _("Yes") : _("No"));
754
755 if (log_handler_id != 0) {
756 /* Unset log handler */
757 g_log_remove_handler (NULL, log_handler_id);
758 }
759
760 g_free (path);
761 g_object_unref (config);
762 g_object_unref (file);
763 }
764
765 static gboolean
766 store_is_available (void)
767 {
768 GDBusConnection *connection;
769 GDBusProxy *proxy;
770 gchar *name_owner;
771
772 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
773
774 if (!connection) {
775 return FALSE;
776 }
777
778 proxy = g_dbus_proxy_new_sync (connection,
779 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
780 NULL,
781 "org.freedesktop.Tracker1",
782 "/org/freedesktop/Tracker1/Status",
783 "org.freedesktop.Tracker1.Status",
784 NULL, NULL);
785
786 if (!proxy) {
787 g_object_unref (connection);
788 return FALSE;
789 }
790
791 name_owner = g_dbus_proxy_get_name_owner (proxy);
792
793 g_object_unref (connection);
794 g_object_unref (proxy);
795
796 if (name_owner) {
797 g_free (name_owner);
798 return TRUE;
799 }
800
801 return FALSE;
802 }
803
804 static gboolean
805 miner_needs_check (TrackerMiner *miner,
806 gboolean store_available)
807 {
808 /* Reasons to not mark ourselves as cleanly shutdown include:
809 *
810 * 1. Still crawling or with files to process in our queues.
811 * 2. We crash (out of our control usually anyway).
812 * 3. At least one of the miners is PAUSED, we have
813 * to exclude the situations where the miner is
814 * exclusively paused due to the store not being
815 * available, but the miner is actually done.
816 */
817 if (!tracker_miner_is_paused (miner)) {
818 if (TRACKER_IS_MINER_FS (miner) &&
819 tracker_miner_fs_has_items_to_process (TRACKER_MINER_FS (miner))) {
820 /* There are items left to process */
821 return TRUE;
822 }
823
824 /* FIXME: We currently don't check the applications
825 * miner OR the userguides miner if we are finished
826 * before returning TRUE/FALSE here, should we?
827 */
828
829 /* We consider the miner finished */
830 return FALSE;
831 } else {
832 if (store_available) {
833 /* Paused for other reasons, so probably not done */
834 return TRUE;
835 } else {
836 /* Check whether there are more pause
837 * reasons than the store being out.
838 */
839 return tracker_miner_get_n_pause_reasons (miner) > 1;
840 }
841 }
842 }
843
844 int
845 main (gint argc, gchar *argv[])
846 {
847 TrackerConfig *config;
848 TrackerMiner *miner_applications, *miner_files;
849 TrackerMinerFilesIndex *miner_files_index;
850 #ifdef HAVE_MAEMO
851 TrackerMiner *miner_userguides;
852 #endif /* HAVE_MAEMO */
853 GOptionContext *context;
854 GError *error = NULL;
855 gchar *log_filename = NULL;
856 gboolean do_mtime_checking;
857 gboolean do_crawling;
858 gboolean force_mtime_checking = FALSE;
859 gboolean store_available;
860
861 main_loop = NULL;
862
863 setlocale (LC_ALL, "");
864
865 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
866 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
867 textdomain (GETTEXT_PACKAGE);
868
869 /* Set timezone info */
870 tzset ();
871
872 /* Translators: this messagge will apper immediately after the
873 * usage string - Usage: COMMAND <THIS_MESSAGE>
874 */
875 context = g_option_context_new (_("- start the tracker indexer"));
876
877 disable_options = g_array_new (FALSE, FALSE, sizeof (gint));
878 g_option_context_add_main_entries (context, entries, NULL);
879 g_option_context_parse (context, &argc, &argv, &error);
880 g_option_context_free (context);
881
882 if (error) {
883 g_printerr ("%s\n", error->message);
884 g_error_free (error);
885 g_array_free (disable_options, TRUE);
886 return EXIT_FAILURE;
887 }
888
889 if (version) {
890 g_print ("\n" ABOUT "\n" LICENSE "\n");
891 g_array_free (disable_options, TRUE);
892 return EXIT_SUCCESS;
893 }
894
895 if (eligible) {
896 check_eligible ();
897 g_array_free (disable_options, TRUE);
898 return EXIT_SUCCESS;
899 }
900
901 initialize_signal_handler ();
902
903 /* Initialize logging */
904 config = tracker_config_new ();
905
906 if (verbosity > -1) {
907 tracker_config_set_verbosity (config, verbosity);
908 }
909
910 if (initial_sleep > -1) {
911 tracker_config_set_initial_sleep (config, initial_sleep);
912 }
913
914 tracker_log_init (tracker_config_get_verbosity (config),
915 &log_filename);
916 if (log_filename) {
917 g_message ("Using log file:'%s'", log_filename);
918 g_free (log_filename);
919 }
920
921 sanity_check_option_values (config);
922
923 /* This makes sure we don't steal all the system's resources */
924 initialize_priority_and_scheduling (tracker_config_get_sched_idle (config),
925 tracker_db_manager_get_first_index_done () == FALSE);
926
927 main_loop = g_main_loop_new (NULL, FALSE);
928
929 g_message ("Checking if we're running as a daemon:");
930 g_message (" %s %s",
931 no_daemon ? "No" : "Yes",
932 no_daemon ? "(forced by command line)" : "");
933
934 /* Create new TrackerMinerFiles object */
935 miner_files = tracker_miner_files_new (config, &error);
936 if (!miner_files) {
937 g_critical ("Couldn't create new Files miner: '%s'",
938 error ? error->message : "unknown error");
939 g_object_unref (config);
940 tracker_log_shutdown ();
941 g_array_free (disable_options, TRUE);
942 return EXIT_FAILURE;
943 }
944
945 tracker_writeback_init (TRACKER_MINER_FILES (miner_files),
946 config,
947 &error);
948
949 if (error) {
950 g_critical ("Couldn't create writeback handling: '%s'",
951 error ? error->message : "unknown error");
952 g_object_unref (config);
953 g_object_unref (miner_files);
954 tracker_log_shutdown ();
955 g_array_free (disable_options, TRUE);
956 return EXIT_FAILURE;
957 }
958
959 /* Create miner for applications */
960 miner_applications = tracker_miner_applications_new (&error);
961 if (!miner_applications) {
962 g_critical ("Couldn't create new Applications miner: '%s'",
963 error ? error->message : "unknown error");
964 g_object_unref (miner_files);
965 tracker_writeback_shutdown ();
966 g_object_unref (config);
967 tracker_log_shutdown ();
968 g_array_free (disable_options, TRUE);
969 return EXIT_FAILURE;
970 }
971
972 /* Create new TrackerMinerFilesIndex object */
973 miner_files_index = tracker_miner_files_index_new (TRACKER_MINER_FILES (miner_files));
974 if (!miner_files_index) {
975 g_object_unref (miner_applications);
976 g_object_unref (miner_files);
977 tracker_writeback_shutdown ();
978 g_object_unref (config);
979 tracker_log_shutdown ();
980 g_array_free (disable_options, TRUE);
981 return EXIT_FAILURE;
982 }
983
984 #ifdef HAVE_MAEMO
985 /* Create miner for userguides */
986 miner_userguides = tracker_miner_userguides_new (&error);
987 if (!miner_userguides) {
988 g_critical ("Couldn't create new User Guides miner: '%s'",
989 error ? error->message : "unknown error");
990 g_object_unref (miner_applications);
991 g_object_unref (miner_files);
992 g_object_unref (miner_files_index);
993 tracker_writeback_shutdown ();
994 g_object_unref (config);
995 tracker_log_shutdown ();
996 g_array_free (disable_options, TRUE);
997 return EXIT_FAILURE;
998 }
999 #endif /* HAVE_MAEMO */
1000
1001 /* Check if we should crawl and if we should force mtime
1002 * checking based on the config.
1003 */
1004 do_crawling = should_crawl (config, &force_mtime_checking);
1005
1006 /* Get the last shutdown state to see if we need to perform a
1007 * full mtime check against the db or not.
1008 *
1009 * Set to TRUE here in case we crash and miss file system
1010 * events.
1011 */
1012 g_message ("Checking whether to force mtime checking during crawling (based on last clean shutdown):");
1013
1014 /* Override the shutdown state decision based on the config */
1015 if (force_mtime_checking) {
1016 do_mtime_checking = TRUE;
1017 } else {
1018 do_mtime_checking = tracker_db_manager_get_need_mtime_check ();
1019 }
1020
1021 g_message (" %s %s",
1022 do_mtime_checking ? "Yes" : "No",
1023 force_mtime_checking ? "(forced from config)" : "");
1024
1025 /* Set the need for an mtime check to TRUE so we check in the
1026 * event of a crash, this is changed back on shutdown if
1027 * everything appears to be fine.
1028 */
1029 tracker_db_manager_set_need_mtime_check (TRUE);
1030
1031 /* Configure files miner */
1032 tracker_miner_fs_set_initial_crawling (TRACKER_MINER_FS (miner_files), do_crawling);
1033 tracker_miner_fs_set_mtime_checking (TRACKER_MINER_FS (miner_files), do_mtime_checking);
1034 g_signal_connect (miner_files, "finished",
1035 G_CALLBACK (miner_finished_cb),
1036 NULL);
1037
1038 /* Configure applications miner */
1039 tracker_miner_fs_set_initial_crawling (TRACKER_MINER_FS (miner_applications), do_crawling);
1040
1041 #ifdef HAVE_MAEMO
1042 /* Configure userguides miner */
1043 tracker_miner_fs_set_initial_crawling (TRACKER_MINER_FS (miner_userguides), do_crawling);
1044 #endif /* HAVE_MAEMO */
1045
1046 /* If a locale change was detected, always do mtime checks */
1047 if (tracker_miner_applications_detect_locale_changed (miner_applications)) {
1048 if (!do_mtime_checking)
1049 g_debug ("Forcing mtime check in applications miner as locale change was detected");
1050 tracker_miner_fs_set_mtime_checking (TRACKER_MINER_FS (miner_applications), TRUE);
1051 } else {
1052 tracker_miner_fs_set_mtime_checking (TRACKER_MINER_FS (miner_applications), do_mtime_checking);
1053 }
1054
1055
1056 #ifdef HAVE_MAEMO
1057 /* If a locale change was detected, always do mtime checks */
1058 if (tracker_miner_userguides_detect_locale_changed (miner_userguides)) {
1059 if (!do_mtime_checking)
1060 g_debug ("Forcing mtime check in userguides miner as locale change was detected");
1061 tracker_miner_fs_set_mtime_checking (TRACKER_MINER_FS (miner_userguides), TRUE);
1062 } else {
1063 tracker_miner_fs_set_mtime_checking (TRACKER_MINER_FS (miner_userguides), do_mtime_checking);
1064 }
1065 #endif /* HAVE_MAEMO */
1066
1067 g_signal_connect (miner_applications, "finished",
1068 G_CALLBACK (miner_finished_cb),
1069 NULL);
1070
1071 #ifdef HAVE_MAEMO
1072 g_signal_connect (miner_userguides, "finished",
1073 G_CALLBACK (miner_finished_cb),
1074 NULL);
1075 #endif /* HAVE_MAEMO */
1076
1077 /* Setup miners, applications first in list */
1078 #ifdef HAVE_MAEMO
1079 miners = g_slist_prepend (miners, miner_userguides);
1080 #endif /* HAVE_MAEMO */
1081
1082 miners = g_slist_prepend (miners, miner_files);
1083 miners = g_slist_prepend (miners, miner_applications);
1084
1085 tracker_thumbnailer_init ();
1086
1087 miner_handle_first (config, do_mtime_checking);
1088
1089 /* Go, go, go! */
1090 g_main_loop_run (main_loop);
1091
1092 g_message ("Shutdown started");
1093
1094 store_available = store_is_available ();
1095
1096 if (miners_timeout_id == 0 &&
1097 !miner_needs_check (miner_files, store_available) &&
1098 #ifdef HAVE_MAEMO
1099 !miner_needs_check (miner_userguides, store_available) &&
1100 #endif
1101 !miner_needs_check (miner_applications, store_available)) {
1102 tracker_db_manager_set_need_mtime_check (FALSE);
1103 }
1104
1105 g_main_loop_unref (main_loop);
1106 g_object_unref (config);
1107 g_object_unref (miner_files_index);
1108
1109 tracker_thumbnailer_shutdown ();
1110
1111 g_slist_foreach (miners, (GFunc) finalize_miner, NULL);
1112 g_slist_free (miners);
1113
1114 tracker_writeback_shutdown ();
1115 tracker_log_shutdown ();
1116
1117 g_array_free (disable_options, TRUE);
1118
1119 g_print ("\nOK\n\n");
1120
1121 return EXIT_SUCCESS;
1122 }