[tracker/tracker-cmd: 2/10] tracker: Merge tracker-control into a 'tracker' command
- From: Martyn James Russell <mr src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/tracker-cmd: 2/10] tracker: Merge tracker-control into a 'tracker' command
- Date: Mon, 6 Oct 2014 13:19:57 +0000 (UTC)
commit 7cd94a533473ba0d50af249a979e25cb6382a4a5
Author: Martyn Russell <martyn lanedo com>
Date: Wed Oct 1 12:38:45 2014 +0100
tracker: Merge tracker-control into a 'tracker' command
configure.ac | 18 +-
docs/manpages/Makefile.am | 4 +-
.../{tracker-control.1 => tracker-daemon.1} | 60 +-
docs/manpages/tracker-index.1 | 28 +
docs/manpages/tracker-reset.1 | 35 +
docs/manpages/tracker-search.1 | 10 +-
docs/manpages/tracker-sparql.1 | 11 +-
docs/manpages/tracker-stats.1 | 8 +-
docs/manpages/tracker-tag.1 | 12 +-
src/Makefile.am | 5 +-
src/tracker-control/.gitignore | 1 -
src/tracker-control/Makefile.am | 24 -
src/tracker-control/tracker-control-general.c | 1383 -------------
src/tracker-control/tracker-control-miners.c | 501 -----
src/tracker-control/tracker-control-status.c | 1051 ----------
src/tracker-utils/Makefile.am | 40 -
src/{tracker-utils => tracker}/.gitignore | 2 +
src/tracker/Makefile.am | 68 +
src/tracker/tracker-config.c | 202 ++
src/tracker/tracker-config.h | 37 +
src/tracker/tracker-control-general.c | 161 ++
src/tracker/tracker-control-miners.c | 128 ++
src/{tracker-control => tracker}/tracker-control.c | 0
src/{tracker-control => tracker}/tracker-control.h | 0
src/tracker/tracker-daemon.c | 2108 ++++++++++++++++++++
src/tracker/tracker-daemon.h | 30 +
src/{tracker-utils => tracker}/tracker-import.c | 0
src/tracker/tracker-index.c | 166 ++
src/tracker/tracker-index.h | 30 +
src/{tracker-utils => tracker}/tracker-info.c | 0
src/tracker/tracker-main.c | 367 ++++
src/tracker/tracker-process.c | 305 +++
src/tracker/tracker-process.h | 48 +
src/tracker/tracker-reset.c | 305 +++
src/tracker/tracker-reset.h | 30 +
src/{tracker-utils => tracker}/tracker-search.c | 0
src/{tracker-utils => tracker}/tracker-sparql.c | 0
src/{tracker-utils => tracker}/tracker-stats.c | 0
src/{tracker-utils => tracker}/tracker-tag.c | 0
39 files changed, 4075 insertions(+), 3103 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 22413a5..380fd68 100644
--- a/configure.ac
+++ b/configure.ac
@@ -323,12 +323,13 @@ LIBTRACKER_SPARQL_REQUIRED="glib-2.0 >= $GLIB_REQUIRED
PKG_CHECK_MODULES(LIBTRACKER_SPARQL, [$LIBTRACKER_SPARQL_REQUIRED])
# Check requirements for tracker-control
-TRACKER_CONTROL_REQUIRED="glib-2.0 >= $GLIB_REQUIRED
- gio-unix-2.0 >= $GLIB_REQUIRED
- uuid"
+TRACKER_REQUIRED="glib-2.0 >= $GLIB_REQUIRED
+ gio-unix-2.0 >= $GLIB_REQUIRED
+ uuid"
-PKG_CHECK_MODULES(TRACKER_CONTROL, [$TRACKER_CONTROL_REQUIRED])
+PKG_CHECK_MODULES(TRACKER, [$TRACKER_REQUIRED])
+# Check requirements for tracker-resdump
TRACKER_RESDUMP_REQUIRED="glib-2.0 >= $GLIB_REQUIRED
gee-0.8 >= $GEE_REQUIRED"
@@ -504,12 +505,6 @@ PKG_CHECK_MODULES(TRACKER_MINER_RSS, [$TRACKER_MINER_RSS_REQUIRED],
[have_tracker_miner_rss=yes],
[have_tracker_miner_rss=no])
-# Check requirements for tracker-utils
-TRACKER_UTILS_REQUIRED="glib-2.0 >= $GLIB_REQUIRED
- gio-unix-2.0 >= $GLIB_REQUIRED"
-
-PKG_CHECK_MODULES(TRACKER_UTILS, [$TRACKER_UTILS_REQUIRED])
-
# Check requirements for tracker-needle
TRACKER_NEEDLE_REQUIRED="glib-2.0 >= $GLIB_REQUIRED
gio-unix-2.0 >= $GLIB_REQUIRED
@@ -2605,13 +2600,12 @@ AC_CONFIG_FILES([
src/miners/rss/Makefile
src/miners/user-guides/Makefile
src/tracker-store/Makefile
- src/tracker-control/Makefile
+ src/tracker/Makefile
src/tracker-extract/Makefile
src/tracker-preferences/Makefile
src/tracker-preferences/tracker-preferences.desktop.in
src/tracker-needle/Makefile
src/tracker-needle/tracker-needle.desktop.in
- src/tracker-utils/Makefile
src/tracker-writeback/Makefile
src/plugins/Makefile
src/plugins/evolution/Makefile
diff --git a/docs/manpages/Makefile.am b/docs/manpages/Makefile.am
index 8cbb71d..be307cb 100644
--- a/docs/manpages/Makefile.am
+++ b/docs/manpages/Makefile.am
@@ -7,12 +7,14 @@ common = \
tracker-import.1 \
tracker-info.1 \
tracker-miner-fs.1 \
- tracker-control.1 \
+ tracker-daemon.1 \
tracker-search.1 \
tracker-sparql.1 \
tracker-stats.1 \
tracker-store.1 \
tracker-tag.1 \
+ tracker-reset.1 \
+ tracker-index.1 \
tracker-writeback.1
# Require only common and enabled manpages
diff --git a/docs/manpages/tracker-control.1 b/docs/manpages/tracker-daemon.1
similarity index 80%
rename from docs/manpages/tracker-control.1
rename to docs/manpages/tracker-daemon.1
index 76ea639..300f4e4 100644
--- a/docs/manpages/tracker-control.1
+++ b/docs/manpages/tracker-daemon.1
@@ -1,14 +1,13 @@
-.TH tracker-control 1 "September 2009" GNU "User Commands"
+.TH tracker-daemon 1 "September 2014" GNU "User Commands"
.SH NAME
-tracker-control \- Manage Tracker processes and data
+tracker-daemon \- Start, stop, restart and list daemons responsible for indexing content
.SH SYNOPSIS
-\fBtracker-control\fR [\fIOPTION\fR...]
+\fBtracker daemon\fR [\fIOPTION\fR...]
.SH DESCRIPTION
-.B tracker-control
-manages and checks status of all Tracker processes and data.
+.B Manages and checks status of all Tracker processes and data.
Controls Tracker both at process level, and at entity level (store, miners).
@@ -28,18 +27,7 @@ load from applications or miners). For a list of common statuses, see
The miners can be paused or resumed using this command and you can
also list miners running and available.
-.SH COMMON OPTIONS
-.TP
-.B \-?, \-\-help
-Show summary of options by group.
-.TP
-.B \-?, \-\-help-all
-Show all groups and options.
-.TP
-.B \-V, \-\-version
-Returns the version of this program.
-
-.SH GENERAL OPTIONS
+.SH OPTIONS
.TP
.B \-p, \-\-list\-processes
This lists all Tracker processes in the system.
@@ -60,27 +48,6 @@ parameter, if no extra parameter is passed,
will be assumed. This is recommended over \-\-kill because it gives
the processes time to shutdown cleanly.
.TP
-.B \-r, \-\-hard-reset
-This kills all processes in the same way that
-.B \-\-kill
-does but it also removes all databases. Restarting
-.B tracker-store
-re-creates the databases.
-.TP
-.B \-e, \-\-soft-reset
-A soft reset works exactly the same way that
-.B \-\-hard-reset
-does, with the exception that the backup and journal are not removed.
-These are restored when
-.B tracker-store
-is restarted.
-.TP
-.B \-c, \-\-remove-config
-This removes all config files in $HOME/.config/tracker. All files
-listed are files which were found and successfully removed.
-Restarting the respective processes re-creates the default
-configuration files.
-.TP
.B \-s, \-\-start
Starts all miners. This indirectly starts tracker-store too because it
is needed for miners to operate properly.
@@ -116,8 +83,6 @@ size of the databases on the disk, the configuration in use, states of
the index (e.g. last filesystem crawl, data set locale, etc.) and
finally statistics about the data in the database (e.g. how many
nfo:FileDataObject resources exist).
-
-.SH STATUS OPTIONS
.TP
.B \-S, \-\-status
Show the current status of all Tracker entities (store and all available
@@ -166,23 +131,10 @@ static and are subject to change at any point.
Additionally, these statuses are not the only ones which may be
reported by a miner. There may be other states pertaining to the
specific roles of the miner in question.
-
-.SH MINER OPTIONS
-.TP
-.B \-m, \-\-reindex-mime-type=MIME
-Re-index files which match the \fIMIME\fR type supplied. This is
-usually used when installing new extractors which support \fIMIME\fR
-types previously unsupported. This forces Tracker to re-index those
-files. You can use
-.B \-\-reindex-mime-type
-more than once per \fIMIME\fR type.
-.TP
-.B \-f, \-\-index-file=FILE
-(Re)index a file matching the \fIFILE\fR type supplied.
.TP
.B \-\-list-miners-running
This will list all miners which have responded to a D-Bus call.
-Sometimes it is helpfult to use this command with
+Sometimes it is helpful to use this command with
.B \-\-list-miners-available.
.TP
.B \-\-list-miners-available
diff --git a/docs/manpages/tracker-index.1 b/docs/manpages/tracker-index.1
new file mode 100644
index 0000000..d8f8718
--- /dev/null
+++ b/docs/manpages/tracker-index.1
@@ -0,0 +1,28 @@
+.TH tracker-control 1 "September 2009" GNU "User Commands"
+
+.SH NAME
+tracker-index \- List, pause, resume and command data miners indexing content
+
+.SH SYNOPSIS
+\fBtracker index\fR [\fIOPTION\fR...]
+
+.SH DESCRIPTION
+Control the indexing process with pausing and resuming and add content
+to be indexed. In addition it is possible to reindex entire MIME
+types, which may be useful in cases where a new extractor or GStreamer
+backend is available and providing support.
+.SH OPTIONS
+.TP
+.B \-m, \-\-reindex-mime-type=MIME
+Re-index files which match the \fIMIME\fR type supplied. This is
+usually used when installing new extractors which support \fIMIME\fR
+types previously unsupported. This forces Tracker to re-index those
+files. You can use
+.B \-\-reindex-mime-type
+more than once per \fIMIME\fR type.
+.TP
+.B \-f, \-\-index-file=FILE
+(Re)index a file matching the \fIFILE\fR type supplied.
+
+.SH SEE ALSO
+.BR tracker (1).
diff --git a/docs/manpages/tracker-reset.1 b/docs/manpages/tracker-reset.1
new file mode 100644
index 0000000..c1c5824
--- /dev/null
+++ b/docs/manpages/tracker-reset.1
@@ -0,0 +1,35 @@
+.TH tracker-reset 1 "September 2014" GNU "User Commands"
+
+.SH NAME
+tracker-reset \- Reset the index, configuration or replay journal
+
+.SH SYNOPSIS
+\fBtracker reset\fR [\fIOPTION\fR...]
+
+.SH DESCRIPTION
+
+.SH OPTIONS
+.TP
+.B \-r, \-\-hard-reset
+This kills all processes in the same way that
+.B \-\-kill
+does but it also removes all databases. Restarting
+.B tracker-store
+re-creates the databases.
+.TP
+.B \-e, \-\-soft-reset
+A soft reset works exactly the same way that
+.B \-\-hard-reset
+does, with the exception that the backup and journal are not removed.
+These are restored when
+.B tracker-store
+is restarted.
+.TP
+.B \-c, \-\-remove-config
+This removes all config files in $HOME/.config/tracker. All files
+listed are files which were found and successfully removed.
+Restarting the respective processes re-creates the default
+configuration files.
+
+.SH SEE ALSO
+.BR tracker (1).
diff --git a/docs/manpages/tracker-search.1 b/docs/manpages/tracker-search.1
index d0b6604..3287865 100644
--- a/docs/manpages/tracker-search.1
+++ b/docs/manpages/tracker-search.1
@@ -4,10 +4,10 @@
tracker-search \- Search all content for keywords
.SH SYNOPSIS
-\fBtracker-search\fR [\fIOPTION\fR...] \fIEXPRESSION\fR [\fIEXPRESSION\fR...]
+\fBtracker search\fR [\fIOPTION\fR...] \fIEXPRESSION\fR [\fIEXPRESSION\fR...]
.SH DESCRIPTION
-.B tracker-search
+.B tracker search
searches all indexed content for \fIEXPRESSION\fR. The resource in
which \fIEXPRESSION\fR matches must exist (see
.B \-\-all
@@ -22,9 +22,6 @@ For logical OR operations, see -r.
.SH OPTIONS
.TP
-.B \-?, \-\-help-all
-Display all help options available.
-.TP
.B \-l, \-\-limit=N
Limit search to N results. The default is 10 or 512 with \-\-disable\-snippets.
.TP
@@ -115,9 +112,6 @@ of those found.
.B \-b, \-\-bookmarks
Search through bookmarks matching \fIEXPRESSION\fR (optional). Returns a list
titles and links for each bookmark found.
-.TP
-.B \-V, \-\-version
-Print version.
.SH ENVIRONMENT
.TP
diff --git a/docs/manpages/tracker-sparql.1 b/docs/manpages/tracker-sparql.1
index cd50525..9435928 100644
--- a/docs/manpages/tracker-sparql.1
+++ b/docs/manpages/tracker-sparql.1
@@ -4,10 +4,10 @@
tracker-sparql \- Use SparQL to query the Tracker databases.
.SH SYNOPSIS
-\fBtracker-sparql\fR [\fIOPTION\fR...] [-q \fIQUERY\fR] | [-f \fIFILE\fR]
+\fBtracker sparql\fR [\fIOPTION\fR...] [-q \fIQUERY\fR] | [-f \fIFILE\fR]
.SH DESCRIPTION
-.B tracker-sparql
+.B tracker sparql
allows the caller to run an RDF query on the database. This can be
done two ways. Either by providing a \fIFILE\fR with the query or by
providing a string with the \fIQUERY\fR string.
@@ -17,9 +17,6 @@ does not have to be an absolute path.
.SH OPTIONS
.TP
-.B \-?, \-\-help
-Show summary of options.
-.TP
.B \-f, \-\-file=FILE
Use a \fIFILE\fR with SPARQL content to query or update.
.TP
@@ -220,10 +217,6 @@ $ tracker-sparql --get-longhand nmm:MusicPiece
http://www.tracker-project.org/temp/nmm#MusicPiece
.fi
-.TP
-.B \-V, \-\-version
-Print version.
-
.SH ENVIRONMENT
.TP
.B TRACKER_SPARQL_BACKEND
diff --git a/docs/manpages/tracker-stats.1 b/docs/manpages/tracker-stats.1
index a3ace16..26bf918 100644
--- a/docs/manpages/tracker-stats.1
+++ b/docs/manpages/tracker-stats.1
@@ -4,7 +4,7 @@
tracker-stats \- Provides statistics on the data indexed
.SH SYNOPSIS
-\fBtracker-stats\fR [\fIOPTION\fR...] [[\fIEXPRESSION\fR...] [\fIEXPRESSION\fR...]]
+\fBtracker stats\fR [\fIOPTION\fR...] [[\fIEXPRESSION\fR...] [\fIEXPRESSION\fR...]]
.SH DESCRIPTION
Display statistics about RDF classes in and how many of each exist for
@@ -29,9 +29,6 @@ with
.SH OPTIONS
.TP
-.B \-h, \-\-help
-Show a brief help message.
-.TP
.B \-a, \-\-all
Display statistics about ALL RDF classes that exist in the database.
Without this option only the common RDF classes will be shown, for
@@ -39,9 +36,6 @@ example nfo:Document and nfo:FileDataObject.
This option is implied if search terms are provided to filter ALL
possible statistics.
-.TP
-.B \-V, \-\-version
-Print version.
.SH SEE ALSO
.BR tracker-store (1),
diff --git a/docs/manpages/tracker-tag.1 b/docs/manpages/tracker-tag.1
index 8b7b8d3..9e85f16 100644
--- a/docs/manpages/tracker-tag.1
+++ b/docs/manpages/tracker-tag.1
@@ -4,13 +4,13 @@
tracker-tag \- Add, remove and list tags.
.SH SYNOPSIS
-\fBtracker-tag\fR [\fIOPTION...\fR] FILE [\fIFILE...\fR]
+\fBtracker tag\fR [\fIOPTION...\fR] FILE [\fIFILE...\fR]
.nf
-\fBtracker-tag\fR [\fIOPTION...\fR] -t [[\fITAG\fR] [\fITAG\fR] ...\fR]
+\fBtracker tag\fR [\fIOPTION...\fR] -t [[\fITAG\fR] [\fITAG\fR] ...\fR]
.fi
.SH DESCRIPTION
-.B tracker-tag
+.B tracker tag
allows the caller add tags, remove tags and list tags by URN or to
list all tags and the files associated with them.
@@ -19,9 +19,6 @@ does not have to be an absolute path.
.SH OPTIONS
.TP
-.B \-?, \-\-help
-Show summary of options.
-.TP
.B \-l, \-\-limit=N
Limit search to N results. The default is 512.
.TP
@@ -80,9 +77,6 @@ This option ONLY applies when using
.B \-\-add
and provides a description to go with the tag label according to
\fISTRING\fR.
-.TP
-.B \-V, \-\-version
-Print version.
.SH ENVIRONMENT
.TP
diff --git a/src/Makefile.am b/src/Makefile.am
index ee76d8c..43a8c7d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -15,11 +15,10 @@ SUBDIRS = \
libtracker-extract \
libtracker-miner \
libtracker-control \
+ tracker \
miners \
plugins \
- tracker-store \
- tracker-control \
- tracker-utils
+ tracker-store
if HAVE_TRACKER_EXTRACT
SUBDIRS += tracker-extract
diff --git a/src/tracker-utils/.gitignore b/src/tracker/.gitignore
similarity index 82%
rename from src/tracker-utils/.gitignore
rename to src/tracker/.gitignore
index ff2faef..5f94367 100644
--- a/src/tracker-utils/.gitignore
+++ b/src/tracker/.gitignore
@@ -6,3 +6,5 @@ tracker-sparql
tracker-stats
tracker-status
tracker-tag
+tracker-control
+tracker
diff --git a/src/tracker/Makefile.am b/src/tracker/Makefile.am
new file mode 100644
index 0000000..0af7c90
--- /dev/null
+++ b/src/tracker/Makefile.am
@@ -0,0 +1,68 @@
+AM_CPPFLAGS = \
+ $(BUILD_CFLAGS) \
+ -DLOCALEDIR=\""$(localedir)"\" \
+ -DMANDIR=\""$(mandir)"\" \
+ -DTRACKER_EXTRACTOR_RULES_DIR=\""$(TRACKER_EXTRACT_RULES_DIR)"\" \
+ -I$(top_srcdir)/src \
+ -I$(top_builddir)/src \
+ $(TRACKER_CFLAGS)
+
+libs = \
+ $(top_builddir)/src/libtracker-sparql-backend/libtracker-sparql- TRACKER_API_VERSION@.la \
+ $(top_builddir)/src/libtracker-miner/libtracker-miner- TRACKER_API_VERSION@.la \
+ $(top_builddir)/src/libtracker-common/libtracker-common.la \
+ $(BUILD_LIBS) \
+ $(TRACKER_LIBS)
+
+bin_PROGRAMS = \
+ tracker \
+ tracker-import \
+ tracker-info \
+ tracker-search \
+ tracker-sparql \
+ tracker-stats \
+ tracker-tag
+
+tracker_search_SOURCES = tracker-search.c
+tracker_search_LDADD = $(libs)
+
+tracker_stats_SOURCES = tracker-stats.c
+tracker_stats_LDADD = $(libs)
+
+tracker_tag_SOURCES = tracker-tag.c
+tracker_tag_LDADD = $(libs)
+
+tracker_info_SOURCES = tracker-info.c
+tracker_info_LDADD = $(libs)
+
+tracker_sparql_SOURCES = tracker-sparql.c
+tracker_sparql_LDADD = $(libs)
+
+tracker_import_SOURCES = tracker-import.c
+tracker_import_LDADD = $(libs)
+
+tracker_SOURCES = \
+ tracker-main.c \
+ tracker-config.c \
+ tracker-config.h \
+ tracker-daemon.c \
+ tracker-daemon.h \
+ tracker-dbus.c \
+ tracker-dbus.h \
+ tracker-help.c \
+ tracker-help.h \
+ tracker-index.c \
+ tracker-index.h \
+ tracker-process.c \
+ tracker-process.h \
+ tracker-reset.c \
+ tracker-reset.h
+
+tracker_LDADD = \
+ $(top_builddir)/src/libtracker-control/libtracker-control- TRACKER_API_VERSION@.la \
+ $(top_builddir)/src/libtracker-miner/libtracker-miner- TRACKER_API_VERSION@.la \
+ $(top_builddir)/src/libtracker-sparql-backend/libtracker-sparql- TRACKER_API_VERSION@.la \
+ $(top_builddir)/src/libtracker-data/libtracker-data.la \
+ $(top_builddir)/src/libtracker-common/libtracker-common.la \
+ $(BUILD_LIBS) \
+ $(TRACKER_LIBS)
diff --git a/src/tracker/tracker-config.c b/src/tracker/tracker-config.c
new file mode 100644
index 0000000..d604634
--- /dev/null
+++ b/src/tracker/tracker-config.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2010, Nokia <ivan frade nokia com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <libtracker-common/tracker-common.h>
+#include <libtracker-control/tracker-control.h>
+
+#include "tracker-config.h"
+
+GSList *
+tracker_gsettings_get_all (gint *longest_name_length)
+{
+ typedef struct {
+ const gchar *schema;
+ const gchar *path;
+ } SchemaWithPath;
+
+ TrackerMinerManager *manager;
+ GError *error = NULL;
+ GSettings *settings;
+ GSList *all = NULL;
+ GSList *l;
+ GSList *miners_available;
+ GSList *valid_schemas = NULL;
+ const gchar * const *schema;
+ gint len = 0;
+ SchemaWithPath components[] = {
+ { "Store", "store" },
+ { "Extract", "extract" },
+ { "Writeback", "writeback" },
+ { 0 }
+ };
+ SchemaWithPath *swp;
+
+ /* Don't auto-start the miners here */
+ manager = tracker_miner_manager_new_full (FALSE, &error);
+ if (!manager) {
+ g_printerr (_("Could not get GSettings for miners, manager could not be created, %s"),
+ error ? error->message : _("No error given"));
+ g_printerr ("\n");
+ g_clear_error (&error);
+ return NULL;
+ }
+
+ miners_available = tracker_miner_manager_get_available (manager);
+
+ /* Get valid schemas so we don't try to load invalid ones */
+ for (schema = g_settings_list_schemas (); schema && *schema; schema++) {
+ if (!g_str_has_prefix (*schema, "org.freedesktop.Tracker.")) {
+ continue;
+ }
+
+ valid_schemas = g_slist_prepend (valid_schemas, g_strdup (*schema));
+ }
+
+ /* Store / General */
+ for (swp = components; swp && swp->schema; swp++) {
+ gchar *schema;
+ gchar *path;
+
+ schema = g_strdup_printf ("org.freedesktop.Tracker.%s", swp->schema);
+ path = g_strdup_printf ("/org/freedesktop/tracker/%s/", swp->path);
+
+ /* If miner doesn't have a schema, no point in getting config */
+ if (!tracker_string_in_gslist (schema, valid_schemas)) {
+ g_free (path);
+ g_free (schema);
+ continue;
+ }
+
+ len = MAX (len, strlen (swp->schema));
+
+ settings = g_settings_new_with_path (schema, path);
+ if (settings) {
+ ComponentGSettings *c = g_slice_new (ComponentGSettings);
+
+ c->name = g_strdup (swp->schema);
+ c->settings = settings;
+ c->is_miner = FALSE;
+
+ all = g_slist_prepend (all, c);
+ }
+ }
+
+ /* Miners */
+ for (l = miners_available; l; l = l->next) {
+ const gchar *name;
+ gchar *schema;
+ gchar *name_lowercase;
+ gchar *path;
+ gchar *miner;
+
+ miner = l->data;
+ if (!miner) {
+ continue;
+ }
+
+ name = g_utf8_strrchr (miner, -1, '.');
+ if (!name) {
+ continue;
+ }
+
+ name++;
+ name_lowercase = g_utf8_strdown (name, -1);
+
+ schema = g_strdup_printf ("org.freedesktop.Tracker.Miner.%s", name);
+ path = g_strdup_printf ("/org/freedesktop/tracker/miner/%s/", name_lowercase);
+ g_free (name_lowercase);
+
+ /* If miner doesn't have a schema, no point in getting config */
+ if (!tracker_string_in_gslist (schema, valid_schemas)) {
+ g_free (path);
+ g_free (schema);
+ continue;
+ }
+
+ settings = g_settings_new_with_path (schema, path);
+ g_free (path);
+ g_free (schema);
+
+ if (settings) {
+ ComponentGSettings *c = g_slice_new (ComponentGSettings);
+
+ c->name = g_strdup (name);
+ c->settings = settings;
+ c->is_miner = TRUE;
+
+ all = g_slist_prepend (all, c);
+ len = MAX (len, strlen (name));
+ }
+ }
+
+ g_slist_foreach (valid_schemas, (GFunc) g_free, NULL);
+ g_slist_free (valid_schemas);
+ g_slist_foreach (miners_available, (GFunc) g_free, NULL);
+ g_slist_free (miners_available);
+ g_object_unref (manager);
+
+ if (longest_name_length) {
+ *longest_name_length = len;
+ }
+
+ return g_slist_reverse (all);
+}
+
+gboolean
+tracker_gsettings_set_all (GSList *all,
+ TrackerVerbosity verbosity)
+{
+ GSList *l;
+ gboolean success = TRUE;
+
+ for (l = all; l && success; l = l->next) {
+ ComponentGSettings *c = l->data;
+
+ if (!c) {
+ continue;
+ }
+
+ success &= g_settings_set_enum (c->settings, "verbosity", verbosity);
+ g_settings_apply (c->settings);
+ }
+
+ g_settings_sync ();
+
+ return success;
+}
+
+void
+tracker_gsettings_free (GSList *all)
+{
+ GSList *l;
+
+ /* Clean up */
+ for (l = all; l; l = l->next) {
+ ComponentGSettings *c = l->data;
+
+ g_free (c->name);
+ g_object_unref (c->settings);
+ g_slice_free (ComponentGSettings, c);
+ }
+}
diff --git a/src/tracker/tracker-config.h b/src/tracker/tracker-config.h
new file mode 100644
index 0000000..0a11eb0
--- /dev/null
+++ b/src/tracker/tracker-config.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014, Nokia <ivan frade nokia com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#ifndef __TRACKER_CONFIG_H__
+#define __TRACKER_CONFIG_H__
+
+typedef struct {
+ gchar *name;
+ GSettings *settings;
+ gboolean is_miner;
+} ComponentGSettings;
+
+GSList *tracker_gsettings_get_all (gint *longest_name_length);
+gboolean tracker_gsettings_set_all (GSList *all,
+ TrackerVerbosity verbosity);
+void tracker_gsettings_free (GSList *all);
+
+#endif /* __TRACKER_CONFIG_H__ */
diff --git a/src/tracker/tracker-control-general.c b/src/tracker/tracker-control-general.c
new file mode 100644
index 0000000..685baeb
--- /dev/null
+++ b/src/tracker/tracker-control-general.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2010, Nokia <ivan frade nokia com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#ifdef __sun
+#include <procfs.h>
+#endif
+
+#include <libtracker-common/tracker-common.h>
+#include <libtracker-data/tracker-data.h>
+#include <libtracker-miner/tracker-miner.h>
+#include <libtracker-control/tracker-control.h>
+
+#include "tracker-control.h"
+#include "tracker-dbus.h"
+
+#define OPTION_TERM_ALL "all"
+#define OPTION_TERM_STORE "store"
+#define OPTION_TERM_MINERS "miners"
+
+typedef enum {
+ TERM_NONE,
+ TERM_ALL,
+ TERM_STORE,
+ TERM_MINERS
+} TermOption;
+
+/* Note:
+ * Every time a new option is added, make sure it is considered in the
+ * 'GENERAL_OPTIONS_ENABLED' macro below
+ */
+static gboolean list_processes;
+static TermOption kill_option = TERM_NONE;
+static TermOption terminate_option = TERM_NONE;
+static gboolean hard_reset;
+static gboolean soft_reset;
+static gboolean remove_config;
+static gchar *set_log_verbosity;
+static gboolean get_log_verbosity;
+static gboolean start;
+static gchar *backup;
+static gchar *restore;
+static gboolean collect_debug_info;
+
+#define GENERAL_OPTIONS_ENABLED() \
+ (list_processes || \
+ kill_option != TERM_NONE || \
+ terminate_option != TERM_NONE || \
+ hard_reset || \
+ soft_reset || \
+ remove_config || \
+ get_log_verbosity || \
+ set_log_verbosity || \
+ start || \
+ backup || \
+ restore || \
+ collect_debug_info)
+
+static gboolean term_option_arg_func (const gchar *option_value,
+ const gchar *value,
+ gpointer data,
+ GError **error);
+
+static GOptionEntry entries[] = {
+ { "list-processes", 'p', 0, G_OPTION_ARG_NONE, &list_processes,
+ N_("List all Tracker processes") },
+ { "kill", 'k', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, term_option_arg_func,
+ N_("Use SIGKILL to stop all matching processes, either \"store\", \"miners\" or \"all\" may be
used, no parameter equals \"all\""),
+ N_("APPS") },
+ { "terminate", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, term_option_arg_func,
+ N_("Use SIGTERM to stop all matching processes, either \"store\", \"miners\" or \"all\" may be
used, no parameter equals \"all\""),
+ N_("APPS") },
+ { "hard-reset", 'r', 0, G_OPTION_ARG_NONE, &hard_reset,
+ N_("Kill all Tracker processes and remove all databases"),
+ NULL },
+ { "soft-reset", 'e', 0, G_OPTION_ARG_NONE, &soft_reset,
+ N_("Same as --hard-reset but the backup & journal are restored after restart"),
+ NULL },
+ { "remove-config", 'c', 0, G_OPTION_ARG_NONE, &remove_config,
+ N_("Remove all configuration files so they are re-generated on next start"),
+ NULL },
+ { "start", 's', 0, G_OPTION_ARG_NONE, &start,
+ N_("Starts miners (which indirectly starts tracker-store too)"),
+ NULL },
+ { "backup", 'b', 0, G_OPTION_ARG_FILENAME, &backup,
+ N_("Backup databases to the file provided"),
+ N_("FILE") },
+ { "restore", 'o', 0, G_OPTION_ARG_FILENAME, &restore,
+ N_("Restore databases from the file provided"),
+ N_("FILE") },
+ { "set-log-verbosity", 0, 0, G_OPTION_ARG_STRING, &set_log_verbosity,
+ N_("Sets the logging verbosity to LEVEL ('debug', 'detailed', 'minimal', 'errors') for all
processes"),
+ N_("LEVEL") },
+ { "get-log-verbosity", 0, 0, G_OPTION_ARG_NONE, &get_log_verbosity,
+ N_("Show logging values in terms of log verbosity for each process"),
+ NULL },
+ { "collect-debug-info", 0, 0, G_OPTION_ARG_NONE, &collect_debug_info,
+ N_("Collect debug information useful for problem reporting and investigation, results are output to
terminal"),
+ NULL },
+ { NULL }
+};
+
+gboolean
+tracker_control_general_options_enabled (void)
+{
+ return GENERAL_OPTIONS_ENABLED ();
+}
+
+void
+tracker_control_general_run_default (void)
+{
+ /* Enable list processes in the default run */
+ list_processes = TRUE;
+
+ tracker_control_general_run ();
+}
+
+gint
+tracker_control_general_run (void)
+{
+
+ return EXIT_SUCCESS;
+}
+
+GOptionGroup *
+tracker_control_general_get_option_group (void)
+{
+ GOptionGroup *group;
+
+ /* Status options */
+ group = g_option_group_new ("general",
+ _("General options"),
+ _("Show general options"),
+ NULL,
+ NULL);
+ g_option_group_add_entries (group, entries);
+
+ return group;
+}
diff --git a/src/tracker/tracker-control-miners.c b/src/tracker/tracker-control-miners.c
new file mode 100644
index 0000000..833c6be
--- /dev/null
+++ b/src/tracker/tracker-control-miners.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010 Nokia <ivan frade nokia com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include <libtracker-common/tracker-common.h>
+#include <libtracker-miner/tracker-miner.h>
+#include <libtracker-control/tracker-control.h>
+
+#include "tracker-control.h"
+
+/* Note:
+ * Every time a new option is added, make sure it is considered in the
+ * 'MINERS_OPTIONS_ENABLED' macro below
+ */
+static const gchar **reindex_mime_types;
+static gchar *index_file;
+static gchar *miner_name;
+static gchar *pause_reason;
+static gchar *pause_for_process_reason;
+static gint resume_cookie = -1;
+static gboolean list_miners_running;
+static gboolean list_miners_available;
+static gboolean pause_details;
+
+#define MINERS_OPTIONS_ENABLED() \
+ (reindex_mime_types || \
+ index_file || \
+ miner_name || \
+ pause_reason || \
+ pause_for_process_reason || \
+ resume_cookie != -1 || \
+ list_miners_running || \
+ list_miners_available || \
+ pause_details)
+
+static GOptionEntry entries[] = {
+ { "reindex-mime-type", 'm', 0, G_OPTION_ARG_STRING_ARRAY, &reindex_mime_types,
+ N_("Tell miners to reindex files which match the mime type supplied (for new extractors), use -m
MIME1 -m MIME2"),
+ N_("MIME") },
+ { "index-file", 'f', 0, G_OPTION_ARG_FILENAME, &index_file,
+ N_("Tell miners to (re)index a given file"),
+ N_("FILE") },
+ { "pause", 0 , 0, G_OPTION_ARG_STRING, &pause_reason,
+ N_("Pause a miner (you must use this with --miner)"),
+ N_("REASON")
+ },
+ { "pause-for-process", 0 , 0, G_OPTION_ARG_STRING, &pause_for_process_reason,
+ N_("Pause a miner while the calling process is alive or until resumed (you must use this with
--miner)"),
+ N_("REASON")
+ },
+ { "resume", 0 , 0, G_OPTION_ARG_INT, &resume_cookie,
+ N_("Resume a miner (you must use this with --miner)"),
+ N_("COOKIE")
+ },
+ { "miner", 0 , 0, G_OPTION_ARG_STRING, &miner_name,
+ N_("Miner to use with --resume or --pause (you can use suffixes, e.g. Files or Applications)"),
+ N_("MINER")
+ },
+ { "list-miners-running", 0, 0, G_OPTION_ARG_NONE, &list_miners_running,
+ N_("List all miners currently running"),
+ NULL
+ },
+ { "list-miners-available", 0, 0, G_OPTION_ARG_NONE, &list_miners_available,
+ N_("List all miners installed"),
+ NULL
+ },
+ { "pause-details", 0, 0, G_OPTION_ARG_NONE, &pause_details,
+ N_("List pause reasons"),
+ NULL
+ },
+ { NULL }
+};
+
+gboolean
+tracker_control_miners_options_enabled (void)
+{
+ return MINERS_OPTIONS_ENABLED ();
+}
+
+void
+tracker_control_miners_run_default (void)
+{
+ /* No miners output in the default run */
+}
+
+gint
+tracker_control_miners_run (void)
+{
+ /* Constraints */
+
+
+ return EXIT_FAILURE;
+}
+
+GOptionGroup *
+tracker_control_miners_get_option_group (void)
+{
+ GOptionGroup *group;
+
+ /* Status options */
+ group = g_option_group_new ("miners",
+ _("Miner options"),
+ _("Show miner options"),
+ NULL,
+ NULL);
+ g_option_group_add_entries (group, entries);
+
+ return group;
+}
diff --git a/src/tracker-control/tracker-control.c b/src/tracker/tracker-control.c
similarity index 100%
rename from src/tracker-control/tracker-control.c
rename to src/tracker/tracker-control.c
diff --git a/src/tracker-control/tracker-control.h b/src/tracker/tracker-control.h
similarity index 100%
rename from src/tracker-control/tracker-control.h
rename to src/tracker/tracker-control.h
diff --git a/src/tracker/tracker-daemon.c b/src/tracker/tracker-daemon.c
new file mode 100644
index 0000000..ddfe5cb
--- /dev/null
+++ b/src/tracker/tracker-daemon.c
@@ -0,0 +1,2108 @@
+/*
+ * Copyright (C) 2010, Nokia <ivan frade nokia com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+
+#ifdef __sun
+#include <procfs.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gprintf.h>
+
+#include <libtracker-common/tracker-common.h>
+#include <libtracker-miner/tracker-miner.h>
+#include <libtracker-control/tracker-control.h>
+
+#include "tracker-daemon.h"
+#include "tracker-config.h"
+#include "tracker-process.h"
+#include "tracker-dbus.h"
+
+typedef struct {
+ TrackerSparqlConnection *connection;
+ GHashTable *prefixes;
+ GStrv filter;
+} WatchData;
+
+static gboolean parse_watch (const gchar *option_name,
+ const gchar *value,
+ gpointer data,
+ GError **error);
+
+static GDBusConnection *connection = NULL;
+static GDBusProxy *proxy = NULL;
+static GMainLoop *main_loop;
+static GHashTable *miners_progress;
+static GHashTable *miners_status;
+static gint longest_miner_name_length = 0;
+static gint paused_length = 0;
+
+static gboolean full_namespaces = FALSE; /* Can be turned on if needed, or made cmd line option */
+
+#define OPTION_TERM_ALL "all"
+#define OPTION_TERM_STORE "store"
+#define OPTION_TERM_MINERS "miners"
+
+
+/* Note:
+ * Every time a new option is added, make sure it is considered in the
+ * 'STATUS_OPTIONS_ENABLED' macro below
+ */
+static gboolean status;
+static gboolean follow;
+static gchar *watch = NULL;
+static gboolean list_common_statuses;
+
+static gchar *miner_name;
+static gchar *pause_reason;
+static gchar *pause_for_process_reason;
+static gint resume_cookie = -1;
+static gboolean list_miners_running;
+static gboolean list_miners_available;
+static gboolean pause_details;
+
+static gboolean list_processes;
+static TrackerProcessTypes daemons_to_kill = TRACKER_PROCESS_TYPE_NONE;
+static TrackerProcessTypes daemons_to_term = TRACKER_PROCESS_TYPE_NONE;
+static gchar *set_log_verbosity;
+static gboolean get_log_verbosity;
+static gboolean start;
+static gchar *backup;
+static gchar *restore;
+static gboolean collect_debug_info;
+
+
+#define DAEMON_OPTIONS_ENABLED() \
+ ((status || follow || watch || list_common_statuses) || \
+ (miner_name || \
+ pause_reason || \
+ pause_for_process_reason || \
+ resume_cookie != -1 || \
+ list_miners_running || \
+ list_miners_available || \
+ pause_details) || \
+ (list_processes || \
+ daemons_to_kill != TRACKER_PROCESS_TYPE_NONE || \
+ daemons_to_term != TRACKER_PROCESS_TYPE_NONE || \
+ get_log_verbosity || \
+ set_log_verbosity || \
+ start || \
+ backup || \
+ restore || \
+ collect_debug_info))
+
+static gboolean term_option_arg_func (const gchar *option_value,
+ const gchar *value,
+ gpointer data,
+ GError **error);
+
+
+/* Make sure our statuses are translated (most from libtracker-miner) */
+static const gchar *statuses[8] = {
+ N_("Unavailable"), /* generic */
+ N_("Initializing"),
+ N_("Processing…"),
+ N_("Fetching…"), /* miner/rss */
+ N_("Crawling single directory '%s'"),
+ N_("Crawling recursively directory '%s'"),
+ N_("Paused"),
+ N_("Idle")
+};
+
+static GOptionEntry entries[] = {
+ /* Status */
+ { "status", 'S', 0, G_OPTION_ARG_NONE, &status,
+ N_("Show current status"),
+ NULL
+ },
+ { "follow", 'f', 0, G_OPTION_ARG_NONE, &follow,
+ N_("Follow status changes as they happen"),
+ NULL
+ },
+ { "watch", 'w', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, parse_watch,
+ N_("Watch changes to the database in real time (e.g. resources or files being added)"),
+ N_("ONTOLOGY")
+ },
+ { "list-common-statuses", 0, 0, G_OPTION_ARG_NONE, &list_common_statuses,
+ N_("List common statuses for miners and the store"),
+ NULL
+ },
+ /* Miners */
+ { "pause", 0 , 0, G_OPTION_ARG_STRING, &pause_reason,
+ N_("Pause a miner (you must use this with --miner)"),
+ N_("REASON")
+ },
+ { "pause-for-process", 0 , 0, G_OPTION_ARG_STRING, &pause_for_process_reason,
+ N_("Pause a miner while the calling process is alive or until resumed (you must use this with
--miner)"),
+ N_("REASON")
+ },
+ { "resume", 0 , 0, G_OPTION_ARG_INT, &resume_cookie,
+ N_("Resume a miner (you must use this with --miner)"),
+ N_("COOKIE")
+ },
+ { "miner", 0 , 0, G_OPTION_ARG_STRING, &miner_name,
+ N_("Miner to use with --resume or --pause (you can use suffixes, e.g. Files or Applications)"),
+ N_("MINER")
+ },
+ { "list-miners-running", 0, 0, G_OPTION_ARG_NONE, &list_miners_running,
+ N_("List all miners currently running"),
+ NULL
+ },
+ { "list-miners-available", 0, 0, G_OPTION_ARG_NONE, &list_miners_available,
+ N_("List all miners installed"),
+ NULL
+ },
+ { "pause-details", 0, 0, G_OPTION_ARG_NONE, &pause_details,
+ N_("List pause reasons"),
+ NULL
+ },
+ /* Processes */
+ { "list-processes", 'p', 0, G_OPTION_ARG_NONE, &list_processes,
+ N_("List all Tracker processes") },
+ { "kill", 'k', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, term_option_arg_func,
+ N_("Use SIGKILL to stop all matching processes, either \"store\", \"miners\" or \"all\" may be
used, no parameter equals \"all\""),
+ N_("APPS") },
+ { "terminate", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, term_option_arg_func,
+ N_("Use SIGTERM to stop all matching processes, either \"store\", \"miners\" or \"all\" may be
used, no parameter equals \"all\""),
+ N_("APPS") },
+ { "start", 's', 0, G_OPTION_ARG_NONE, &start,
+ N_("Starts miners (which indirectly starts tracker-store too)"),
+ NULL },
+ { "backup", 'b', 0, G_OPTION_ARG_FILENAME, &backup,
+ N_("Backup databases to the file provided"),
+ N_("FILE") },
+ { "restore", 'o', 0, G_OPTION_ARG_FILENAME, &restore,
+ N_("Restore databases from the file provided"),
+ N_("FILE") },
+ { "set-log-verbosity", 0, 0, G_OPTION_ARG_STRING, &set_log_verbosity,
+ N_("Sets the logging verbosity to LEVEL ('debug', 'detailed', 'minimal', 'errors') for all
processes"),
+ N_("LEVEL") },
+ { "get-log-verbosity", 0, 0, G_OPTION_ARG_NONE, &get_log_verbosity,
+ N_("Show logging values in terms of log verbosity for each process"),
+ NULL },
+ { "collect-debug-info", 0, 0, G_OPTION_ARG_NONE, &collect_debug_info,
+ N_("Collect debug information useful for problem reporting and investigation, results are output to
terminal"),
+ NULL },
+ { NULL }
+};
+
+static gboolean
+parse_watch (const gchar *option_name,
+ const gchar *value,
+ gpointer data,
+ GError **error)
+{
+ if (!value) {
+ watch = g_strdup ("");
+ } else {
+ watch = g_strdup (value);
+ }
+
+ return TRUE;
+}
+
+static void
+signal_handler (int signo)
+{
+ static gboolean in_loop = FALSE;
+
+ /* Die if we get re-entrant signals handler calls */
+ if (in_loop) {
+ exit (EXIT_FAILURE);
+ }
+
+ switch (signo) {
+ case SIGTERM:
+ case SIGINT:
+ in_loop = TRUE;
+ g_main_loop_quit (main_loop);
+
+ /* Fall through */
+ default:
+ if (g_strsignal (signo)) {
+ g_print ("\n");
+ g_print ("Received signal:%d->'%s'\n",
+ signo,
+ g_strsignal (signo));
+ }
+ break;
+ }
+}
+
+static void
+initialize_signal_handler (void)
+{
+ struct sigaction act;
+ sigset_t empty_mask;
+
+ sigemptyset (&empty_mask);
+ act.sa_handler = signal_handler;
+ act.sa_mask = empty_mask;
+ act.sa_flags = 0;
+
+ sigaction (SIGTERM, &act, NULL);
+ sigaction (SIGINT, &act, NULL);
+ sigaction (SIGHUP, &act, NULL);
+}
+
+static gboolean
+miner_get_details (TrackerMinerManager *manager,
+ const gchar *miner,
+ gchar **status,
+ gdouble *progress,
+ gint *remaining_time,
+ GStrv *pause_applications,
+ GStrv *pause_reasons)
+{
+ if ((status || progress || remaining_time) &&
+ !tracker_miner_manager_get_status (manager,
+ miner,
+ status,
+ progress,
+ remaining_time)) {
+ g_printerr (_("Could not get status from miner: %s"), miner);
+ return FALSE;
+ }
+
+ tracker_miner_manager_is_paused (manager, miner,
+ pause_applications,
+ pause_reasons);
+
+ if (!(*pause_applications) || !(*pause_reasons)) {
+ /* unable to get pause details,
+ already logged by tracker_miner_manager_is_paused */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+miner_print_state (TrackerMinerManager *manager,
+ const gchar *miner_name,
+ const gchar *status,
+ gdouble progress,
+ gint remaining_time,
+ gboolean is_running,
+ gboolean is_paused)
+{
+ const gchar *name;
+ time_t now;
+ gchar time_str[64];
+ size_t len;
+ struct tm *local_time;
+
+ now = time ((time_t *) NULL);
+ local_time = localtime (&now);
+ len = strftime (time_str,
+ sizeof (time_str) - 1,
+ "%d %b %Y, %H:%M:%S:",
+ local_time);
+ time_str[len] = '\0';
+
+ name = tracker_miner_manager_get_display_name (manager, miner_name);
+
+ if (is_running) {
+ gchar *progress_str = NULL;
+ gchar *remaining_time_str = NULL;
+
+ if (progress >= 0.0 && progress < 1.0) {
+ progress_str = g_strdup_printf ("%3u%%", (guint)(progress * 100));
+ }
+
+ /* Progress > 0.01 here because we want to avoid any message
+ * during crawling, as we don't have the remaining time in that
+ * case and it would just print "unknown time left" */
+ if (progress > 0.01 &&
+ progress < 1.0 &&
+ remaining_time >= 0) {
+ /* 0 means that we couldn't properly compute the remaining
+ * time. */
+ if (remaining_time > 0) {
+ gchar *seconds_str = tracker_seconds_to_string (remaining_time, TRUE);
+
+ /* Translators: %s is a time string */
+ remaining_time_str = g_strdup_printf (_("%s remaining"), seconds_str);
+ g_free (seconds_str);
+ } else {
+ remaining_time_str = g_strdup (_("unknown time left"));
+ }
+ }
+
+ g_print ("%s %s %-*.*s %s%-*.*s%s %s %s %s\n",
+ time_str,
+ progress_str ? progress_str : "✓ ",
+ longest_miner_name_length,
+ longest_miner_name_length,
+ name,
+ is_paused ? "(" : " ",
+ paused_length,
+ paused_length,
+ is_paused ? _("PAUSED") : " ",
+ is_paused ? ")" : " ",
+ status ? "-" : "",
+ status ? _(status) : "",
+ remaining_time_str ? remaining_time_str : "");
+
+ g_free (progress_str);
+ g_free (remaining_time_str);
+ } else {
+ g_print ("%s ✗ %-*.*s %-*.*s - %s\n",
+ time_str,
+ longest_miner_name_length,
+ longest_miner_name_length,
+ name,
+ paused_length,
+ paused_length,
+ " ",
+ _("Not running or is a disabled plugin"));
+ }
+}
+
+static void
+store_print_state (const gchar *status,
+ gdouble progress)
+{
+ gchar time_str[64];
+ struct tm *local_time;
+ time_t now;
+ size_t len;
+
+ now = time ((time_t *) NULL);
+ local_time = localtime (&now);
+ len = strftime (time_str,
+ sizeof (time_str) - 1,
+ "%d %b %Y, %H:%M:%S:",
+ local_time);
+ time_str[len] = '\0';
+
+ if (status) {
+ gchar *operation = NULL;
+ gchar *operation_status = NULL;
+ gchar *progress_str;
+
+ if (strstr (status, "-")) {
+ gchar **status_split;
+
+ status_split = g_strsplit (status, "-", 2);
+ if (status_split[0] && status_split[1]) {
+ operation = g_strstrip (status_split[0]);
+ operation_status = g_strstrip (status_split[1]);
+ /* Free the array, not the contents */
+ g_free (status_split);
+ } else {
+ /* Free everything */
+ g_strfreev (status_split);
+ }
+ }
+
+ if (progress >= 0.0 && progress < 1.0) {
+ progress_str = g_strdup_printf ("%3u%%", (guint)(progress * 100));
+ } else {
+ progress_str = g_strdup_printf ("✓ ");
+ }
+
+ g_print ("%s %s %-*.*s - %s %s%s%s\n",
+ time_str,
+ progress_str ? progress_str : " ",
+ longest_miner_name_length + paused_length,
+ longest_miner_name_length + paused_length,
+ "Store",
+ /*(operation ? _(operation) : _(status)),*/
+ /*operation ? "-" : "",*/
+ operation ? _(operation) : _(status),
+ operation_status ? "(" : "",
+ operation_status ? operation_status : "",
+ operation_status ? ")" : "");
+
+ g_free (progress_str);
+ g_free (operation);
+ g_free (operation_status);
+ } else {
+ g_print ("%s %s %-*.*s - %s\n",
+ time_str,
+ "✗ ", /* Progress */
+ longest_miner_name_length + paused_length,
+ longest_miner_name_length + paused_length,
+ "Store",
+ _("Unavailable"));
+ }
+}
+
+static void
+store_get_and_print_state (void)
+{
+ GVariant *v_status, *v_progress;
+ const gchar *status = NULL;
+ gdouble progress = -1.0;
+ GError *error = NULL;
+ gchar *owner;
+
+ owner = g_dbus_proxy_get_name_owner (proxy);
+ if (!owner) {
+ /* Name is not owned yet, store is not running */
+ store_print_state (NULL, -1);
+ return;
+ }
+ g_free (owner);
+
+ /* Status */
+ v_status = g_dbus_proxy_call_sync (proxy,
+ "GetStatus",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+
+ if (!v_status || error) {
+ g_critical ("%s, %s",
+ _("Could not retrieve tracker-store status"),
+ error ? error->message : _("No error given"));
+ g_clear_error (&error);
+ return;
+ }
+
+ g_variant_get (v_status, "(&s)", &status);
+
+ /* Progress */
+ v_progress = g_dbus_proxy_call_sync (proxy,
+ "GetProgress",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+
+ g_variant_get (v_progress, "(d)", &progress);
+
+ if (progress < 0.0 || error) {
+ g_critical ("%s, %s",
+ _("Could not retrieve tracker-store progress"),
+ error ? error->message : _("No error given"));
+ g_clear_error (&error);
+ return;
+ }
+
+ /* Print */
+ store_print_state (status, progress);
+
+ g_variant_unref (v_progress);
+ g_variant_unref (v_status);
+}
+
+static void
+manager_miner_progress_cb (TrackerMinerManager *manager,
+ const gchar *miner_name,
+ const gchar *status,
+ gdouble progress,
+ gint remaining_time)
+{
+ GValue *gvalue;
+
+ gvalue = g_slice_new0 (GValue);
+
+ g_value_init (gvalue, G_TYPE_DOUBLE);
+ g_value_set_double (gvalue, progress);
+
+ miner_print_state (manager, miner_name, status, progress, remaining_time, TRUE, FALSE);
+
+ g_hash_table_replace (miners_status,
+ g_strdup (miner_name),
+ g_strdup (status));
+ g_hash_table_replace (miners_progress,
+ g_strdup (miner_name),
+ gvalue);
+}
+
+static void
+manager_miner_paused_cb (TrackerMinerManager *manager,
+ const gchar *miner_name)
+{
+ GValue *gvalue;
+
+ gvalue = g_hash_table_lookup (miners_progress, miner_name);
+
+ miner_print_state (manager, miner_name,
+ g_hash_table_lookup (miners_status, miner_name),
+ gvalue ? g_value_get_double (gvalue) : 0.0,
+ -1,
+ TRUE,
+ TRUE);
+}
+
+static void
+manager_miner_resumed_cb (TrackerMinerManager *manager,
+ const gchar *miner_name)
+{
+ GValue *gvalue;
+
+ gvalue = g_hash_table_lookup (miners_progress, miner_name);
+
+ miner_print_state (manager, miner_name,
+ g_hash_table_lookup (miners_status, miner_name),
+ gvalue ? g_value_get_double (gvalue) : 0.0,
+ 0,
+ TRUE,
+ FALSE);
+}
+
+static void
+miners_progress_destroy_notify (gpointer data)
+{
+ GValue *value;
+
+ value = data;
+ g_value_unset (value);
+ g_slice_free (GValue, value);
+}
+
+static gchar *
+get_shorthand (GHashTable *prefixes,
+ const gchar *namespace)
+{
+ gchar *hash;
+
+ hash = strrchr (namespace, '#');
+
+ if (hash) {
+ gchar *property;
+ const gchar *prefix;
+
+ property = hash + 1;
+ *hash = '\0';
+
+ prefix = g_hash_table_lookup (prefixes, namespace);
+
+ return g_strdup_printf ("%s:%s", prefix, property);
+ }
+
+ return g_strdup (namespace);
+}
+
+static GHashTable *
+get_prefixes (TrackerSparqlConnection *connection)
+{
+ TrackerSparqlCursor *cursor;
+ GError *error = NULL;
+ GHashTable *retval;
+ const gchar *query;
+
+ retval = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_free);
+
+ /* FIXME: Would like to get this in the same SPARQL that we
+ * use to get the info, but doesn't seem possible at the
+ * moment with the limited string manipulation features we
+ * support in SPARQL.
+ */
+ query = "SELECT ?ns ?prefix "
+ "WHERE {"
+ " ?ns a tracker:Namespace ;"
+ " tracker:prefix ?prefix "
+ "}";
+
+ cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
+
+ if (error) {
+ g_printerr ("%s, %s\n",
+ _("Unable to retrieve namespace prefixes"),
+ error->message);
+
+ g_error_free (error);
+ return retval;
+ }
+
+ if (!cursor) {
+ g_printerr ("%s\n", _("No namespace prefixes were returned"));
+ return retval;
+ }
+
+ while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
+ const gchar *key, *value;
+
+ key = tracker_sparql_cursor_get_string (cursor, 0, NULL);
+ value = tracker_sparql_cursor_get_string (cursor, 1, NULL);
+
+ if (!key || !value) {
+ continue;
+ }
+
+ g_hash_table_insert (retval,
+ g_strndup (key, strlen (key) - 1),
+ g_strdup (value));
+ }
+
+ if (cursor) {
+ g_object_unref (cursor);
+ }
+
+ return retval;
+}
+
+static inline void
+print_key (GHashTable *prefixes,
+ const gchar *key)
+{
+ if (G_UNLIKELY (full_namespaces)) {
+ g_print ("'%s'\n", key);
+ } else {
+ gchar *shorthand;
+
+ shorthand = get_shorthand (prefixes, key);
+ g_print ("'%s'\n", shorthand);
+ g_free (shorthand);
+ }
+}
+
+static void
+store_progress (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ const gchar *status = NULL;
+ gdouble progress = 0.0;
+
+ g_variant_get (parameters, "(sd)", &status, &progress);
+ store_print_state (status, progress);
+}
+
+static void
+store_graph_update_interpret (WatchData *wd,
+ GHashTable *updates,
+ gint subject,
+ gint predicate)
+{
+ TrackerSparqlCursor *cursor;
+ GError *error = NULL;
+ gchar *query, *key;
+ gboolean ok = TRUE;
+
+ query = g_strdup_printf ("SELECT tracker:uri (%d) tracker:uri(%d) {}",
+ subject,
+ predicate);
+ cursor = tracker_sparql_connection_query (wd->connection,
+ query,
+ NULL,
+ &error);
+ g_free (query);
+
+ if (error) {
+ g_critical ("%s, %s",
+ _("Could not run SPARQL query"),
+ error->message);
+ g_clear_error (&error);
+ return;
+ }
+
+ if (!tracker_sparql_cursor_next (cursor, NULL, &error) || error) {
+ g_critical ("%s, %s",
+ _("Could not call tracker_sparql_cursor_next() on SPARQL query"),
+ error ? error->message : _("No error given"));
+ g_clear_error (&error);
+ return;
+ }
+
+ /* Key = predicate */
+ key = g_strdup (tracker_sparql_cursor_get_string (cursor, 1, NULL));
+ query = g_strdup_printf ("SELECT ?t { <%s> <%s> ?t } ORDER BY DESC(<%s>)",
+ tracker_sparql_cursor_get_string (cursor, 0, NULL),
+ key,
+ key);
+ g_object_unref (cursor);
+
+ cursor = tracker_sparql_connection_query (wd->connection, query, NULL, &error);
+ g_free (query);
+
+ if (error) {
+ g_critical ("%s, %s",
+ _("Could not run SPARQL query"),
+ error->message);
+ g_clear_error (&error);
+ return;
+ }
+
+ while (ok) {
+ const gchar *value;
+
+ ok = tracker_sparql_cursor_next (cursor, NULL, &error);
+
+ if (error) {
+ g_critical ("%s, %s",
+ _("Could not call tracker_sparql_cursor_next() on SPARQL query"),
+ error ? error->message : _("No error given"));
+ g_clear_error (&error);
+ break;
+ }
+
+ value = tracker_sparql_cursor_get_string (cursor, 0, NULL);
+
+ if (!key || !value) {
+ continue;
+ }
+
+ /* Don't display nie:plainTextContent */
+ if (strcmp (key, "http://www.semanticdesktop.org/ontologies/2007/01/19/nie#plainTextContent")
== 0) {
+ continue;
+ }
+
+ if (G_UNLIKELY (full_namespaces)) {
+ if (wd->filter == NULL ||
+ tracker_string_in_string_list (key, wd->filter) != -1) {
+ g_hash_table_replace (updates, g_strdup (key), g_strdup (value));
+ }
+ } else {
+ gchar *shorthand;
+
+ shorthand = get_shorthand (wd->prefixes, key);
+
+ if (wd->filter == NULL ||
+ tracker_string_in_string_list (shorthand, wd->filter) != -1) {
+ g_hash_table_replace (updates, shorthand, g_strdup (value));
+ } else {
+ g_free (shorthand);
+ }
+ }
+ }
+
+ g_free (key);
+ g_object_unref (cursor);
+}
+
+static void
+store_graph_update_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+
+{
+ WatchData *wd;
+ GHashTable *updates;
+ GVariantIter *iter1, *iter2;
+ gchar *class_name;
+ gint graph = 0, subject = 0, predicate = 0, object = 0;
+
+ wd = user_data;
+
+ updates = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
+
+ g_variant_get (parameters, "(&sa(iiii)a(iiii))", &class_name, &iter1, &iter2);
+
+ while (g_variant_iter_loop (iter1, "(iiii)", &graph, &subject, &predicate, &object)) {
+ store_graph_update_interpret (wd, updates, subject, predicate);
+ }
+
+ while (g_variant_iter_loop (iter2, "(iiii)", &graph, &subject, &predicate, &object)) {
+ store_graph_update_interpret (wd, updates, subject, predicate);
+ }
+
+ /* Print updates sorted and filtered */
+ GList *keys, *l;
+
+ keys = g_hash_table_get_keys (updates);
+ keys = g_list_sort (keys, (GCompareFunc) g_strcmp0);
+
+ if (g_hash_table_size (updates) > 0) {
+ print_key (wd->prefixes, class_name);
+ }
+
+ for (l = keys; l; l = l->next) {
+ gchar *key = l->data;
+ gchar *value = g_hash_table_lookup (updates, l->data);
+
+ g_print (" '%s' = '%s'\n", key, value);
+ }
+
+ g_list_free (keys);
+ g_hash_table_unref (updates);
+ g_variant_iter_free (iter1);
+ g_variant_iter_free (iter2);
+}
+
+static WatchData *
+watch_data_new (TrackerSparqlConnection *sparql_connection,
+ GHashTable *sparql_prefixes,
+ const gchar *watch_filter)
+{
+ WatchData *data;
+
+ data = g_new0 (WatchData, 1);
+ data->connection = g_object_ref (sparql_connection);
+ data->prefixes = g_hash_table_ref (sparql_prefixes);
+
+ if (watch_filter && strlen (watch_filter) > 0) {
+ data->filter = g_strsplit (watch_filter, ",", -1);
+ }
+
+ return data;
+}
+
+static void
+watch_data_free (WatchData *data)
+{
+ if (!data) {
+ return;
+ }
+
+ if (data->filter) {
+ g_strfreev (data->filter);
+ }
+
+ if (data->prefixes) {
+ g_hash_table_unref (data->prefixes);
+ }
+
+ if (data->connection) {
+ g_object_unref (data->connection);
+ }
+
+ g_free (data);
+}
+
+
+static gint
+miner_pause (const gchar *miner,
+ const gchar *reason,
+ gboolean for_process)
+{
+ TrackerMinerManager *manager;
+ GError *error = NULL;
+ gchar *str;
+ gint cookie;
+
+ /* Don't auto-start the miners here */
+ manager = tracker_miner_manager_new_full (FALSE, &error);
+ if (!manager) {
+ g_printerr (_("Could not pause miner, manager could not be created, %s"),
+ error ? error->message : _("No error given"));
+ g_printerr ("\n");
+ g_clear_error (&error);
+ return EXIT_FAILURE;
+ }
+
+ str = g_strdup_printf (_("Attempting to pause miner '%s' with reason '%s'"),
+ miner,
+ reason);
+ g_print ("%s\n", str);
+ g_free (str);
+
+ if (for_process) {
+ if (!tracker_miner_manager_pause_for_process (manager, miner, reason, &cookie)) {
+ g_printerr (_("Could not pause miner: %s"), miner);
+ g_printerr ("\n");
+ return EXIT_FAILURE;
+ }
+ } else {
+ if (!tracker_miner_manager_pause (manager, miner, reason, &cookie)) {
+ g_printerr (_("Could not pause miner: %s"), miner);
+ g_printerr ("\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ str = g_strdup_printf (_("Cookie is %d"), cookie);
+ g_print (" %s\n", str);
+ g_free (str);
+
+ if (for_process) {
+ GMainLoop *main_loop;
+
+ g_print ("%s\n", _("Press Ctrl+C to stop"));
+
+ main_loop = g_main_loop_new (NULL, FALSE);
+ /* Block until Ctrl+C */
+ g_main_loop_run (main_loop);
+ g_object_unref (main_loop);
+ }
+
+ g_object_unref (manager);
+
+ return EXIT_SUCCESS;
+}
+
+static gint
+miner_resume (const gchar *miner,
+ gint cookie)
+{
+ TrackerMinerManager *manager;
+ GError *error = NULL;
+ gchar *str;
+
+ /* Don't auto-start the miners here */
+ manager = tracker_miner_manager_new_full (FALSE, &error);
+ if (!manager) {
+ g_printerr (_("Could not resume miner, manager could not be created, %s"),
+ error ? error->message : _("No error given"));
+ g_printerr ("\n");
+ g_clear_error (&error);
+ return EXIT_FAILURE;
+ }
+
+ str = g_strdup_printf (_("Attempting to resume miner %s with cookie %d"),
+ miner,
+ cookie);
+ g_print ("%s\n", str);
+ g_free (str);
+
+ if (!tracker_miner_manager_resume (manager, miner, cookie)) {
+ g_printerr (_("Could not resume miner: %s"), miner);
+ return EXIT_FAILURE;
+ }
+
+ g_print (" %s\n", _("Done"));
+
+ g_object_unref (manager);
+
+ return EXIT_SUCCESS;
+}
+
+static gint
+miner_list (gboolean available,
+ gboolean running)
+{
+ TrackerMinerManager *manager;
+ GError *error = NULL;
+
+ /* Don't auto-start the miners here */
+ manager = tracker_miner_manager_new_full (FALSE, &error);
+ if (!manager) {
+ g_printerr (_("Could not list miners, manager could not be created, %s"),
+ error ? error->message : _("No error given"));
+ g_printerr ("\n");
+ g_clear_error (&error);
+ return EXIT_FAILURE;
+ }
+
+ if (available) {
+ GSList *miners_available;
+ gchar *str;
+ GSList *l;
+
+ miners_available = tracker_miner_manager_get_available (manager);
+
+ str = g_strdup_printf (ngettext ("Found %d miner installed",
+ "Found %d miners installed",
+ g_slist_length (miners_available)),
+ g_slist_length (miners_available));
+
+ g_print ("%s%s\n", str, g_slist_length (miners_available) > 0 ? ":" : "");
+ g_free (str);
+
+ for (l = miners_available; l; l = l->next) {
+ g_print (" %s\n", (gchar*) l->data);
+ }
+
+ g_slist_foreach (miners_available, (GFunc) g_free, NULL);
+ g_slist_free (miners_available);
+ }
+
+ if (running) {
+ GSList *miners_running;
+ gchar *str;
+ GSList *l;
+
+ miners_running = tracker_miner_manager_get_running (manager);
+
+ str = g_strdup_printf (ngettext ("Found %d miner running",
+ "Found %d miners running",
+ g_slist_length (miners_running)),
+ g_slist_length (miners_running));
+
+ g_print ("%s%s\n", str, g_slist_length (miners_running) > 0 ? ":" : "");
+ g_free (str);
+
+ for (l = miners_running; l; l = l->next) {
+ g_print (" %s\n", (gchar*) l->data);
+ }
+
+ g_slist_foreach (miners_running, (GFunc) g_free, NULL);
+ g_slist_free (miners_running);
+ }
+
+ g_object_unref (manager);
+
+ return EXIT_SUCCESS;
+}
+
+static gint
+miner_pause_details (void)
+{
+ TrackerMinerManager *manager;
+ GError *error = NULL;
+ GSList *miners_running, *l;
+ gint paused_miners = 0;
+
+ /* Don't auto-start the miners here */
+ manager = tracker_miner_manager_new_full (FALSE, &error);
+ if (!manager) {
+ g_printerr (_("Could not get pause details, manager could not be created, %s"),
+ error ? error->message : _("No error given"));
+ g_printerr ("\n");
+ g_clear_error (&error);
+ return EXIT_FAILURE;
+ }
+
+ miners_running = tracker_miner_manager_get_running (manager);
+
+ if (!miners_running) {
+ g_print ("%s\n", _("No miners are running"));
+
+ g_slist_foreach (miners_running, (GFunc) g_free, NULL);
+ g_slist_free (miners_running);
+ g_object_unref (manager);
+
+ return EXIT_SUCCESS;
+ }
+
+ for (l = miners_running; l; l = l->next) {
+ const gchar *name;
+ GStrv pause_applications, pause_reasons;
+ gint i;
+
+ name = tracker_miner_manager_get_display_name (manager, l->data);
+
+ if (!name) {
+ g_critical ("Could not get name for '%s'", (gchar *) l->data);
+ continue;
+ }
+
+ tracker_miner_manager_is_paused (manager,
+ l->data,
+ &pause_applications,
+ &pause_reasons);
+
+ if (!pause_applications || !pause_reasons) {
+ /* unable to get pause details,
+ already logged by tracker_miner_manager_is_paused */
+ continue;
+ }
+
+ if (!(*pause_applications) || !(*pause_reasons)) {
+ g_strfreev (pause_applications);
+ g_strfreev (pause_reasons);
+ continue;
+ }
+
+ paused_miners++;
+ if (paused_miners == 1) {
+ g_print ("%s:\n", _("Miners"));
+ }
+
+ g_print (" %s:\n", name);
+
+ for (i = 0; pause_applications[i] != NULL; i++) {
+ g_print (" %s: '%s', %s: '%s'\n",
+ _("Application"),
+ pause_applications[i],
+ _("Reason"),
+ pause_reasons[i]);
+ }
+
+ g_strfreev (pause_applications);
+ g_strfreev (pause_reasons);
+ }
+
+ if (paused_miners < 1) {
+ g_print ("%s\n", _("No miners are paused"));
+ }
+
+ g_slist_foreach (miners_running, (GFunc) g_free, NULL);
+ g_slist_free (miners_running);
+
+ g_object_unref (manager);
+
+ return EXIT_SUCCESS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+inline static const gchar *
+verbosity_to_string (TrackerVerbosity verbosity)
+{
+ GType type;
+ GEnumClass *enum_class;
+ GEnumValue *enum_value;
+
+ type = tracker_verbosity_get_type ();
+ enum_class = G_ENUM_CLASS (g_type_class_peek (type));
+ enum_value = g_enum_get_value (enum_class, verbosity);
+
+ if (!enum_value) {
+ return "unknown";
+ }
+
+ return enum_value->value_nick;
+}
+
+inline static void
+tracker_gsettings_print_verbosity (GSList *all,
+ gint longest,
+ gboolean miners)
+{
+ GSList *l;
+
+ for (l = all; l; l = l->next) {
+ ComponentGSettings *c;
+ TrackerVerbosity v;
+
+ c = l->data;
+
+ if (c->is_miner == miners) {
+ continue;
+ }
+
+ v = g_settings_get_enum (c->settings, "verbosity");
+
+ g_print (" %-*.*s: %s\n",
+ longest,
+ longest,
+ c->name,
+ verbosity_to_string (v));
+ }
+}
+
+static gboolean
+term_option_arg_func (const gchar *option_value,
+ const gchar *value,
+ gpointer data,
+ GError **error)
+{
+ TrackerProcessTypes option;
+
+ if (!value) {
+ value = OPTION_TERM_ALL;
+ }
+
+ if (strcmp (value, OPTION_TERM_ALL) == 0) {
+ option = TRACKER_PROCESS_TYPE_ALL;
+ } else if (strcmp (value, OPTION_TERM_STORE) == 0) {
+ option = TRACKER_PROCESS_TYPE_STORE;
+ } else if (strcmp (value, OPTION_TERM_MINERS) == 0) {
+ option = TRACKER_PROCESS_TYPE_MINERS;
+ } else {
+ g_set_error_literal (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+ _("Only one of 'all', 'store' and 'miners' options are allowed"));
+ return FALSE;
+ }
+
+ if (strcmp (option_value, "-k") == 0 ||
+ strcmp (option_value, "--kill") == 0) {
+ daemons_to_kill = option;
+ } else if (strcmp (option_value, "-t") == 0 ||
+ strcmp (option_value, "--terminate") == 0) {
+ daemons_to_term = option;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+has_valid_uri_scheme (const gchar *uri)
+{
+ const gchar *s;
+
+ s = uri;
+
+ if (!g_ascii_isalpha (*s)) {
+ return FALSE;
+ }
+
+ do {
+ s++;
+ } while (g_ascii_isalnum (*s) || *s == '+' || *s == '.' || *s == '-');
+
+ return (*s == ':');
+}
+
+static gchar *
+get_uri_from_arg (const gchar *arg)
+{
+ gchar *uri;
+
+ /* support both, URIs and local file paths */
+ if (has_valid_uri_scheme (arg)) {
+ uri = g_strdup (arg);
+ } else {
+ GFile *file;
+
+ file = g_file_new_for_commandline_arg (arg);
+ uri = g_file_get_uri (file);
+ g_object_unref (file);
+ }
+
+ return uri;
+}
+
+static void
+collect_debug (void)
+{
+ /* What to collect?
+ * This is based on information usually requested from maintainers to users.
+ *
+ * 1. Package details, e.g. version.
+ * 2. Disk size, space left, type (SSD/etc)
+ * 3. Size of dataset (tracker-stats), size of databases
+ * 4. Current configuration (libtracker-fts, tracker-miner-fs, tracker-extract)
+ * All txt files in ~/.cache/
+ * 5. Statistics about data (tracker-stats)
+ */
+
+ GDir *d;
+ gchar *data_dir;
+ gchar *str;
+
+ data_dir = g_build_filename (g_get_user_cache_dir (), "tracker", NULL);
+
+ /* 1. Package details, e.g. version. */
+ g_print ("[Package Details]\n");
+ g_print ("%s: " PACKAGE_VERSION "\n", _("Version"));
+ g_print ("\n\n");
+
+ /* 2. Disk size, space left, type (SSD/etc) */
+ guint64 remaining_bytes;
+ gdouble remaining;
+
+ g_print ("[%s]\n", _("Disk Information"));
+
+ remaining_bytes = tracker_file_system_get_remaining_space (data_dir);
+ str = g_format_size (remaining_bytes);
+
+ remaining = tracker_file_system_get_remaining_space_percentage (data_dir);
+ g_print ("%s: %s (%3.2lf%%)\n",
+ _("Remaining space on database partition"),
+ str,
+ remaining);
+ g_free (str);
+ g_print ("\n\n");
+
+ /* 3. Size of dataset (tracker-stats), size of databases */
+ g_print ("[%s]\n", _("Data Set"));
+
+ for (d = g_dir_open (data_dir, 0, NULL); d != NULL;) {
+ const gchar *f;
+ gchar *path;
+ goffset size;
+
+ f = g_dir_read_name (d);
+ if (!f) {
+ break;
+ }
+
+ if (g_str_has_suffix (f, ".txt")) {
+ continue;
+ }
+
+ path = g_build_filename (data_dir, f, NULL);
+ size = tracker_file_get_size (path);
+ str = g_format_size (size);
+
+ g_print ("%s\n%s\n\n", path, str);
+ g_free (str);
+ g_free (path);
+ }
+ g_dir_close (d);
+ g_print ("\n");
+
+ /* 4. Current configuration (libtracker-fts, tracker-miner-fs, tracker-extract)
+ * All txt files in ~/.cache/
+ */
+ GSList *all, *l;
+
+ g_print ("[%s]\n", _("Configuration"));
+
+ all = tracker_gsettings_get_all (NULL);
+
+ if (all) {
+ for (l = all; l; l = l->next) {
+ ComponentGSettings *c = l->data;
+ gchar **keys, **p;
+
+ if (!c) {
+ continue;
+ }
+
+ keys = g_settings_list_keys (c->settings);
+ for (p = keys; p && *p; p++) {
+ GVariant *v;
+ gchar *printed;
+
+ v = g_settings_get_value (c->settings, *p);
+ printed = g_variant_print (v, FALSE);
+ g_print ("%s.%s: %s\n", c->name, *p, printed);
+ g_free (printed);
+ g_variant_unref (v);
+ }
+ }
+
+ tracker_gsettings_free (all);
+ } else {
+ g_print ("** %s **\n", _("No configuration was found"));
+ }
+ g_print ("\n\n");
+
+ g_print ("[%s]\n", _("States"));
+
+ for (d = g_dir_open (data_dir, 0, NULL); d != NULL;) {
+ const gchar *f;
+ gchar *path;
+ gchar *content = NULL;
+
+ f = g_dir_read_name (d);
+ if (!f) {
+ break;
+ }
+
+ if (!g_str_has_suffix (f, ".txt")) {
+ continue;
+ }
+
+ path = g_build_filename (data_dir, f, NULL);
+ if (g_file_get_contents (path, &content, NULL, NULL)) {
+ /* Special case last-index.txt which is time() dump to file */
+ if (g_str_has_suffix (path, "last-crawl.txt")) {
+ guint64 then, now;
+
+ now = (guint64) time (NULL);
+ then = g_ascii_strtoull (content, NULL, 10);
+ str = tracker_seconds_to_string (now - then, FALSE);
+
+ g_print ("%s\n%s (%s)\n\n", path, content, str);
+ } else {
+ g_print ("%s\n%s\n\n", path, content);
+ }
+ g_free (content);
+ }
+ g_free (path);
+ }
+ g_dir_close (d);
+ g_print ("\n");
+
+ /* 5. Statistics about data (tracker-stats) */
+ TrackerSparqlConnection *connection;
+ GError *error = NULL;
+
+ g_print ("[%s]\n", _("Data Statistics"));
+
+ connection = tracker_sparql_connection_get (NULL, &error);
+
+ if (!connection) {
+ g_print ("** %s, %s **\n",
+ _("No connection available"),
+ error ? error->message : _("No error given"));
+ g_clear_error (&error);
+ } else {
+ TrackerSparqlCursor *cursor;
+
+ cursor = tracker_sparql_connection_statistics (connection, NULL, &error);
+
+ if (error) {
+ g_print ("** %s, %s **\n",
+ _("Could not get statistics"),
+ error ? error->message : _("No error given"));
+ g_error_free (error);
+ } else {
+ if (!cursor) {
+ g_print ("** %s **\n",
+ _("No statistics were available"));
+ } else {
+ gint count = 0;
+
+ while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
+ g_print ("%s: %s\n",
+ tracker_sparql_cursor_get_string (cursor, 0, NULL),
+ tracker_sparql_cursor_get_string (cursor, 1, NULL));
+ count++;
+ }
+
+ if (count == 0) {
+ g_print ("%s\n",
+ _("Database is currently empty"));
+ }
+
+ g_object_unref (cursor);
+ }
+ }
+ }
+
+ g_object_unref (connection);
+ g_print ("\n\n");
+
+ g_print ("\n");
+
+ g_free (data_dir);
+}
+
+void
+tracker_daemon_run_default (void)
+{
+ /* Enable status output in the default run */
+ status = TRUE;
+
+ tracker_daemon_run ();
+}
+
+gint
+tracker_daemon_run (void)
+{
+ TrackerMinerManager *manager;
+
+ /* --follow implies --status */
+ if (follow) {
+ status = TRUE;
+ }
+
+ if (watch != NULL) {
+ TrackerSparqlConnection *sparql_connection;
+ GHashTable *sparql_prefixes;
+ GError *error = NULL;
+ guint signal_id;
+
+ sparql_connection = tracker_sparql_connection_get (NULL, &error);
+
+ if (!sparql_connection) {
+ g_critical ("%s, %s",
+ _("Could not get SPARQL connection"),
+ error ? error->message : _("No error given"));
+ g_clear_error (&error);
+ return EXIT_FAILURE;
+ }
+
+ if (!tracker_dbus_get_connection ("org.freedesktop.Tracker1",
+ "/org/freedesktop/Tracker1/Resources",
+ "org.freedesktop.Tracker1.Resources",
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+ &connection,
+ &proxy)) {
+ g_object_unref (sparql_connection);
+ return EXIT_FAILURE;
+ }
+
+ sparql_prefixes = get_prefixes (sparql_connection);
+
+ signal_id = g_dbus_connection_signal_subscribe (connection,
+ TRACKER_DBUS_SERVICE,
+ TRACKER_DBUS_INTERFACE_RESOURCES,
+ "GraphUpdated",
+ TRACKER_DBUS_OBJECT_RESOURCES,
+ NULL, /* TODO: Use class-name here */
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ store_graph_update_cb,
+ watch_data_new (sparql_connection,
sparql_prefixes, watch),
+ (GDestroyNotify) watch_data_free);
+
+ g_hash_table_unref (sparql_prefixes);
+ g_object_unref (sparql_connection);
+
+ g_print ("%s\n", _("Now listening for resource updates to the database"));
+ g_print ("%s\n\n", _("All nie:plainTextContent properties are omitted"));
+ g_print ("%s\n", _("Press Ctrl+C to stop"));
+
+ main_loop = g_main_loop_new (NULL, FALSE);
+ g_main_loop_run (main_loop);
+ g_main_loop_unref (main_loop);
+
+ g_dbus_connection_signal_unsubscribe (connection, signal_id);
+
+ return EXIT_SUCCESS;
+ }
+
+ if (list_common_statuses) {
+ gint i;
+
+ g_print ("%s:\n", _("Common statuses include"));
+
+ for (i = 0; i < G_N_ELEMENTS (statuses); i++) {
+ g_print (" %s\n", _(statuses[i]));
+ }
+
+ return EXIT_SUCCESS;
+ }
+
+ if (status) {
+ GError *error = NULL;
+ GSList *miners_available;
+ GSList *miners_running;
+ GSList *l;
+
+ /* Don't auto-start the miners here */
+ manager = tracker_miner_manager_new_full (FALSE, &error);
+ if (!manager) {
+ g_printerr (_("Could not get status, manager could not be created, %s"),
+ error ? error->message : _("No error given"));
+ g_printerr ("\n");
+ g_clear_error (&error);
+ return EXIT_FAILURE;
+ }
+
+ miners_available = tracker_miner_manager_get_available (manager);
+ miners_running = tracker_miner_manager_get_running (manager);
+
+ /* Work out lengths for output spacing */
+ paused_length = strlen (_("PAUSED"));
+
+ for (l = miners_available; l; l = l->next) {
+ const gchar *name;
+
+ name = tracker_miner_manager_get_display_name (manager, l->data);
+ longest_miner_name_length = MAX (longest_miner_name_length, strlen (name));
+ }
+
+ /* Display states */
+ g_print ("%s:\n", _("Store"));
+
+ if (!tracker_dbus_get_connection ("org.freedesktop.Tracker1",
+ "/org/freedesktop/Tracker1/Status",
+ "org.freedesktop.Tracker1.Status",
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+ &connection,
+ &proxy)) {
+ return EXIT_FAILURE;
+ }
+
+ g_dbus_connection_signal_subscribe (connection,
+ "org.freedesktop.Tracker1",
+ "org.freedesktop.Tracker1.Status",
+ "Progress",
+ "/org/freedesktop/Tracker1/Status",
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ store_progress,
+ NULL,
+ NULL);
+
+ store_get_and_print_state ();
+
+ g_print ("\n");
+
+ g_print ("%s:\n", _("Miners"));
+
+ for (l = miners_available; l; l = l->next) {
+ const gchar *name;
+ gboolean is_running;
+
+ name = tracker_miner_manager_get_display_name (manager, l->data);
+ if (!name) {
+ g_critical (_("Could not get display name for miner '%s'"),
+ (const gchar*) l->data);
+ continue;
+ }
+
+ is_running = tracker_string_in_gslist (l->data, miners_running);
+
+ if (is_running) {
+ GStrv pause_applications, pause_reasons;
+ gchar *status = NULL;
+ gdouble progress;
+ gint remaining_time;
+ gboolean is_paused;
+
+ if (!miner_get_details (manager,
+ l->data,
+ &status,
+ &progress,
+ &remaining_time,
+ &pause_applications,
+ &pause_reasons)) {
+ continue;
+ }
+
+ is_paused = *pause_applications || *pause_reasons;
+
+ miner_print_state (manager,
+ l->data,
+ status,
+ progress,
+ remaining_time,
+ TRUE,
+ is_paused);
+
+ g_strfreev (pause_applications);
+ g_strfreev (pause_reasons);
+ g_free (status);
+ } else {
+ miner_print_state (manager, l->data, NULL, 0.0, -1, FALSE, FALSE);
+ }
+ }
+
+ g_slist_foreach (miners_available, (GFunc) g_free, NULL);
+ g_slist_free (miners_available);
+
+ g_slist_foreach (miners_running, (GFunc) g_free, NULL);
+ g_slist_free (miners_running);
+
+ if (!follow) {
+ /* Do nothing further */
+ if (proxy) {
+ g_object_unref (proxy);
+ }
+ g_print ("\n");
+ return EXIT_SUCCESS;
+ }
+
+ g_print ("%s\n", _("Press Ctrl+C to stop"));
+
+ g_signal_connect (manager, "miner-progress",
+ G_CALLBACK (manager_miner_progress_cb), NULL);
+ g_signal_connect (manager, "miner-paused",
+ G_CALLBACK (manager_miner_paused_cb), NULL);
+ g_signal_connect (manager, "miner-resumed",
+ G_CALLBACK (manager_miner_resumed_cb), NULL);
+
+ initialize_signal_handler ();
+
+ miners_progress = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) miners_progress_destroy_notify);
+ miners_status = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
+
+ main_loop = g_main_loop_new (NULL, FALSE);
+ g_main_loop_run (main_loop);
+ g_main_loop_unref (main_loop);
+
+ g_hash_table_unref (miners_progress);
+ g_hash_table_unref (miners_status);
+
+ if (proxy) {
+ g_object_unref (proxy);
+ }
+
+ if (manager) {
+ g_object_unref (manager);
+ }
+
+ return EXIT_SUCCESS;
+ }
+
+ /* Miners */
+ if (pause_reason && resume_cookie != -1) {
+ g_printerr ("%s\n",
+ _("You can not use miner pause and resume switches together"));
+ return EXIT_FAILURE;
+ }
+
+ if ((pause_reason || pause_for_process_reason || resume_cookie != -1) && !miner_name) {
+ g_printerr ("%s\n",
+ _("You must provide the miner for pause or resume commands"));
+ return EXIT_FAILURE;
+ }
+
+ if ((!pause_reason && !pause_for_process_reason && resume_cookie == -1) && miner_name) {
+ g_printerr ("%s\n",
+ _("You must provide a pause or resume command for the miner"));
+ return EXIT_FAILURE;
+ }
+
+ /* Known actions */
+
+ if (list_miners_running || list_miners_available) {
+ return miner_list (list_miners_available,
+ list_miners_running);
+ }
+
+ if (pause_reason) {
+ return miner_pause (miner_name, pause_reason, FALSE);
+ }
+
+ if (pause_for_process_reason) {
+ return miner_pause (miner_name, pause_for_process_reason, TRUE);
+ }
+
+ if (resume_cookie != -1) {
+ return miner_resume (miner_name, resume_cookie);
+ }
+
+ if (pause_details) {
+ return miner_pause_details ();
+ }
+
+ /* Processes */
+ GError *error = NULL;
+ gpointer verbosity_type_enum_class_pointer = NULL;
+ TrackerVerbosity set_log_verbosity_value = TRACKER_VERBOSITY_ERRORS;
+
+ /* Constraints */
+
+ if (daemons_to_kill != TRACKER_PROCESS_TYPE_NONE && daemons_to_term != TRACKER_PROCESS_TYPE_NONE) {
+ g_printerr ("%s\n",
+ _("You can not use the --kill and --terminate arguments together"));
+ return EXIT_FAILURE;
+ }
+
+ if (get_log_verbosity && set_log_verbosity) {
+ g_printerr ("%s\n",
+ _("You can not use the --get-logging and --set-logging arguments together"));
+ return EXIT_FAILURE;
+ }
+
+ if (set_log_verbosity) {
+ if (g_ascii_strcasecmp (set_log_verbosity, "debug") == 0) {
+ set_log_verbosity_value = TRACKER_VERBOSITY_DEBUG;
+ } else if (g_ascii_strcasecmp (set_log_verbosity, "detailed") == 0) {
+ set_log_verbosity_value = TRACKER_VERBOSITY_DETAILED;
+ } else if (g_ascii_strcasecmp (set_log_verbosity, "minimal") == 0) {
+ set_log_verbosity_value = TRACKER_VERBOSITY_MINIMAL;
+ } else if (g_ascii_strcasecmp (set_log_verbosity, "errors") == 0) {
+ set_log_verbosity_value = TRACKER_VERBOSITY_ERRORS;
+ } else {
+ g_printerr ("%s\n",
+ _("Invalid log verbosity, try 'debug', 'detailed', 'minimal' or
'errors'"));
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (collect_debug_info) {
+ collect_debug ();
+ return EXIT_SUCCESS;
+ }
+
+ if (get_log_verbosity || set_log_verbosity) {
+ GType etype;
+
+ /* Since we don't reference this enum anywhere, we do
+ * it here to make sure it exists when we call
+ * g_type_class_peek(). This wouldn't be necessary if
+ * it was a param in a GObject for example.
+ *
+ * This does mean that we are leaking by 1 reference
+ * here and should clean it up, but it doesn't grow so
+ * this is acceptable.
+ */
+ etype = tracker_verbosity_get_type ();
+ verbosity_type_enum_class_pointer = g_type_class_ref (etype);
+ }
+
+ if (list_processes) {
+ GSList *pids, *l;
+ gchar *str;
+
+ pids = tracker_process_find_all ();
+
+ str = g_strdup_printf (g_dngettext (NULL,
+ "Found %d PID…",
+ "Found %d PIDs…",
+ g_slist_length (pids)),
+ g_slist_length (pids));
+ g_print ("%s\n", str);
+ g_free (str);
+
+ for (l = pids; l; l = l->next) {
+ TrackerProcessData *pd = l->data;
+
+ str = g_strdup_printf (_("Found process ID %d for '%s'"), pd->pid, pd->cmd);
+ g_print ("%s\n", str);
+ g_free (str);
+ }
+
+ g_slist_foreach (pids, (GFunc) tracker_process_data_free, NULL);
+ g_slist_free (pids);
+
+ return EXIT_SUCCESS;
+ }
+
+ if (daemons_to_kill != TRACKER_PROCESS_TYPE_NONE ||
+ daemons_to_term != TRACKER_PROCESS_TYPE_NONE) {
+ exit (tracker_process_stop (daemons_to_term, daemons_to_kill));
+ }
+
+ /* Deal with logging changes AFTER the config may have been
+ * reset, this way users can actually use --remove-config with
+ * the --set-logging switch.
+ */
+ if (get_log_verbosity) {
+ GSList *all;
+ gint longest = 0;
+
+ all = tracker_gsettings_get_all (&longest);
+
+ if (!all) {
+ return EXIT_FAILURE;
+ }
+
+ g_print ("%s:\n", _("Components"));
+ tracker_gsettings_print_verbosity (all, longest, TRUE);
+ g_print ("\n");
+
+ /* Miners */
+ g_print ("%s (%s):\n",
+ _("Miners"),
+ _("Only those with config listed"));
+ tracker_gsettings_print_verbosity (all, longest, FALSE);
+ g_print ("\n");
+
+ tracker_gsettings_free (all);
+ }
+
+ if (set_log_verbosity) {
+ GSList *all;
+ gchar *str;
+ gint longest = 0;
+
+ all = tracker_gsettings_get_all (&longest);
+
+ if (!all) {
+ return EXIT_FAILURE;
+ }
+
+ str = g_strdup_printf (_("Setting log verbosity for all components to '%s'…"),
set_log_verbosity);
+ g_print ("%s\n", str);
+ g_print ("\n");
+ g_free (str);
+
+ tracker_gsettings_set_all (all, set_log_verbosity_value);
+ tracker_gsettings_free (all);
+
+ /* We free to make sure we get new settings and that
+ * they're saved properly.
+ */
+ all = tracker_gsettings_get_all (&longest);
+
+ if (!all) {
+ return EXIT_FAILURE;
+ }
+
+ g_print ("%s:\n", _("Components"));
+ tracker_gsettings_print_verbosity (all, longest, TRUE);
+ g_print ("\n");
+
+ /* Miners */
+ g_print ("%s (%s):\n",
+ _("Miners"),
+ _("Only those with config listed"));
+ tracker_gsettings_print_verbosity (all, longest, FALSE);
+ g_print ("\n");
+
+ tracker_gsettings_free (all);
+ }
+
+ if (verbosity_type_enum_class_pointer) {
+ g_type_class_unref (verbosity_type_enum_class_pointer);
+ }
+
+ if (start) {
+ TrackerMinerManager *manager;
+ GSList *miners, *l;
+
+ g_print ("%s\n", _("Starting miners…"));
+
+ /* Auto-start the miners here */
+ manager = tracker_miner_manager_new_full (TRUE, &error);
+ if (!manager) {
+ g_printerr (_("Could not start miners, manager could not be created, %s"),
+ error ? error->message : _("No error given"));
+ g_printerr ("\n");
+ g_clear_error (&error);
+ return EXIT_FAILURE;
+ }
+
+ miners = tracker_miner_manager_get_available (manager);
+
+ /* Get the status of all miners, this will start all
+ * miners not already running.
+ */
+ for (l = miners; l; l = l->next) {
+ const gchar *display_name;
+ gdouble progress = 0.0;
+
+ display_name = tracker_miner_manager_get_display_name (manager, l->data);
+
+ if (!tracker_miner_manager_get_status (manager,
+ l->data,
+ NULL,
+ &progress,
+ NULL)) {
+ g_printerr (" ✗ %s (%s)\n",
+ display_name,
+ _("perhaps a disabled plugin?"));
+ } else {
+ g_print (" ✓ %s\n",
+ display_name);
+ }
+
+ g_free (l->data);
+ }
+
+ g_slist_free (miners);
+ g_object_unref (manager);
+
+ return EXIT_SUCCESS;
+ }
+
+ if (backup) {
+ GDBusConnection *connection;
+ GDBusProxy *proxy;
+ GError *error = NULL;
+ GVariant *v;
+ gchar *uri;
+
+ if (!tracker_dbus_get_connection ("org.freedesktop.Tracker1",
+ "/org/freedesktop/Tracker1/Backup",
+ "org.freedesktop.Tracker1.Backup",
+ G_DBUS_PROXY_FLAGS_NONE,
+ &connection,
+ &proxy)) {
+ return EXIT_FAILURE;
+ }
+
+ uri = get_uri_from_arg (backup);
+
+ g_print ("%s\n", _("Backing up database"));
+ g_print (" %s\n", uri);
+
+ /* Backup/Restore can take some time */
+ g_dbus_proxy_set_default_timeout (proxy, G_MAXINT);
+
+ v = g_dbus_proxy_call_sync (proxy,
+ "Save",
+ g_variant_new ("(s)", uri),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+
+ if (proxy) {
+ g_object_unref (proxy);
+ }
+
+ if (error) {
+ g_critical ("%s, %s",
+ _("Could not backup database"),
+ error ? error->message : _("No error given"));
+ g_clear_error (&error);
+ g_free (uri);
+
+ return EXIT_FAILURE;
+ }
+
+ if (v) {
+ g_variant_unref (v);
+ }
+
+ g_free (uri);
+ }
+
+ if (restore) {
+ GDBusConnection *connection;
+ GDBusProxy *proxy;
+ GError *error = NULL;
+ GVariant *v;
+ gchar *uri;
+
+ if (!tracker_dbus_get_connection ("org.freedesktop.Tracker1",
+ "/org/freedesktop/Tracker1/Backup",
+ "org.freedesktop.Tracker1.Backup",
+ G_DBUS_PROXY_FLAGS_NONE,
+ &connection,
+ &proxy)) {
+ return EXIT_FAILURE;
+ }
+
+ uri = get_uri_from_arg (restore);
+
+ g_print ("%s\n", _("Restoring database from backup"));
+ g_print (" %s\n", uri);
+
+ /* Backup/Restore can take some time */
+ g_dbus_proxy_set_default_timeout (proxy, G_MAXINT);
+
+ v = g_dbus_proxy_call_sync (proxy,
+ "Restore",
+ g_variant_new ("(s)", uri),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+
+ if (proxy) {
+ g_object_unref (proxy);
+ }
+
+ if (error) {
+ g_critical ("%s, %s",
+ _("Could not backup database"),
+ error ? error->message : _("No error given"));
+ g_clear_error (&error);
+ g_free (uri);
+
+ return EXIT_FAILURE;
+ }
+
+ if (v) {
+ g_variant_unref (v);
+ }
+
+ g_free (uri);
+ }
+
+ /* All known options have their own exit points */
+ g_warn_if_reached ();
+
+ return EXIT_FAILURE;
+}
+
+GOptionGroup *
+tracker_daemon_get_option_group (void)
+{
+ GOptionGroup *group;
+
+ /* Status options */
+ group = g_option_group_new ("Daemon",
+ _("Daemon options"),
+ _("Show daemon options"),
+ NULL,
+ NULL);
+ g_option_group_add_entries (group, entries);
+
+ return group;
+}
+
+gboolean
+tracker_daemon_options_enabled (void)
+{
+ return DAEMON_OPTIONS_ENABLED ();
+}
diff --git a/src/tracker/tracker-daemon.h b/src/tracker/tracker-daemon.h
new file mode 100644
index 0000000..b757fea
--- /dev/null
+++ b/src/tracker/tracker-daemon.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014, Nokia <ivan frade nokia com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <glib.h>
+
+#ifndef __TRACKER_DAEMON_H__
+#define __TRACKER_DAEMON_H__
+
+gint tracker_daemon_run (void);
+void tracker_daemon_run_default (void);
+GOptionGroup *tracker_daemon_get_option_group (void);
+gboolean tracker_daemon_options_enabled (void);
+
+#endif /* __TRACKER_DAEMON_H__ */
diff --git a/src/tracker-utils/tracker-import.c b/src/tracker/tracker-import.c
similarity index 100%
rename from src/tracker-utils/tracker-import.c
rename to src/tracker/tracker-import.c
diff --git a/src/tracker/tracker-index.c b/src/tracker/tracker-index.c
new file mode 100644
index 0000000..edbb204
--- /dev/null
+++ b/src/tracker/tracker-index.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2014, Nokia <ivan frade nokia com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#ifdef __sun
+#include <procfs.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include <libtracker-control/tracker-control.h>
+
+#include "tracker-index.h"
+
+static const gchar **reindex_mime_types;
+static gchar *index_file;
+
+#define INDEX_OPTIONS_ENABLED() \
+ (reindex_mime_types || index_file)
+
+static GOptionEntry entries[] = {
+ { "reindex-mime-type", 'm', 0, G_OPTION_ARG_STRING_ARRAY, &reindex_mime_types,
+ N_("Tell miners to reindex files which match the mime type supplied (for new extractors), use -m
MIME1 -m MIME2"),
+ N_("MIME") },
+ { "index-file", 'f', 0, G_OPTION_ARG_FILENAME, &index_file,
+ N_("Tell miners to (re)index a given file"),
+ N_("FILE") },
+ { NULL }
+};
+
+static gint
+miner_reindex_mime_types (const gchar **mime_types)
+{
+ GError *error = NULL;
+ TrackerMinerManager *manager;
+
+ /* Auto-start the miners here if we need to */
+ manager = tracker_miner_manager_new_full (TRUE, &error);
+ if (!manager) {
+ g_printerr (_("Could not reindex mimetypes, manager could not be created, %s"),
+ error ? error->message : _("No error given"));
+ g_printerr ("\n");
+ g_clear_error (&error);
+ return EXIT_FAILURE;
+ }
+
+ tracker_miner_manager_reindex_by_mimetype (manager, (GStrv)reindex_mime_types, &error);
+ if (error) {
+ g_printerr ("%s: %s\n",
+ _("Could not reindex mimetypes"),
+ error->message);
+ g_error_free (error);
+ return EXIT_FAILURE;
+ }
+
+ g_print ("%s\n", _("Reindexing mime types was successful"));
+ g_object_unref (manager);
+
+ return EXIT_SUCCESS;
+}
+
+static gint
+miner_index_file (const gchar *filepath)
+{
+ TrackerMinerManager *manager;
+ GError *error = NULL;
+ GFile *file;
+
+ /* Auto-start the miners here if we need to */
+ manager = tracker_miner_manager_new_full (TRUE, &error);
+ if (!manager) {
+ g_printerr (_("Could not (re)index file, manager could not be created, %s"),
+ error ? error->message : _("No error given"));
+ g_printerr ("\n");
+ g_clear_error (&error);
+ return EXIT_FAILURE;
+ }
+
+ file = g_file_new_for_commandline_arg (index_file);
+
+ tracker_miner_manager_index_file (manager, file, &error);
+
+ if (error) {
+ g_printerr ("%s: %s\n",
+ _("Could not (re)index file"),
+ error->message);
+ g_error_free (error);
+ return EXIT_FAILURE;
+ }
+
+ g_print ("%s\n", _("(Re)indexing file was successful"));
+
+ g_object_unref (manager);
+ g_object_unref (file);
+
+ return EXIT_SUCCESS;
+}
+
+void
+tracker_index_run_default (void)
+{
+ /* Set options in here we want to run by default with no args */
+
+ tracker_index_run ();
+}
+
+gint
+tracker_index_run (void)
+{
+ if (reindex_mime_types) {
+ return miner_reindex_mime_types (reindex_mime_types);
+ }
+
+ if (index_file) {
+ return miner_index_file (index_file);
+ }
+
+ /* All known options have their own exit points */
+ g_warn_if_reached ();
+
+ return EXIT_FAILURE;
+}
+
+GOptionGroup *
+tracker_index_get_option_group (void)
+{
+ GOptionGroup *group;
+
+ /* Status options */
+ group = g_option_group_new ("Index",
+ _("Index options"),
+ _("Show index options"),
+ NULL,
+ NULL);
+ g_option_group_add_entries (group, entries);
+
+ return group;
+}
+
+gboolean
+tracker_index_options_enabled (void)
+{
+ return INDEX_OPTIONS_ENABLED ();
+}
diff --git a/src/tracker/tracker-index.h b/src/tracker/tracker-index.h
new file mode 100644
index 0000000..e75f1d9
--- /dev/null
+++ b/src/tracker/tracker-index.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014, Nokia <ivan frade nokia com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <glib.h>
+
+#ifndef __TRACKER_INDEX_H__
+#define __TRACKER_INDEX_H__
+
+gint tracker_index_run (void);
+void tracker_index_run_default (void);
+GOptionGroup *tracker_index_get_option_group (void);
+gboolean tracker_index_options_enabled (void);
+
+#endif /* __TRACKER_INDEX_H__ */
diff --git a/src/tracker-utils/tracker-info.c b/src/tracker/tracker-info.c
similarity index 100%
rename from src/tracker-utils/tracker-info.c
rename to src/tracker/tracker-info.c
diff --git a/src/tracker/tracker-main.c b/src/tracker/tracker-main.c
new file mode 100644
index 0000000..508e15f
--- /dev/null
+++ b/src/tracker/tracker-main.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2014, Lanedo GmbH <martyn lanedo com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include <libtracker-common/tracker-common.h>
+
+#include "tracker-control.h"
+#include "tracker-daemon.h"
+#include "tracker-index.h"
+#include "tracker-reset.h"
+#include "tracker-help.h"
+
+const char usage_string[] =
+ "tracker [--version] [--help]\n"
+ " <command> [<args>]";
+
+const char usage_more_info_string[] =
+ N_("See 'tracker help <command>' to read about a specific subcommand.");
+
+const char about[] =
+ "Tracker " PACKAGE_VERSION "\n"
+ "\n"
+ "This program is free software and comes without any warranty.\n"
+ "It is licensed under version 2 or later of the General Public "
+ "License which can be viewed at:\n"
+ "\n"
+ " http://www.gnu.org/licenses/gpl.txt"
+ "\n";
+
+static void print_usage (void);
+
+static int
+cmd_backup (int argc, const char **argv, const char *prefix)
+{
+
+
+ return 0;
+}
+
+static int
+cmd_daemon (int argc, const char **argv, const char *prefix)
+{
+ GOptionContext *context;
+ GError *error = NULL;
+
+ context = g_option_context_new (NULL);
+ g_option_context_add_group (context, tracker_daemon_get_option_group ());
+
+ /* Common options */
+ /* g_option_context_add_main_entries (context, common_entries, NULL); */
+
+ if (!g_option_context_parse (context, &argc, (char***) &argv, &error)) {
+ g_printerr ("%s, %s\n", _("Unrecognized options"), error->message);
+ g_error_free (error);
+ g_option_context_free (context);
+ return 1;
+ }
+
+ g_option_context_free (context);
+
+ if (tracker_daemon_options_enabled ()) {
+ return tracker_daemon_run ();
+ }
+
+ tracker_daemon_run_default ();
+
+ return 0;
+}
+
+static int
+cmd_import (int argc, const char **argv, const char *prefix)
+{
+ return 0;
+}
+
+static int
+cmd_help (int argc, const char **argv, const char *prefix)
+{
+ if (!argv[0] || !argv[1]) {
+ print_usage ();
+ return 0;
+ }
+
+ tracker_help_show_man_page (argv[1]);
+
+ return 0;
+}
+
+static int
+cmd_info (int argc, const char **argv, const char *prefix)
+{
+ return 0;
+}
+
+static int
+cmd_index (int argc, const char **argv, const char *prefix)
+{
+ GOptionContext *context;
+ GError *error = NULL;
+
+ context = g_option_context_new (NULL);
+ g_option_context_add_group (context, tracker_index_get_option_group ());
+
+ /* Common options */
+ /* g_option_context_add_main_entries (context, common_entries, NULL); */
+
+ if (!g_option_context_parse (context, &argc, (char***) &argv, &error)) {
+ g_printerr ("%s, %s\n", _("Unrecognized options"), error->message);
+ g_error_free (error);
+ g_option_context_free (context);
+ return 1;
+ }
+
+ g_option_context_free (context);
+
+ if (tracker_index_options_enabled ()) {
+ return tracker_index_run ();
+ }
+
+ tracker_index_run_default ();
+
+ return 0;
+}
+
+static int
+cmd_reset (int argc, const char **argv, const char *prefix)
+{
+ GOptionContext *context;
+ GError *error = NULL;
+
+ context = g_option_context_new (NULL);
+ g_option_context_add_group (context, tracker_reset_get_option_group ());
+
+ /* Common options */
+ /* g_option_context_add_main_entries (context, common_entries, NULL); */
+
+ if (!g_option_context_parse (context, &argc, (char***) &argv, &error)) {
+ g_printerr ("%s, %s\n", _("Unrecognized options"), error->message);
+ g_error_free (error);
+ g_option_context_free (context);
+ return 1;
+ }
+
+ g_option_context_free (context);
+
+ if (tracker_reset_options_enabled ()) {
+ return tracker_reset_run ();
+ }
+
+ tracker_reset_run_default ();
+
+ return 0;
+}
+
+static int
+cmd_restore (int argc, const char **argv, const char *prefix)
+{
+ return 0;
+}
+
+static int
+cmd_search (int argc, const char **argv, const char *prefix)
+{
+ return 0;
+}
+
+static int
+cmd_sparql (int argc, const char **argv, const char *prefix)
+{
+ return 0;
+}
+
+static int
+cmd_stats (int argc, const char **argv, const char *prefix)
+{
+ return 0;
+}
+
+static int
+cmd_status (int argc, const char **argv, const char *prefix)
+{
+ return 0;
+}
+
+static int
+cmd_tag (int argc, const char **argv, const char *prefix)
+{
+ return 0;
+}
+
+static int
+cmd_version (int argc, const char **argv, const char *prefix)
+{
+ puts (about);
+ return 0;
+}
+
+
+/*
+ * require working tree to be present -- anything uses this needs
+ * RUN_SETUP for reading from the configuration file.
+ */
+#define NEED_NOTHING (1<<0)
+#define NEED_WORK_TREE (1<<1)
+
+struct cmd_struct {
+ const char *cmd;
+ int (*fn)(int, const char **, const char *);
+ int option;
+ const char *help;
+};
+
+static struct cmd_struct commands[] = {
+ { "backup", cmd_backup, NEED_WORK_TREE, N_("Backup indexed content") },
+ { "daemon", cmd_daemon, NEED_WORK_TREE, N_("Start, stop, restart and list daemons responsible for
indexing content") },
+ { "import", cmd_import, NEED_WORK_TREE, N_("Import a data set into the index") },
+ { "help", cmd_help, NEED_NOTHING, N_("Get help on how to use Tracker and any of these commands") },
+ { "info", cmd_info, NEED_WORK_TREE, N_("Show information known about local files or items indexed")
},
+ { "index", cmd_index, NEED_NOTHING, N_("List, pause, resume and command data miners indexing
content") },
+ { "reset", cmd_reset, NEED_NOTHING, N_("Reset the index, configuration or replay journal") },
+ { "restore", cmd_restore, NEED_NOTHING, N_("Restore the index from a previous backup") },
+ { "search", cmd_search, NEED_WORK_TREE, N_("Search the index by RDF class") },
+ { "sparql", cmd_sparql, NEED_WORK_TREE, N_("Query and update the index using SPARQL or search and
list ontology in use") },
+ { "stats", cmd_stats, NEED_WORK_TREE, N_("Show statistical information about indexed content") },
+ { "status", cmd_status, NEED_NOTHING, N_("Show the index status for the working tree") },
+ { "tag", cmd_tag, NEED_WORK_TREE, N_("Create, list or delete tags and related content") },
+ { "version", cmd_version, NEED_NOTHING, N_("Show the license and version in use") },
+};
+
+static int
+run_builtin (struct cmd_struct *p, int argc, const char **argv)
+{
+ int status, help;
+ const char *prefix;
+
+ prefix = NULL;
+ help = argc == 2 && !strcmp (argv[1], "-h");
+
+ if (!help && p->option & NEED_WORK_TREE) {
+ /* Check we have working tree */
+ /* FIXME: Finish */
+ }
+
+ status = p->fn (argc, argv, prefix);
+ if (status) {
+ return status;
+ }
+
+ return 0;
+}
+
+static void
+handle_command (int argc, const char **argv)
+{
+ const char *cmd = argv[0];
+ int i;
+
+ /* Turn "tracker cmd --help" into "tracker help cmd" */
+ if (argc > 1 && !strcmp (argv[1], "--help")) {
+ argv[1] = argv[0];
+ argv[0] = cmd = "help";
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (commands); i++) {
+ struct cmd_struct *p = commands + i;
+
+ if (strcmp (p->cmd, cmd)) {
+ continue;
+ }
+
+ exit (run_builtin (p, argc, argv));
+ }
+}
+
+static inline void
+mput_char (char c, unsigned int num)
+{
+ while (num--) {
+ putchar (c);
+ }
+}
+
+static void
+print_usage_list_cmds (void)
+{
+ int i, longest = 0;
+
+ for (i = 0; i < G_N_ELEMENTS(commands); i++) {
+ if (longest < strlen (commands[i].cmd))
+ longest = strlen(commands[i].cmd);
+ }
+
+ puts (_("Available tracker commands are:"));
+ for (i = 0; i < G_N_ELEMENTS(commands); i++) {
+ /* Don't list version in commands */
+ if (!strcmp (commands[i].cmd, "version") ||
+ !strcmp (commands[i].cmd, "help")) {
+ continue;
+ }
+
+ g_print(" %s ", commands[i].cmd);
+ mput_char (' ', longest - strlen (commands[i].cmd));
+ puts(_(commands[i].help));
+ }
+}
+
+static void
+print_usage (void)
+{
+ g_print("usage: %s\n\n", usage_string);
+ print_usage_list_cmds ();
+ g_print("\n%s\n", _(usage_more_info_string));
+}
+
+int
+main (int argc, char **av)
+{
+ const char **argv = (const char **) av;
+
+ setlocale (LC_ALL, "");
+
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ argv++;
+ argc--;
+
+ if (argc > 0) {
+ /* For cases like --version */
+ if (g_str_has_prefix (argv[0], "--")) {
+ argv[0] += 2;
+ }
+ } else {
+ /* The user didn't specify a command; give them help */
+ print_usage ();
+ exit (1);
+ }
+
+ handle_command (argc, argv);
+
+ return 1;
+}
diff --git a/src/tracker/tracker-process.c b/src/tracker/tracker-process.c
new file mode 100644
index 0000000..4057e14
--- /dev/null
+++ b/src/tracker/tracker-process.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2010, Nokia <ivan frade nokia com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "tracker-process.h"
+
+static TrackerProcessData *
+process_data_new (gchar *cmd, pid_t pid)
+{
+ TrackerProcessData *pd;
+
+ pd = g_slice_new0 (TrackerProcessData);
+ pd->cmd = cmd;
+ pd->pid = pid;
+
+ return pd;
+}
+
+void
+tracker_process_data_free (TrackerProcessData *pd)
+{
+ if (!pd) {
+ return;
+ }
+
+ g_free (pd->cmd);
+ g_slice_free (TrackerProcessData, pd);
+}
+
+GSList *
+tracker_process_get_pids (void)
+{
+ GError *error = NULL;
+ GDir *dir;
+ GSList *pids = NULL;
+ const gchar *name;
+
+ dir = g_dir_open ("/proc", 0, &error);
+ if (error) {
+ g_printerr ("%s: %s\n",
+ _("Could not open /proc"),
+ error ? error->message : _("No error given"));
+ g_clear_error (&error);
+ return NULL;
+ }
+
+ while ((name = g_dir_read_name (dir)) != NULL) {
+ gchar c;
+ gboolean is_pid = TRUE;
+
+ for (c = *name; c && c != ':' && is_pid; c++) {
+ is_pid &= g_ascii_isdigit (c);
+ }
+
+ if (!is_pid) {
+ continue;
+ }
+
+ pids = g_slist_prepend (pids, g_strdup (name));
+ }
+
+ g_dir_close (dir);
+
+ return g_slist_reverse (pids);
+}
+
+guint32
+tracker_process_get_uid_for_pid (const gchar *pid_as_string,
+ gchar **filename)
+{
+ GFile *f;
+ GFileInfo *info;
+ GError *error = NULL;
+ gchar *fn;
+ guint uid;
+
+#ifdef __sun /* Solaris */
+ fn = g_build_filename ("/proc", pid_as_string, "psinfo", NULL);
+#else
+ fn = g_build_filename ("/proc", pid_as_string, "cmdline", NULL);
+#endif
+
+ f = g_file_new_for_path (fn);
+ info = g_file_query_info (f,
+ G_FILE_ATTRIBUTE_UNIX_UID,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL,
+ &error);
+
+ if (error) {
+ g_printerr ("%s '%s', %s", _("Could not stat() file"), fn, error->message);
+ g_error_free (error);
+ uid = 0;
+ } else {
+ uid = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID);
+ g_object_unref (info);
+ }
+
+ if (filename) {
+ *filename = fn;
+ } else {
+ g_free (fn);
+ }
+
+ g_object_unref (f);
+
+ return uid;
+}
+
+GSList *
+tracker_process_find_all (void)
+{
+ GSList *pids, *l;
+ GSList *found_pids = NULL;
+ guint32 own_pid;
+ guint32 own_uid;
+ gchar *own_pid_str;
+
+ /* Unless we are stopping processes or listing processes,
+ * don't iterate them.
+ */
+ pids = tracker_process_get_pids ();
+
+ /* Establish own uid/pid */
+ own_pid = (guint32) getpid ();
+ own_pid_str = g_strdup_printf ("%d", own_pid);
+ own_uid = tracker_process_get_uid_for_pid (own_pid_str, NULL);
+ g_free (own_pid_str);
+
+ for (l = pids; l; l = l->next) {
+ GError *error = NULL;
+ gchar *filename;
+#ifdef __sun /* Solaris */
+ psinfo_t psinfo = { 0 };
+#endif
+ gchar *contents = NULL;
+ gchar **strv;
+ guint uid;
+ pid_t pid;
+
+ uid = tracker_process_get_uid_for_pid (l->data, &filename);
+
+ /* Stat the file and make sure current user == file owner */
+ if (uid != own_uid) {
+ continue;
+ }
+
+ pid = atoi (l->data);
+
+ /* Don't return our own PID */
+ if (pid == own_pid) {
+ continue;
+ }
+
+ /* Get contents to determine basename */
+ if (!g_file_get_contents (filename, &contents, NULL, &error)) {
+ gchar *str;
+
+ str = g_strdup_printf (_("Could not open '%s'"), filename);
+ g_printerr ("%s: %s\n",
+ str,
+ error ? error->message : _("No error given"));
+ g_free (str);
+ g_clear_error (&error);
+ g_free (contents);
+ g_free (filename);
+
+ continue;
+ }
+#ifdef __sun /* Solaris */
+ memcpy (&psinfo, contents, sizeof (psinfo));
+
+ /* won't work with paths containing spaces :( */
+ strv = g_strsplit (psinfo.pr_psargs, " ", 2);
+#else
+ strv = g_strsplit (contents, "^@", 2);
+#endif
+ if (strv && strv[0]) {
+ gchar *basename;
+
+ basename = g_path_get_basename (strv[0]);
+
+ if ((g_str_has_prefix (basename, "tracker") ||
+ g_str_has_prefix (basename, "lt-tracker"))) {
+ found_pids = g_slist_prepend (found_pids, process_data_new (basename, pid));
+ } else {
+ g_free (basename);
+ }
+ }
+
+ g_strfreev (strv);
+ g_free (contents);
+ g_free (filename);
+ }
+
+ g_slist_foreach (pids, (GFunc) g_free, NULL);
+ g_slist_free (pids);
+
+ return g_slist_reverse (found_pids);
+}
+
+gint
+tracker_process_stop (TrackerProcessTypes daemons_to_term,
+ TrackerProcessTypes daemons_to_kill)
+{
+ GSList *pids, *l;
+ gchar *str;
+
+ if (daemons_to_kill == TRACKER_PROCESS_TYPE_NONE &&
+ daemons_to_term == TRACKER_PROCESS_TYPE_NONE) {
+ return 0;
+ }
+
+ pids = tracker_process_find_all ();
+
+ str = g_strdup_printf (g_dngettext (NULL,
+ "Found %d PID…",
+ "Found %d PIDs…",
+ g_slist_length (pids)),
+ g_slist_length (pids));
+ g_print ("%s\n", str);
+ g_free (str);
+
+ for (l = pids; l; l = l->next) {
+ TrackerProcessData *pd;
+ const gchar *basename;
+ pid_t pid;
+
+ pd = l->data;
+ basename = pd->cmd;
+ pid = pd->pid;
+
+ if (daemons_to_term != TRACKER_PROCESS_TYPE_NONE) {
+ if ((daemons_to_term == TRACKER_PROCESS_TYPE_STORE &&
+ !g_str_has_suffix (basename, "tracker-store")) ||
+ (daemons_to_term == TRACKER_PROCESS_TYPE_MINERS &&
+ !strstr (basename, "tracker-miner"))) {
+ continue;
+ }
+
+ if (kill (pid, SIGTERM) == -1) {
+ const gchar *errstr = g_strerror (errno);
+
+ str = g_strdup_printf (_("Could not terminate process %d - '%s'"), pid,
basename);
+ g_printerr (" %s: %s\n",
+ str,
+ errstr ? errstr : _("No error given"));
+ g_free (str);
+ } else {
+ str = g_strdup_printf (_("Terminated process %d - '%s'"), pid, basename);
+ g_print (" %s\n", str);
+ g_free (str);
+ }
+ } else if (daemons_to_kill != TRACKER_PROCESS_TYPE_NONE) {
+ if ((daemons_to_kill == TRACKER_PROCESS_TYPE_STORE &&
+ !g_str_has_suffix (basename, "tracker-store")) ||
+ (daemons_to_kill == TRACKER_PROCESS_TYPE_MINERS &&
+ !strstr (basename, "tracker-miner"))) {
+ continue;
+ }
+
+ if (kill (pid, SIGKILL) == -1) {
+ const gchar *errstr = g_strerror (errno);
+
+ str = g_strdup_printf (_("Could not kill process %d - '%s'"), pid, basename);
+ g_printerr (" %s: %s\n",
+ str,
+ errstr ? errstr : _("No error given"));
+ g_free (str);
+ } else {
+ str = g_strdup_printf (_("Killed process %d - '%s'"), pid, basename);
+ g_print (" %s\n", str);
+ g_free (str);
+ }
+ }
+ }
+
+ g_slist_foreach (pids, (GFunc) tracker_process_data_free, NULL);
+ g_slist_free (pids);
+
+ return 0;
+}
diff --git a/src/tracker/tracker-process.h b/src/tracker/tracker-process.h
new file mode 100644
index 0000000..bf8a0a4
--- /dev/null
+++ b/src/tracker/tracker-process.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014, Nokia <ivan frade nokia com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#ifndef __TRACKER_PROCESS_H__
+#define __TRACKER_PROCESS_H__
+
+typedef struct {
+ char *cmd;
+ pid_t pid;
+} TrackerProcessData;
+
+typedef enum {
+ TRACKER_PROCESS_TYPE_NONE,
+ TRACKER_PROCESS_TYPE_ALL,
+ TRACKER_PROCESS_TYPE_STORE,
+ TRACKER_PROCESS_TYPE_MINERS
+} TrackerProcessTypes;
+
+GSList * tracker_process_get_pids (void);
+guint32 tracker_process_get_uid_for_pid (const gchar *pid_as_string,
+ gchar **filename);
+
+void tracker_process_data_free (TrackerProcessData *pd);
+
+GSList * tracker_process_find_all (void);
+gint tracker_process_stop (TrackerProcessTypes daemons_to_term,
+ TrackerProcessTypes daemons_to_kill);
+
+#endif /* __TRACKER_PROCESS_H__ */
diff --git a/src/tracker/tracker-reset.c b/src/tracker/tracker-reset.c
new file mode 100644
index 0000000..57e9162
--- /dev/null
+++ b/src/tracker/tracker-reset.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2014, Nokia <ivan frade nokia com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gprintf.h>
+#include <gio/gio.h>
+
+#include <libtracker-common/tracker-common.h>
+#include <libtracker-data/tracker-data.h>
+
+#include "tracker-reset.h"
+#include "tracker-daemon.h"
+#include "tracker-process.h"
+#include "tracker-config.h"
+
+static gboolean hard_reset;
+static gboolean soft_reset;
+static gboolean remove_config;
+
+#define RESET_OPTIONS_ENABLED() \
+ (hard_reset || \
+ soft_reset || \
+ remove_config)
+
+static GOptionEntry entries[] = {
+ { "hard-reset", 'r', 0, G_OPTION_ARG_NONE, &hard_reset,
+ N_("Kill all Tracker processes and remove all databases"),
+ NULL },
+ { "soft-reset", 'e', 0, G_OPTION_ARG_NONE, &soft_reset,
+ N_("Same as --hard-reset but the backup & journal are restored after restart"),
+ NULL },
+ { "remove-config", 'c', 0, G_OPTION_ARG_NONE, &remove_config,
+ N_("Remove all configuration files so they are re-generated on next start"),
+ NULL },
+ { NULL }
+};
+
+static void
+log_handler (const gchar *domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data)
+{
+ switch (log_level) {
+ case G_LOG_LEVEL_WARNING:
+ case G_LOG_LEVEL_CRITICAL:
+ case G_LOG_LEVEL_ERROR:
+ case G_LOG_FLAG_RECURSION:
+ case G_LOG_FLAG_FATAL:
+ g_fprintf (stderr, "%s\n", message);
+ fflush (stderr);
+ break;
+ case G_LOG_LEVEL_MESSAGE:
+ case G_LOG_LEVEL_INFO:
+ case G_LOG_LEVEL_DEBUG:
+ case G_LOG_LEVEL_MASK:
+ default:
+ g_fprintf (stdout, "%s\n", message);
+ fflush (stdout);
+ break;
+ }
+}
+
+static void
+delete_file (GFile *file,
+ gpointer user_data)
+{
+ if (g_file_delete (file, NULL, NULL)) {
+ gchar *path;
+
+ path = g_file_get_path (file);
+ g_print (" %s\n", path);
+ g_free (path);
+ }
+}
+
+static void
+directory_foreach (GFile *file,
+ gchar *suffix,
+ GFunc func,
+ gpointer user_data)
+{
+ GFileEnumerator *enumerator;
+ GFileInfo *info;
+ GFile *child;
+
+ enumerator = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NONE, NULL, NULL);
+
+ while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL) {
+
+ if (!suffix || g_str_has_suffix (g_file_info_get_name (info), suffix)) {
+ child = g_file_enumerator_get_child (enumerator, info);
+ (func) (child, user_data);
+ g_object_unref (child);
+ }
+
+ g_object_unref (info);
+ }
+
+ g_object_unref (enumerator);
+}
+
+void
+tracker_reset_run_default (void)
+{
+ /* Set options in here we want to run by default with no args */
+
+ tracker_reset_run ();
+}
+
+gint
+tracker_reset_run (void)
+{
+ TrackerProcessTypes kill_option = TRACKER_PROCESS_TYPE_NONE;
+ GError *error = NULL;
+
+ if (hard_reset && soft_reset) {
+ g_printerr ("%s\n",
+ _("You can not use the --hard-reset and --soft-reset arguments together"));
+ return EXIT_FAILURE;
+ }
+
+ if (hard_reset || soft_reset) {
+ /* Imply --kill */
+ kill_option = TRACKER_PROCESS_TYPE_ALL;
+ /* FIXME: Kill all before doing reset ... */
+ }
+
+ if (hard_reset || soft_reset) {
+ guint log_handler_id;
+#ifndef DISABLE_JOURNAL
+ gchar *rotate_to;
+ TrackerDBConfig *db_config;
+ gsize chunk_size;
+ gint chunk_size_mb;
+#endif /* DISABLE_JOURNAL */
+
+ /* Set log handler for library messages */
+ log_handler_id = g_log_set_handler (NULL,
+ G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL,
+ log_handler,
+ NULL);
+
+ g_log_set_default_handler (log_handler, NULL);
+
+#ifndef DISABLE_JOURNAL
+ db_config = tracker_db_config_new ();
+
+ chunk_size_mb = tracker_db_config_get_journal_chunk_size (db_config);
+ chunk_size = (gsize) ((gsize) chunk_size_mb * (gsize) 1024 * (gsize) 1024);
+ rotate_to = tracker_db_config_get_journal_rotate_destination (db_config);
+
+ /* This call is needed to set the journal's filename */
+ tracker_db_journal_set_rotating ((chunk_size_mb != -1),
+ chunk_size, rotate_to);
+
+ g_free (rotate_to);
+ g_object_unref (db_config);
+
+#endif /* DISABLE_JOURNAL */
+
+ /* Clean up (select_cache_size and update_cache_size don't matter here) */
+ if (!tracker_db_manager_init (TRACKER_DB_MANAGER_REMOVE_ALL,
+ NULL,
+ FALSE,
+ FALSE,
+ 100,
+ 100,
+ NULL,
+ NULL,
+ NULL,
+ &error)) {
+
+ g_message ("Error initializing database: %s", error->message);
+ g_free (error);
+
+ return EXIT_FAILURE;
+ }
+#ifndef DISABLE_JOURNAL
+ tracker_db_journal_init (NULL, FALSE, NULL);
+#endif /* DISABLE_JOURNAL */
+
+ tracker_db_manager_remove_all (hard_reset);
+ tracker_db_manager_shutdown ();
+#ifndef DISABLE_JOURNAL
+ tracker_db_journal_shutdown (NULL);
+#endif /* DISABLE_JOURNAL */
+
+ /* Unset log handler */
+ g_log_remove_handler (NULL, log_handler_id);
+ }
+
+ if (remove_config) {
+ GFile *file;
+ const gchar *home_conf_dir;
+ gchar *path;
+ GSList *all, *l;
+
+ /* Check the default XDG_DATA_HOME location */
+ home_conf_dir = g_getenv ("XDG_CONFIG_HOME");
+
+ if (home_conf_dir && tracker_path_has_write_access_or_was_created (home_conf_dir)) {
+ path = g_build_path (G_DIR_SEPARATOR_S, home_conf_dir, "tracker", NULL);
+ } else {
+ home_conf_dir = g_getenv ("HOME");
+
+ if (!home_conf_dir || !tracker_path_has_write_access_or_was_created (home_conf_dir)) {
+ home_conf_dir = g_get_home_dir ();
+ }
+ path = g_build_path (G_DIR_SEPARATOR_S, home_conf_dir, ".config", "tracker", NULL);
+ }
+
+ file = g_file_new_for_path (path);
+ g_free (path);
+
+ g_print ("%s\n", _("Removing configuration files…"));
+
+ directory_foreach (file, ".cfg", (GFunc) delete_file, NULL);
+ g_object_unref (file);
+
+ g_print ("%s\n", _("Resetting existing configuration…"));
+
+ all = tracker_gsettings_get_all (NULL);
+
+ if (!all) {
+ return EXIT_FAILURE;
+ }
+
+ for (l = all; l; l = l->next) {
+ ComponentGSettings *c = l->data;
+ gchar **keys, **p;
+
+ if (!c) {
+ continue;
+ }
+
+ g_print (" %s\n", c->name);
+
+ keys = g_settings_list_keys (c->settings);
+ for (p = keys; p && *p; p++) {
+ g_print (" %s\n", *p);
+ g_settings_reset (c->settings, *p);
+ }
+
+ if (keys) {
+ g_strfreev (keys);
+ }
+
+ g_settings_apply (c->settings);
+ }
+
+ g_settings_sync ();
+
+ tracker_gsettings_free (all);
+ }
+
+ /* All known options have their own exit points */
+ g_warn_if_reached ();
+
+ return EXIT_FAILURE;
+}
+
+GOptionGroup *
+tracker_reset_get_option_group (void)
+{
+ GOptionGroup *group;
+
+ /* Status options */
+ group = g_option_group_new ("Reset",
+ _("Reset options"),
+ _("Show reset options"),
+ NULL,
+ NULL);
+ g_option_group_add_entries (group, entries);
+
+ return group;
+}
+
+gboolean
+tracker_reset_options_enabled (void)
+{
+ return RESET_OPTIONS_ENABLED ();
+}
diff --git a/src/tracker/tracker-reset.h b/src/tracker/tracker-reset.h
new file mode 100644
index 0000000..d6bb2e4
--- /dev/null
+++ b/src/tracker/tracker-reset.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014, Nokia <ivan frade nokia com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <glib.h>
+
+#ifndef __TRACKER_RESET_H__
+#define __TRACKER_RESET_H__
+
+gint tracker_reset_run (void);
+void tracker_reset_run_default (void);
+GOptionGroup *tracker_reset_get_option_group (void);
+gboolean tracker_reset_options_enabled (void);
+
+#endif /* __TRACKER_RESET_H__ */
diff --git a/src/tracker-utils/tracker-search.c b/src/tracker/tracker-search.c
similarity index 100%
rename from src/tracker-utils/tracker-search.c
rename to src/tracker/tracker-search.c
diff --git a/src/tracker-utils/tracker-sparql.c b/src/tracker/tracker-sparql.c
similarity index 100%
rename from src/tracker-utils/tracker-sparql.c
rename to src/tracker/tracker-sparql.c
diff --git a/src/tracker-utils/tracker-stats.c b/src/tracker/tracker-stats.c
similarity index 100%
rename from src/tracker-utils/tracker-stats.c
rename to src/tracker/tracker-stats.c
diff --git a/src/tracker-utils/tracker-tag.c b/src/tracker/tracker-tag.c
similarity index 100%
rename from src/tracker-utils/tracker-tag.c
rename to src/tracker/tracker-tag.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]