[PackageKit-commit] packagekit: Branch 'master' - 22 commits
Richard Hughes
hughsient at kemper.freedesktop.org
Mon Jul 13 03:25:33 PDT 2009
.gitignore | 1
backends/dummy/pk-backend-dummy.c | 2
backends/portage/portageBackend.py | 170 +++--
client/pk-console.c | 14
docs/api/.gitignore | 1
docs/security.txt | 78 ++
etc/PackageKit.conf.in | 35 +
lib/packagekit-glib/pk-enum.c | 5
lib/packagekit-glib/pk-enum.h | 7
po/pl.po | 209 +++---
src/Makefile.am | 6
src/gdb.sh | 2
src/pk-engine.c | 13
src/pk-engine.h | 1
src/pk-lsof.c | 344 ++++++++++
src/pk-lsof.h | 59 +
src/pk-post-trans.c | 889 ----------------------------
src/pk-post-trans.h | 63 -
src/pk-self-test.c | 2
src/pk-transaction-extra.c | 1167 +++++++++++++++++++++++++++++++++++++
src/pk-transaction-extra.h | 65 ++
src/pk-transaction-list.c | 78 ++
src/pk-transaction-list.h | 3
src/pk-transaction.c | 317 +++++++++-
src/pk-transaction.h | 1
25 files changed, 2404 insertions(+), 1128 deletions(-)
New commits:
commit 9a276f6ec7cc270f07aab6f0be5e37891d36d2f0
Author: Richard Hughes <richard at hughsie.com>
Date: Mon Jul 13 10:45:24 2009 +0100
Add a security document after some initial review
diff --git a/.gitignore b/.gitignore
index ec41eff..02af524 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,7 +51,6 @@ py-compile
tags
*.patch
NEWS.new
-*.txt
.lock-wscript
.waf-*
_build_
diff --git a/docs/api/.gitignore b/docs/api/.gitignore
index f580302..3c13afb 100644
--- a/docs/api/.gitignore
+++ b/docs/api/.gitignore
@@ -4,6 +4,7 @@ Makefile.libs
*.bak
*.gcno
*.out
+*.txt
tmpl
xml
html
diff --git a/docs/security.txt b/docs/security.txt
new file mode 100644
index 0000000..5aff5a2
--- /dev/null
+++ b/docs/security.txt
@@ -0,0 +1,78 @@
+ Security and PackageKit
+
+This document is a brief overview of security policies and notes about security
+in the PackageKit project. It has been written by the PackageKit authors, and
+should not be treated as independent analysis. This document has been written as
+packagekitd is a system activated daemon running as the root user (uid 0), which
+means the package management system is run as root also. The daemon receives
+untrusted input from the client, which means the daemon is security sensitive.
+
+First, a high level overview, in this case using the yum backend as an example:
+
+ gpk-update-icon gpk-application
+ | _______/
+ [DBUS] __[DBUS]__/
+ | /
+ packagekitd -- [DBUS] -- polkit-daemon-1
+ |
+ [pipe]
+ |
+ yumBackend.py (using yum)
+
+packagekitd does not expose itself remotely over XMLRPC or other remote
+interface, and so a remote denial of service or exploit is impossible without a
+serious exploit of other services such as DBus. It advertises a simple interface
+that can be queried by clients in unprivileged and privileged modes.
+The privileged modes are controlled using PolicyKit, and policy and the
+authentication mechanism is deferred to the polkit-daemon-1 service.
+
+When a privileged method is executed, the daemon asks polkit-daemon-1 for
+authentication, which then blocks until the authentication is completed. This
+is handled asynchronously, and the daemon can process other requests whilst
+waiting for user input.
+
+The packagekitd daemon is started using DBus system activation, which means it
+is started without any environment (no PATH, etc) and therefore is impossible to
+exploit by preloading other libraries. It is also running as uid 0, and so
+requires root privileges to inject code into it.
+
+A typical transaction would be for the client to request a TID (transaction ID)
+to which the server responds by creating a transaction instance and exposing
+this on the system bus. The client then connects to this interface, and executes
+the chosen method. This method will emit signals such as ::Package(), then
+::Finished() and then after a number of seconds ::Destroy() which will remove
+the interface from the bus.
+
+Attack vectors:
+
+ * A client could cause a local DoS (denial of service) by repeatedly calling
+ GetTid without then calling a method to use this TID. This is mitigated by
+ timing out Tid request after a present number of seconds, and the effect can be
+ limited with a config variable (SimultaneousTransactionsForUid).
+
+ * Local DoS by repeatedly calling non-privileged methods such as Resolve and
+ SearchName. This could be mitigated by limiting the number of requests per
+ second for a certain seat, although no code has been written to do this at
+ present.
+
+ * A privileged method could be requested and then ignored or hidden by the
+ window manager. This is mitigated by not blocking the daemon when processing
+ authentication, and timing-out the authentication after a number of seconds if
+ authentication credentials are not supplied.
+
+ * Passing untrusted input to the backend which could be used to crash and
+ exploit the underlying package system. This is mitigated by rejecting invalid
+ input to methods, and testing filenames for existence before they are passed
+ to the backend.
+
+ * A session service can be written to automatically authenticate methods, and
+ replace the native client. This is hard to mitigate, as as soon as you have
+ untrusted code running in the session, it's very easy to load exploit code
+ using GTK_MODULES into previously trusted applications, such as gpk-application.
+
+ * Issuing a large amount of data to a method to cause a local denial of
+ service, for instance calling Resolve with millions of parameters. This is
+ mitigated in the daemon by checking for a sane number of requests
+ (MaximumPackagesToProcess) for each method, and also limiting the total length
+ of the data.
+
commit d0e14db8ccb34128c624bed157c1b0079169563f
Author: Richard Hughes <richard at hughsie.com>
Date: Mon Jul 13 10:27:54 2009 +0100
Limit the number of packages that can be processed by the daemon in one method call
diff --git a/etc/PackageKit.conf.in b/etc/PackageKit.conf.in
index ddc7957..702a6df 100644
--- a/etc/PackageKit.conf.in
+++ b/etc/PackageKit.conf.in
@@ -178,3 +178,20 @@ StateChangedTimeoutNormal=600
# default=25
SimultaneousTransactionsForUid=25
+# The maximum number of items that can be resolved in one method
+#
+# Setting this lower decreases the risk of a local denial of service, but may
+# cause errors if the desktop client is trying to resolve a large number of
+# packages in one method.
+#
+# default=10
+MaximumItemsToResolve=10
+
+# The maximum number of packages that can be processed in one method
+#
+# Setting this lower decreases the risk of a local denial of service, but may
+# cause errors if the desktop client is trying to do a large transaction.
+#
+# default=2500
+MaximumPackagesToProcess=2500
+
diff --git a/src/pk-transaction.c b/src/pk-transaction.c
index c583c26..c6c534c 100644
--- a/src/pk-transaction.c
+++ b/src/pk-transaction.c
@@ -241,6 +241,7 @@ pk_transaction_error_get_type (void)
ENUM_ENTRY (PK_TRANSACTION_ERROR_PACK_INVALID, "PackInvalid"),
ENUM_ENTRY (PK_TRANSACTION_ERROR_MIME_TYPE_NOT_SUPPORTED, "MimeTypeNotSupported"),
ENUM_ENTRY (PK_TRANSACTION_ERROR_INVALID_PROVIDE, "InvalidProvide"),
+ ENUM_ENTRY (PK_TRANSACTION_ERROR_NUMBER_OF_PACKAGES_INVALID, "NumberOfPackagesInvalid"),
{ 0, NULL, NULL }
};
etype = g_enum_register_static ("PkTransactionError", values);
@@ -2121,6 +2122,8 @@ pk_transaction_download_packages (PkTransaction *transaction, gchar **package_id
gchar *package_ids_temp;
gchar *directory = NULL;
gint retval;
+ guint length;
+ guint max_length;
g_return_if_fail (PK_IS_TRANSACTION (transaction));
g_return_if_fail (transaction->priv->tid != NULL);
@@ -2144,6 +2147,17 @@ pk_transaction_download_packages (PkTransaction *transaction, gchar **package_id
goto out;
}
+ /* check for length sanity */
+ length = g_strv_length (package_ids);
+ max_length = pk_conf_get_int (transaction->priv->conf, "MaximumPackagesToProcess");
+ if (length > max_length) {
+ error = g_error_new (PK_TRANSACTION_ERROR, PK_TRANSACTION_ERROR_NUMBER_OF_PACKAGES_INVALID,
+ "Too many packages to process (%i/%i)", length, max_length);
+ pk_transaction_release_tid (transaction);
+ pk_transaction_dbus_return_error (context, error);
+ return;
+ }
+
/* check package_ids */
ret = pk_package_ids_check (package_ids);
if (!ret) {
@@ -2268,6 +2282,8 @@ pk_transaction_get_depends (PkTransaction *transaction, const gchar *filter, gch
gboolean ret;
GError *error;
gchar *package_ids_temp;
+ guint length;
+ guint max_length;
g_return_if_fail (PK_IS_TRANSACTION (transaction));
g_return_if_fail (transaction->priv->tid != NULL);
@@ -2301,6 +2317,17 @@ pk_transaction_get_depends (PkTransaction *transaction, const gchar *filter, gch
return;
}
+ /* check for length sanity */
+ length = g_strv_length (package_ids);
+ max_length = pk_conf_get_int (transaction->priv->conf, "MaximumPackagesToProcess");
+ if (length > max_length) {
+ error = g_error_new (PK_TRANSACTION_ERROR, PK_TRANSACTION_ERROR_NUMBER_OF_PACKAGES_INVALID,
+ "Too many packages to process (%i/%i)", length, max_length);
+ pk_transaction_release_tid (transaction);
+ pk_transaction_dbus_return_error (context, error);
+ return;
+ }
+
/* check package_ids */
ret = pk_package_ids_check (package_ids);
if (!ret) {
@@ -2342,6 +2369,8 @@ pk_transaction_get_details (PkTransaction *transaction, gchar **package_ids, DBu
gboolean ret;
GError *error;
gchar *package_ids_temp;
+ guint length;
+ guint max_length;
g_return_if_fail (PK_IS_TRANSACTION (transaction));
g_return_if_fail (transaction->priv->tid != NULL);
@@ -2367,6 +2396,17 @@ pk_transaction_get_details (PkTransaction *transaction, gchar **package_ids, DBu
return;
}
+ /* check for length sanity */
+ length = g_strv_length (package_ids);
+ max_length = pk_conf_get_int (transaction->priv->conf, "MaximumPackagesToProcess");
+ if (length > max_length) {
+ error = g_error_new (PK_TRANSACTION_ERROR, PK_TRANSACTION_ERROR_NUMBER_OF_PACKAGES_INVALID,
+ "Too many packages to process (%i/%i)", length, max_length);
+ pk_transaction_release_tid (transaction);
+ pk_transaction_dbus_return_error (context, error);
+ return;
+ }
+
/* check package_ids */
ret = pk_package_ids_check (package_ids);
if (!ret) {
@@ -2456,6 +2496,8 @@ pk_transaction_get_files (PkTransaction *transaction, gchar **package_ids, DBusG
gboolean ret;
GError *error;
gchar *package_ids_temp;
+ guint length;
+ guint max_length;
g_return_if_fail (PK_IS_TRANSACTION (transaction));
g_return_if_fail (transaction->priv->tid != NULL);
@@ -2481,6 +2523,17 @@ pk_transaction_get_files (PkTransaction *transaction, gchar **package_ids, DBusG
return;
}
+ /* check for length sanity */
+ length = g_strv_length (package_ids);
+ max_length = pk_conf_get_int (transaction->priv->conf, "MaximumPackagesToProcess");
+ if (length > max_length) {
+ error = g_error_new (PK_TRANSACTION_ERROR, PK_TRANSACTION_ERROR_NUMBER_OF_PACKAGES_INVALID,
+ "Too many packages to process (%i/%i)", length, max_length);
+ pk_transaction_release_tid (transaction);
+ pk_transaction_dbus_return_error (context, error);
+ return;
+ }
+
/* check package_ids */
ret = pk_package_ids_check (package_ids);
if (!ret) {
@@ -2693,6 +2746,8 @@ pk_transaction_get_requires (PkTransaction *transaction, const gchar *filter, gc
gboolean ret;
GError *error;
gchar *package_ids_temp;
+ guint length;
+ guint max_length;
g_return_if_fail (PK_IS_TRANSACTION (transaction));
g_return_if_fail (transaction->priv->tid != NULL);
@@ -2726,6 +2781,17 @@ pk_transaction_get_requires (PkTransaction *transaction, const gchar *filter, gc
return;
}
+ /* check for length sanity */
+ length = g_strv_length (package_ids);
+ max_length = pk_conf_get_int (transaction->priv->conf, "MaximumPackagesToProcess");
+ if (length > max_length) {
+ error = g_error_new (PK_TRANSACTION_ERROR, PK_TRANSACTION_ERROR_NUMBER_OF_PACKAGES_INVALID,
+ "Too many packages to process (%i/%i)", length, max_length);
+ pk_transaction_release_tid (transaction);
+ pk_transaction_dbus_return_error (context, error);
+ return;
+ }
+
/* check package_ids */
ret = pk_package_ids_check (package_ids);
if (!ret) {
@@ -2809,6 +2875,8 @@ pk_transaction_get_update_detail (PkTransaction *transaction, gchar **package_id
gboolean ret;
GError *error;
gchar *package_ids_temp;
+ guint length;
+ guint max_length;
g_return_if_fail (PK_IS_TRANSACTION (transaction));
g_return_if_fail (transaction->priv->tid != NULL);
@@ -2834,6 +2902,17 @@ pk_transaction_get_update_detail (PkTransaction *transaction, gchar **package_id
return;
}
+ /* check for length sanity */
+ length = g_strv_length (package_ids);
+ max_length = pk_conf_get_int (transaction->priv->conf, "MaximumPackagesToProcess");
+ if (length > max_length) {
+ error = g_error_new (PK_TRANSACTION_ERROR, PK_TRANSACTION_ERROR_NUMBER_OF_PACKAGES_INVALID,
+ "Too many packages to process (%i/%i)", length, max_length);
+ pk_transaction_release_tid (transaction);
+ pk_transaction_dbus_return_error (context, error);
+ return;
+ }
+
/* check package_ids */
ret = pk_package_ids_check (package_ids);
if (!ret) {
@@ -3132,6 +3211,8 @@ pk_transaction_install_packages (PkTransaction *transaction, gboolean only_trust
gboolean ret;
GError *error;
gchar *package_ids_temp;
+ guint length;
+ guint max_length;
g_return_if_fail (PK_IS_TRANSACTION (transaction));
g_return_if_fail (transaction->priv->tid != NULL);
@@ -3157,6 +3238,17 @@ pk_transaction_install_packages (PkTransaction *transaction, gboolean only_trust
return;
}
+ /* check for length sanity */
+ length = g_strv_length (package_ids);
+ max_length = pk_conf_get_int (transaction->priv->conf, "MaximumPackagesToProcess");
+ if (length > max_length) {
+ error = g_error_new (PK_TRANSACTION_ERROR, PK_TRANSACTION_ERROR_NUMBER_OF_PACKAGES_INVALID,
+ "Too many packages to process (%i/%i)", length, max_length);
+ pk_transaction_release_tid (transaction);
+ pk_transaction_dbus_return_error (context, error);
+ return;
+ }
+
/* check package_ids */
ret = pk_package_ids_check (package_ids);
if (!ret) {
@@ -3332,6 +3424,8 @@ pk_transaction_remove_packages (PkTransaction *transaction, gchar **package_ids,
gboolean ret;
GError *error;
gchar *package_ids_temp;
+ guint length;
+ guint max_length;
g_return_if_fail (PK_IS_TRANSACTION (transaction));
g_return_if_fail (transaction->priv->tid != NULL);
@@ -3357,6 +3451,17 @@ pk_transaction_remove_packages (PkTransaction *transaction, gchar **package_ids,
return;
}
+ /* check for length sanity */
+ length = g_strv_length (package_ids);
+ max_length = pk_conf_get_int (transaction->priv->conf, "MaximumPackagesToProcess");
+ if (length > max_length) {
+ error = g_error_new (PK_TRANSACTION_ERROR, PK_TRANSACTION_ERROR_NUMBER_OF_PACKAGES_INVALID,
+ "Too many packages to process (%i/%i)", length, max_length);
+ pk_transaction_release_tid (transaction);
+ pk_transaction_dbus_return_error (context, error);
+ return;
+ }
+
/* check package_ids */
ret = pk_package_ids_check (package_ids);
if (!ret) {
@@ -3518,6 +3623,7 @@ pk_transaction_resolve (PkTransaction *transaction, const gchar *filter,
gchar *packages_temp;
guint i;
guint length;
+ guint max_length;
g_return_if_fail (PK_IS_TRANSACTION (transaction));
g_return_if_fail (transaction->priv->tid != NULL);
@@ -3551,8 +3657,18 @@ pk_transaction_resolve (PkTransaction *transaction, const gchar *filter,
return;
}
- /* check for sanity */
+ /* check for length sanity */
length = g_strv_length (packages);
+ max_length = pk_conf_get_int (transaction->priv->conf, "MaximumItemsToResolve");
+ if (length > max_length) {
+ error = g_error_new (PK_TRANSACTION_ERROR, PK_TRANSACTION_ERROR_INPUT_INVALID,
+ "Too many items to process (%i/%i)", length, max_length);
+ pk_transaction_release_tid (transaction);
+ pk_transaction_dbus_return_error (context, error);
+ return;
+ }
+
+ /* check each package for sanity */
for (i=0; i<length; i++) {
ret = pk_strvalidate (packages[i]);
if (!ret) {
@@ -3972,6 +4088,8 @@ pk_transaction_update_packages (PkTransaction *transaction, gboolean only_truste
gboolean ret;
GError *error;
gchar *package_ids_temp;
+ guint length;
+ guint max_length;
g_return_if_fail (PK_IS_TRANSACTION (transaction));
g_return_if_fail (transaction->priv->tid != NULL);
@@ -3997,6 +4115,17 @@ pk_transaction_update_packages (PkTransaction *transaction, gboolean only_truste
return;
}
+ /* check for length sanity */
+ length = g_strv_length (package_ids);
+ max_length = pk_conf_get_int (transaction->priv->conf, "MaximumPackagesToProcess");
+ if (length > max_length) {
+ error = g_error_new (PK_TRANSACTION_ERROR, PK_TRANSACTION_ERROR_NUMBER_OF_PACKAGES_INVALID,
+ "Too many packages to process (%i/%i)", length, max_length);
+ pk_transaction_release_tid (transaction);
+ pk_transaction_dbus_return_error (context, error);
+ return;
+ }
+
/* check package_ids */
ret = pk_package_ids_check (package_ids);
if (!ret) {
diff --git a/src/pk-transaction.h b/src/pk-transaction.h
index 086f793..38cdf49 100644
--- a/src/pk-transaction.h
+++ b/src/pk-transaction.h
@@ -73,6 +73,7 @@ typedef enum
PK_TRANSACTION_ERROR_INVALID_PROVIDE,
PK_TRANSACTION_ERROR_PACK_INVALID,
PK_TRANSACTION_ERROR_MIME_TYPE_NOT_SUPPORTED,
+ PK_TRANSACTION_ERROR_NUMBER_OF_PACKAGES_INVALID,
PK_TRANSACTION_ERROR_LAST
} PkTransactionError;
commit 316d771f9e150e115de1de980ff33c7939c7e99e
Author: Richard Hughes <richard at hughsie.com>
Date: Mon Jul 13 09:50:21 2009 +0100
Limit the maximum number of requests a given user is able to request and queue
diff --git a/etc/PackageKit.conf.in b/etc/PackageKit.conf.in
index 259a752..ddc7957 100644
--- a/etc/PackageKit.conf.in
+++ b/etc/PackageKit.conf.in
@@ -169,3 +169,12 @@ StateChangedTimeoutPriority=5
# default=600
StateChangedTimeoutNormal=600
+# The maximum number of requests a given user is able to request and queue
+#
+# Setting this lower decreases the risk of a local denial of service, but may
+# cause errors if the desktop client is doing many requests to the daemon in a
+# short period of time.
+#
+# default=25
+SimultaneousTransactionsForUid=25
+
diff --git a/src/pk-engine.c b/src/pk-engine.c
index 532a8dd..d5ab3ef 100644
--- a/src/pk-engine.c
+++ b/src/pk-engine.c
@@ -149,6 +149,7 @@ pk_engine_error_get_type (void)
ENUM_ENTRY (PK_ENGINE_ERROR_REFUSED_BY_POLICY, "RefusedByPolicy"),
ENUM_ENTRY (PK_ENGINE_ERROR_CANNOT_SET_PROXY, "CannotSetProxy"),
ENUM_ENTRY (PK_ENGINE_ERROR_NOT_SUPPORTED, "NotSupported"),
+ ENUM_ENTRY (PK_ENGINE_ERROR_CANNOT_ALLOCATE_TID, "CannotAllocateTid"),
{ 0, NULL, NULL }
};
etype = g_enum_register_static ("PkEngineError", values);
@@ -239,6 +240,8 @@ pk_engine_get_tid (PkEngine *engine, DBusGMethodInvocation *context)
gchar *new_tid;
gboolean ret;
gchar *sender = NULL;
+ GError *error;
+ GError *error_local = NULL;
g_return_if_fail (PK_IS_ENGINE (engine));
@@ -246,7 +249,14 @@ pk_engine_get_tid (PkEngine *engine, DBusGMethodInvocation *context)
sender = dbus_g_method_get_sender (context);
new_tid = pk_transaction_db_generate_id (engine->priv->transaction_db);
- ret = pk_transaction_list_create (engine->priv->transaction_list, new_tid, sender);
+ ret = pk_transaction_list_create (engine->priv->transaction_list, new_tid, sender, &error_local);
+ if (!ret) {
+ error = g_error_new (PK_ENGINE_ERROR, PK_ENGINE_ERROR_CANNOT_ALLOCATE_TID, "getting the tid failed: %s", error_local->message);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error_local);
+ goto out;
+ }
+
egg_debug ("sending tid: '%s'", new_tid);
/* reset the timer */
@@ -254,6 +264,7 @@ pk_engine_get_tid (PkEngine *engine, DBusGMethodInvocation *context)
/* return TID */
dbus_g_method_return (context, new_tid);
+out:
g_free (new_tid);
g_free (sender);
}
diff --git a/src/pk-engine.h b/src/pk-engine.h
index f45b5fa..8096f3a 100644
--- a/src/pk-engine.h
+++ b/src/pk-engine.h
@@ -60,6 +60,7 @@ typedef enum
PK_ENGINE_ERROR_REFUSED_BY_POLICY,
PK_ENGINE_ERROR_CANNOT_SET_PROXY,
PK_ENGINE_ERROR_NOT_SUPPORTED,
+ PK_ENGINE_ERROR_CANNOT_ALLOCATE_TID,
PK_ENGINE_ERROR_LAST
} PkEngineError;
diff --git a/src/pk-transaction-list.c b/src/pk-transaction-list.c
index 0fb15b2..03234ea 100644
--- a/src/pk-transaction-list.c
+++ b/src/pk-transaction-list.c
@@ -42,6 +42,7 @@
#include "egg-debug.h"
#include "egg-string.h"
+#include "pk-conf.h"
#include "pk-transaction-list.h"
#include "org.freedesktop.PackageKit.Transaction.h"
@@ -63,6 +64,7 @@ struct PkTransactionListPrivate
GPtrArray *array;
guint unwedge1_id;
guint unwedge2_id;
+ PkConf *conf;
};
typedef struct {
@@ -76,6 +78,7 @@ typedef struct {
guint idle_id;
guint commit_id;
gulong finished_id;
+ guint uid;
} PkTransactionItem;
enum {
@@ -350,12 +353,37 @@ pk_transaction_list_no_commit_cb (PkTransactionItem *item)
}
/**
+ * pk_transaction_list_get_number_transactions_for_uid:
+ *
+ * Find all the transactions that are pending from this uid.
+ **/
+static guint
+pk_transaction_list_get_number_transactions_for_uid (PkTransactionList *tlist, guint uid)
+{
+ guint i;
+ GPtrArray *array;
+ PkTransactionItem *item;
+ guint count = 0;
+
+ /* find all the transactions in progress */
+ array = tlist->priv->array;
+ for (i=0; i<array->len; i++) {
+ item = (PkTransactionItem *) g_ptr_array_index (array, i);
+ if (item->uid == uid)
+ count++;
+ }
+ return count;
+}
+
+/**
* pk_transaction_list_create:
**/
gboolean
-pk_transaction_list_create (PkTransactionList *tlist, const gchar *tid, const gchar *sender)
+pk_transaction_list_create (PkTransactionList *tlist, const gchar *tid, const gchar *sender, GError **error)
{
- gboolean ret;
+ guint count;
+ guint max_count;
+ gboolean ret = FALSE;
PkTransactionItem *item;
DBusGConnection *connection;
@@ -365,8 +393,10 @@ pk_transaction_list_create (PkTransactionList *tlist, const gchar *tid, const gc
/* already added? */
item = pk_transaction_list_get_from_tid (tlist, tid);
if (item != NULL) {
+ if (error != NULL)
+ *error = g_error_new (1, 0, "already added %s to list", tid);
egg_warning ("already added %s to list", tid);
- return FALSE;
+ goto out;
}
/* add to the array */
@@ -394,13 +424,42 @@ pk_transaction_list_create (PkTransactionList *tlist, const gchar *tid, const gc
/* set the TID on the transaction */
ret = pk_transaction_set_tid (item->transaction, item->tid);
- if (!ret)
- egg_error ("failed to set TID");
+ if (!ret) {
+ if (error != NULL)
+ *error = g_error_new (1, 0, "failed to set TID: %s", tid);
+ goto out;
+ }
/* set the DBUS sender on the transaction */
ret = pk_transaction_set_sender (item->transaction, sender);
- if (!ret)
- egg_error ("failed to set sender");
+ if (!ret) {
+ if (error != NULL)
+ *error = g_error_new (1, 0, "failed to set sender: %s", tid);
+ goto out;
+ }
+
+ /* get the uid for the transaction */
+ g_object_get (item->transaction,
+ "uid", &item->uid,
+ NULL);
+
+ /* find out the number of transactions this uid already has in progress */
+ count = pk_transaction_list_get_number_transactions_for_uid (tlist, item->uid);
+ egg_debug ("uid=%i, count=%i", item->uid, count);
+
+ /* would this take us over the maximum number of requests allowed */
+ max_count = pk_conf_get_int (tlist->priv->conf, "SimultaneousTransactionsForUid");
+ if (count > max_count) {
+ if (error != NULL)
+ *error = g_error_new (1, 0, "failed to allocate %s as uid %i already has %i transactions in progress", tid, item->uid, count);
+
+ /* free transaction, as it's never going to be added */
+ pk_transaction_list_item_free (item);
+
+ /* failure */
+ ret = FALSE;
+ goto out;
+ }
/* put on the bus */
dbus_g_object_type_install_info (PK_TYPE_TRANSACTION, &dbus_glib_pk_transaction_object_info);
@@ -412,7 +471,8 @@ pk_transaction_list_create (PkTransactionList *tlist, const gchar *tid, const gc
egg_debug ("adding transaction %p, item %p", item->transaction, item);
g_ptr_array_add (tlist->priv->array, item);
- return TRUE;
+out:
+ return ret;
}
/**
@@ -745,6 +805,7 @@ static void
pk_transaction_list_init (PkTransactionList *tlist)
{
tlist->priv = PK_TRANSACTION_LIST_GET_PRIVATE (tlist);
+ tlist->priv->conf = pk_conf_new ();
tlist->priv->array = g_ptr_array_new ();
tlist->priv->unwedge2_id = 0;
tlist->priv->unwedge1_id = g_timeout_add_seconds (PK_TRANSACTION_WEDGE_CHECK, (GSourceFunc) pk_transaction_list_wedge_check1, tlist);
@@ -772,6 +833,7 @@ pk_transaction_list_finalize (GObject *object)
g_ptr_array_foreach (tlist->priv->array, (GFunc) pk_transaction_list_item_free, NULL);
g_ptr_array_free (tlist->priv->array, TRUE);
+ g_object_unref (tlist->priv->conf);
G_OBJECT_CLASS (pk_transaction_list_parent_class)->finalize (object);
}
diff --git a/src/pk-transaction-list.h b/src/pk-transaction-list.h
index 07e9862..83221f0 100644
--- a/src/pk-transaction-list.h
+++ b/src/pk-transaction-list.h
@@ -56,7 +56,8 @@ PkTransactionList *pk_transaction_list_new (void);
gboolean pk_transaction_list_create (PkTransactionList *tlist,
const gchar *tid,
- const gchar *sender);
+ const gchar *sender,
+ GError **error);
gboolean pk_transaction_list_remove (PkTransactionList *tlist,
const gchar *tid);
gboolean pk_transaction_list_commit (PkTransactionList *tlist,
commit 0bbc51bf285d89abf7b979961897be151d65b1ed
Author: Richard Hughes <richard at hughsie.com>
Date: Mon Jul 13 09:45:27 2009 +0100
Add a uid property to the PkTransaction object for future use
diff --git a/src/pk-transaction.c b/src/pk-transaction.c
index 697fbc6..c583c26 100644
--- a/src/pk-transaction.c
+++ b/src/pk-transaction.c
@@ -184,6 +184,13 @@ enum {
PK_TRANSACTION_LAST_SIGNAL
};
+enum
+{
+ PROP_0,
+ PROP_UID,
+ PROP_LAST
+};
+
static guint signals [PK_TRANSACTION_LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE (PkTransaction, pk_transaction, G_TYPE_OBJECT)
@@ -4154,6 +4161,26 @@ pk_transaction_what_provides (PkTransaction *transaction, const gchar *filter, c
}
/**
+ * pk_transaction_get_property:
+ **/
+static void
+pk_transaction_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ PkTransaction *transaction;
+
+ transaction = PK_TRANSACTION (object);
+
+ switch (prop_id) {
+ case PROP_UID:
+ g_value_set_uint (value, transaction->priv->uid);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/**
* pk_transaction_class_init:
* @klass: The PkTransactionClass
**/
@@ -4163,6 +4190,15 @@ pk_transaction_class_init (PkTransactionClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = pk_transaction_dispose;
object_class->finalize = pk_transaction_finalize;
+ object_class->get_property = pk_transaction_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_UID,
+ g_param_spec_uint ("uid",
+ "UID",
+ "User ID that created the transaction",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READABLE));
signals [PK_TRANSACTION_ALLOW_CANCEL] =
g_signal_new ("allow-cancel",
commit 9e4a6fed9c20e317c3a86cd4a425d9de55341266
Author: raven <raven at fedoraproject.org>
Date: Sun Jul 12 19:32:20 2009 +0000
Sending translation for Polish
diff --git a/po/pl.po b/po/pl.po
index e2f4a42..97230e8 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -5,8 +5,8 @@ msgid ""
msgstr ""
"Project-Id-Version: pl\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-06-30 14:32+0000\n"
-"PO-Revision-Date: 2009-06-30 17:53+0200\n"
+"POT-Creation-Date: 2009-07-12 16:41+0000\n"
+"PO-Revision-Date: 2009-07-12 21:31+0200\n"
"Last-Translator: Piotr DrÄ
g <piotrdrag at gmail.com>\n"
"Language-Team: Polish <pl at li.org>\n"
"MIME-Version: 1.0\n"
@@ -205,41 +205,70 @@ msgstr "Ponowne uruchomienie systemu jest wymagane przez:"
msgid "Session restart required:"
msgstr "Wymagane jest ponowne uruchomienie sesji:"
-#. TRANSLATORS: a package requires the application to be restarted
+#. TRANSLATORS: a package requires the system to be restarted due to a security update
#: ../client/pk-console.c:523
+msgid "System restart (security) required by:"
+msgstr ""
+"Ponowne uruchomienie systemu jest wymagane przez:"
+
+#. TRANSLATORS: a package requires the session to be restarted due to a security update
+#: ../client/pk-console.c:526
+msgid "Session restart (security) required:"
+msgstr "Wymagane jest ponowne uruchomienie sesji (z powodu bezpieczeÅstwa):"
+
+#. TRANSLATORS: a package requires the application to be restarted
+#: ../client/pk-console.c:529
msgid "Application restart required by:"
msgstr "Ponowne uruchomienie programu jest wymagane przez:"
-#. TRANSLATORS: a package needs to restart they system
-#: ../client/pk-console.c:578
+#. TRANSLATORS: a package needs to restart their system
+#: ../client/pk-console.c:584
msgid "Please restart the computer to complete the update."
msgstr "ProszÄ uruchomiÄ ponownie komputer, aby zakoÅczyÄ aktualizacjÄ."
#. TRANSLATORS: a package needs to restart the session
-#: ../client/pk-console.c:581
+#: ../client/pk-console.c:587
msgid "Please logout and login to complete the update."
msgstr "ProszÄ wylogowaÄ siÄ i zalogowaÄ, aby zakoÅczyÄ aktualizacjÄ."
#. TRANSLATORS: a package needs to restart the application
-#: ../client/pk-console.c:584
+#: ../client/pk-console.c:590
msgid "Please restart the application as it is being used."
msgstr "ProszÄ uruchomiÄ program ponownie, ponieważ jest używany."
+#. TRANSLATORS: a package needs to restart their system (due to security)
+#: ../client/pk-console.c:593
+msgid ""
+"Please restart the computer to complete the update as important security "
+"updates have been installed."
+msgstr ""
+"ProszÄ uruchomiÄ ponownie komputer, aby zakoÅczyÄ aktualizacjÄ, ponieważ "
+"zainstalowano aktualizacje bezpieczeÅstwa."
+
+#. TRANSLATORS: a package needs to restart the session (due to security)
+#: ../client/pk-console.c:596
+msgid ""
+"Please logout and login to complete the update as important security updates "
+"have been installed."
+msgstr ""
+"ProszÄ wylogowaÄ siÄ i zalogowaÄ, aby zakoÅczyÄ aktualizacjÄ, ponieważ "
+"zainstalowano aktualizacje bezpieczeÅstwa."
+
#. TRANSLATORS: The package is already installed on the system
-#: ../client/pk-console.c:711
+#: ../client/pk-console.c:723
#, c-format
msgid "The package %s is already installed"
msgstr "Pakiet %s jest już zainstalowany"
#. TRANSLATORS: The package name was not found in any software sources. The detailed error follows
-#: ../client/pk-console.c:719
+#: ../client/pk-console.c:731
#, c-format
msgid "The package %s could not be installed: %s"
msgstr "Nie można zainstalowaÄ pakietu %s: %s"
#. TRANSLATORS: There was a programming error that shouldn't happen. The detailed error follows
-#: ../client/pk-console.c:744 ../client/pk-console.c:767
-#: ../client/pk-console.c:863 ../client/pk-console.c:980
+#: ../client/pk-console.c:756 ../client/pk-console.c:779
+#: ../client/pk-console.c:875 ../client/pk-console.c:992
#: ../client/pk-tools-common.c:62 ../client/pk-tools-common.c:81
#: ../client/pk-tools-common.c:89
#, c-format
@@ -247,254 +276,254 @@ msgid "Internal error: %s"
msgstr "WewnÄtrzny bÅÄ
d: %s"
#. TRANSLATORS: There was an error installing the packages. The detailed error follows
-#: ../client/pk-console.c:752 ../client/pk-console.c:1376
+#: ../client/pk-console.c:764 ../client/pk-console.c:1388
#, c-format
msgid "This tool could not install the packages: %s"
msgstr "To narzÄdzie nie może zainstalowaÄ pakietów: %s"
#. TRANSLATORS: There was an error installing the files. The detailed error follows
-#: ../client/pk-console.c:775
+#: ../client/pk-console.c:787
#, c-format
msgid "This tool could not install the files: %s"
msgstr "To narzÄdzie nie może zainstalowaÄ plików: %s"
#. TRANSLATORS: The package name was not found in the installed list. The detailed error follows
-#: ../client/pk-console.c:831
+#: ../client/pk-console.c:843
#, c-format
msgid "This tool could not remove %s: %s"
msgstr "To narzÄdzie nie może usunÄ
Ä %s: %s"
#. TRANSLATORS: There was an error removing the packages. The detailed error follows
-#: ../client/pk-console.c:854 ../client/pk-console.c:892
-#: ../client/pk-console.c:925
+#: ../client/pk-console.c:866 ../client/pk-console.c:904
+#: ../client/pk-console.c:937
#, c-format
msgid "This tool could not remove the packages: %s"
msgstr "To narzÄdzie nie może usunÄ
Ä pakietów: %s"
#. TRANSLATORS: When removing, we might have to remove other dependencies
-#: ../client/pk-console.c:904
+#: ../client/pk-console.c:916
msgid "The following packages have to be removed:"
msgstr "NastÄpujÄ
ce pakiety muszÄ
zostaÄ usuniÄte:"
#. TRANSLATORS: We are checking if it's okay to remove a list of packages
-#: ../client/pk-console.c:911
+#: ../client/pk-console.c:923
msgid "Proceed removing additional packages?"
msgstr "KontynuowaÄ usuwanie dodatkowych pakietów?"
#. TRANSLATORS: We did not remove any packages
-#: ../client/pk-console.c:916
+#: ../client/pk-console.c:928
msgid "The package removal was canceled!"
msgstr "Anulowano usuniÄcie pakietu!"
#. TRANSLATORS: The package name was not found in any software sources
-#: ../client/pk-console.c:957
+#: ../client/pk-console.c:969
#, c-format
msgid "This tool could not download the package %s as it could not be found"
msgstr "To narzÄdzie nie może pobraÄ pakietu %s, ponieważ nie można go znaleźÄ"
#. TRANSLATORS: Could not download the packages for some reason. The detailed error follows
-#: ../client/pk-console.c:988
+#: ../client/pk-console.c:1000
#, c-format
msgid "This tool could not download the packages: %s"
msgstr "To narzÄdzie nie może pobraÄ pakietów: %s"
#. TRANSLATORS: There was an error getting the list of files for the package. The detailed error follows
-#: ../client/pk-console.c:1015 ../client/pk-console.c:1024
+#: ../client/pk-console.c:1027 ../client/pk-console.c:1036
#, c-format
msgid "This tool could not update %s: %s"
msgstr "To narzÄdzie nie może zaktualizowaÄ %s: %s"
#. TRANSLATORS: There was an error getting the list of files for the package. The detailed error follows
-#: ../client/pk-console.c:1046 ../client/pk-console.c:1054
+#: ../client/pk-console.c:1058 ../client/pk-console.c:1066
#, c-format
msgid "This tool could not get the requirements for %s: %s"
msgstr "To narzÄdzie nie może uzyskaÄ wymagaÅ dla %s: %s"
#. TRANSLATORS: There was an error getting the dependencies for the package. The detailed error follows
-#: ../client/pk-console.c:1076 ../client/pk-console.c:1084
+#: ../client/pk-console.c:1088 ../client/pk-console.c:1096
#, c-format
msgid "This tool could not get the dependencies for %s: %s"
msgstr "To narzÄdzie nie może uzyskaÄ zależnoÅci dla %s: %s"
#. TRANSLATORS: There was an error getting the details about the package. The detailed error follows
-#: ../client/pk-console.c:1106 ../client/pk-console.c:1114
+#: ../client/pk-console.c:1118 ../client/pk-console.c:1126
#, c-format
msgid "This tool could not get package details for %s: %s"
msgstr "To narzÄdzie nie może uzyskaÄ szczegóÅów pakietu %s: %s"
#. TRANSLATORS: The package name was not found in any software sources. The detailed error follows
-#: ../client/pk-console.c:1136
+#: ../client/pk-console.c:1148
#, c-format
msgid "This tool could not find the files for %s: %s"
msgstr "To narzÄdzie nie może znaleÅºÄ plików dla %s: %s"
#. TRANSLATORS: There was an error getting the list of files for the package. The detailed error follows
-#: ../client/pk-console.c:1144
+#: ../client/pk-console.c:1156
#, c-format
msgid "This tool could not get the file list for %s: %s"
msgstr "To narzÄdzie nie może uzyskaÄ listy plików dla %s: %s"
#. TRANSLATORS: There was an error getting the list of packages. The filename follows
-#: ../client/pk-console.c:1166
+#: ../client/pk-console.c:1178
#, c-format
msgid "File already exists: %s"
msgstr "Plik już istnieje: %s"
#. TRANSLATORS: follows a list of packages to install
-#: ../client/pk-console.c:1171 ../client/pk-console.c:1227
-#: ../client/pk-console.c:1302
+#: ../client/pk-console.c:1183 ../client/pk-console.c:1239
+#: ../client/pk-console.c:1314
msgid "Getting package list"
msgstr "Pobieranie listy pakietów"
#. TRANSLATORS: There was an error getting the list of packages. The detailed error follows
-#: ../client/pk-console.c:1177 ../client/pk-console.c:1233
-#: ../client/pk-console.c:1308
+#: ../client/pk-console.c:1189 ../client/pk-console.c:1245
+#: ../client/pk-console.c:1320
#, c-format
msgid "This tool could not get package list: %s"
msgstr "To narzÄdzie nie może pobraÄ listy pakietów: %s"
#. TRANSLATORS: There was an error saving the list
-#: ../client/pk-console.c:1188
+#: ../client/pk-console.c:1200
#, c-format
msgid "Failed to save to disk"
msgstr "Zapisanie na dysku nie powiodÅo siÄ"
#. TRANSLATORS: There was an error getting the list. The filename follows
-#: ../client/pk-console.c:1222 ../client/pk-console.c:1297
+#: ../client/pk-console.c:1234 ../client/pk-console.c:1309
#, c-format
msgid "File does not exist: %s"
msgstr "Plik nie istnieje: %s"
#. TRANSLATORS: header to a list of packages newly added
-#: ../client/pk-console.c:1254
+#: ../client/pk-console.c:1266
msgid "Packages to add"
msgstr "Pakiety do dodania"
#. TRANSLATORS: header to a list of packages removed
-#: ../client/pk-console.c:1262
+#: ../client/pk-console.c:1274
msgid "Packages to remove"
msgstr "Pakiety do usuniÄcia"
#. TRANSLATORS: We didn't find any differences
-#: ../client/pk-console.c:1330
+#: ../client/pk-console.c:1342
#, c-format
msgid "No new packages need to be installed"
msgstr "Nie trzeba instalowaÄ nowych pakietów"
#. TRANSLATORS: follows a list of packages to install
-#: ../client/pk-console.c:1336
+#: ../client/pk-console.c:1348
msgid "To install"
msgstr "Do zainstalowania"
#. TRANSLATORS: searching takes some time....
-#: ../client/pk-console.c:1348
+#: ../client/pk-console.c:1360
msgid "Searching for package: "
msgstr "Wyszukiwanie pakietu: "
#. TRANSLATORS: package was not found -- this is the end of a string ended in ...
-#: ../client/pk-console.c:1352
+#: ../client/pk-console.c:1364
msgid "not found."
msgstr "nie znaleziono."
#. TRANSLATORS: We didn't find any packages to install
-#: ../client/pk-console.c:1363
+#: ../client/pk-console.c:1375
#, c-format
msgid "No packages can be found to install"
msgstr "Nie można znaleÅºÄ pakietów do zainstalowania"
#. TRANSLATORS: installing new packages from package list
#. TRANSLATORS: we are now installing the debuginfo packages we found earlier
-#: ../client/pk-console.c:1369
+#: ../client/pk-console.c:1381
#: ../contrib/debuginfo-install/pk-debuginfo-install.c:868
#, c-format
msgid "Installing packages"
msgstr "Instalowanie pakietów"
#. TRANSLATORS: The package name was not found in any software sources. The detailed error follows
-#: ../client/pk-console.c:1405
+#: ../client/pk-console.c:1417
#, c-format
msgid "This tool could not find the update details for %s: %s"
msgstr "To narzÄdzie nie może znaleÅºÄ szczegóÅów aktualizacji dla %s: %s"
#. TRANSLATORS: There was an error getting the details about the update for the package. The detailed error follows
-#: ../client/pk-console.c:1413
+#: ../client/pk-console.c:1425
#, c-format
msgid "This tool could not get the update details for %s: %s"
msgstr "To narzÄdzie nie może uzyskaÄ szczegóÅów aktualizacji dla %s: %s"
#. TRANSLATORS: This was an unhandled error, and we don't have _any_ context
-#: ../client/pk-console.c:1444
+#: ../client/pk-console.c:1456
msgid "Error:"
msgstr "BÅÄ
d:"
#. TRANSLATORS: This a list of details about the package
-#: ../client/pk-console.c:1458
+#: ../client/pk-console.c:1470
msgid "Package description"
msgstr "Opis pakietu"
#. TRANSLATORS: This a message (like a little note that may be of interest) from the transaction
-#: ../client/pk-console.c:1474
+#: ../client/pk-console.c:1486
msgid "Message:"
msgstr "Komunikat:"
#. TRANSLATORS: This a list files contained in the package
-#: ../client/pk-console.c:1502
+#: ../client/pk-console.c:1514
msgid "Package files"
msgstr "Pliki pakietu"
#. TRANSLATORS: This where the package has no files
-#: ../client/pk-console.c:1510
+#: ../client/pk-console.c:1522
msgid "No files"
msgstr "Brak plików"
#. TRANSLATORS: This a request for a GPG key signature from the backend, which the client will prompt for later
-#: ../client/pk-console.c:1533
+#: ../client/pk-console.c:1545
msgid "Repository signature required"
msgstr "Wymagany jest podpis repozytorium"
#. TRANSLATORS: This a prompt asking the user to import the security key
-#: ../client/pk-console.c:1543
+#: ../client/pk-console.c:1555
msgid "Do you accept this signature?"
msgstr "ZaakceptowaÄ ten podpis?"
#. TRANSLATORS: This is where the user declined the security key
-#: ../client/pk-console.c:1547
+#: ../client/pk-console.c:1559
msgid "The signature was not accepted."
msgstr "Podpis nie zostaÅ zaakceptowany."
#. TRANSLATORS: This a request for a EULA
-#: ../client/pk-console.c:1581
+#: ../client/pk-console.c:1593
msgid "End user license agreement required"
msgstr "Licencja jest wymagana"
#. TRANSLATORS: This a prompt asking the user to agree to the license
-#: ../client/pk-console.c:1588
+#: ../client/pk-console.c:1600
msgid "Do you agree to this license?"
msgstr "ZaakceptowaÄ tÄ licencjÄ?"
#. TRANSLATORS: This is where the user declined the license
-#: ../client/pk-console.c:1592
+#: ../client/pk-console.c:1604
msgid "The license was refused."
msgstr "Odrzucono licencjÄ."
#. TRANSLATORS: This is when the daemon crashed, and we are up shit creek without a paddle
-#: ../client/pk-console.c:1621
+#: ../client/pk-console.c:1633
msgid "The daemon crashed mid-transaction!"
msgstr "Demon zawiesiÅ siÄ w poÅowie transakcji!"
#. TRANSLATORS: This is the header to the --help menu
-#: ../client/pk-console.c:1674
+#: ../client/pk-console.c:1686
msgid "PackageKit Console Interface"
msgstr "Interfejs konsoli PackageKit"
#. these are commands we can use with pkcon
-#: ../client/pk-console.c:1676
+#: ../client/pk-console.c:1688
msgid "Subcommands:"
msgstr "Podpolecenia:"
#. TRANSLATORS: command line argument, if we should show debugging information
#. TRANSLATORS: if we should show debugging data
-#: ../client/pk-console.c:1768 ../client/pk-generate-pack.c:185
+#: ../client/pk-console.c:1780 ../client/pk-generate-pack.c:185
#: ../client/pk-monitor.c:125
#: ../contrib/command-not-found/pk-command-not-found.c:521
#: ../contrib/debuginfo-install/pk-debuginfo-install.c:532
@@ -503,149 +532,149 @@ msgid "Show extra debugging information"
msgstr "WyÅwietla dodatkowe informacje o debugowaniu"
#. TRANSLATORS: command line argument, just show the version string
-#: ../client/pk-console.c:1771 ../client/pk-monitor.c:127
+#: ../client/pk-console.c:1783 ../client/pk-monitor.c:127
msgid "Show the program version and exit"
msgstr "WyÅwietla wersjÄ programu i wyÅÄ
cza"
#. TRANSLATORS: command line argument, use a filter to narrow down results
-#: ../client/pk-console.c:1774
+#: ../client/pk-console.c:1786
msgid "Set the filter, e.g. installed"
msgstr "Ustawia filtr, np. zainstalowane"
#. TRANSLATORS: command line argument, work asynchronously
-#: ../client/pk-console.c:1777
+#: ../client/pk-console.c:1789
msgid "Exit without waiting for actions to complete"
msgstr "WyÅÄ
cza bez oczekiwania na zakoÅczenie dziaÅaÅ"
#. TRANSLATORS: This is when we could not connect to the system bus, and is fatal
-#: ../client/pk-console.c:1804
+#: ../client/pk-console.c:1816
msgid "This tool could not connect to system DBUS."
msgstr "To narzÄdzie nie może poÅÄ
czyÄ siÄ z systemowym D-Bus."
#. TRANSLATORS: The user specified an incorrect filter
-#: ../client/pk-console.c:1893
+#: ../client/pk-console.c:1905
msgid "The filter specified was invalid"
msgstr "Podany filtr jest nieprawidÅowy"
#. TRANSLATORS: a search type can be name, details, file, etc
-#: ../client/pk-console.c:1911
+#: ../client/pk-console.c:1923
msgid "A search type is required, e.g. name"
msgstr "Wymagany jest typ wyszukiwania, np. nazwa"
#. TRANSLATORS: the user needs to provide a search term
-#: ../client/pk-console.c:1917 ../client/pk-console.c:1925
-#: ../client/pk-console.c:1933 ../client/pk-console.c:1941
+#: ../client/pk-console.c:1929 ../client/pk-console.c:1937
+#: ../client/pk-console.c:1945 ../client/pk-console.c:1953
msgid "A search term is required"
msgstr "Wymagany jest wyszukiwany termin"
#. TRANSLATORS: the search type was provided, but invalid
-#: ../client/pk-console.c:1947
+#: ../client/pk-console.c:1959
msgid "Invalid search type"
msgstr "NieprawidÅowy typ wyszukiwania"
#. TRANSLATORS: the user did not specify what they wanted to install
-#: ../client/pk-console.c:1953
+#: ../client/pk-console.c:1965
msgid "A package name or filename to install is required"
msgstr "Wymagana jest nazwa pakietu lub pliku do zainstalowania"
#. TRANSLATORS: geeky error, 99.9999% of users won't see this
-#: ../client/pk-console.c:1961
+#: ../client/pk-console.c:1973
msgid "A type, key_id and package_id are required"
msgstr "Wymagany jest typ, key_id i package_id"
#. TRANSLATORS: the user did not specify what they wanted to remove
-#: ../client/pk-console.c:1969
+#: ../client/pk-console.c:1981
msgid "A package name to remove is required"
msgstr "Wymagana jest nazwa pakietu do usuniÄcia"
#. TRANSLATORS: the user did not specify anything about what to download or where
-#: ../client/pk-console.c:1976
+#: ../client/pk-console.c:1988
msgid ""
"A destination directory and then the package names to download are required"
msgstr "Wymagany jest katalog docelowy, a nastÄpnie nazwy pakietów do pobrania"
#. TRANSLATORS: the directory does not exist, so we can't continue
-#: ../client/pk-console.c:1982
+#: ../client/pk-console.c:1994
msgid "Directory not found"
msgstr "Nie znaleziono katalogu"
#. TRANSLATORS: geeky error, 99.9999% of users won't see this
-#: ../client/pk-console.c:1989
+#: ../client/pk-console.c:2001
msgid "A licence identifier (eula-id) is required"
msgstr "Wymagany jest identyfikator licencji (eula-id)"
#. TRANSLATORS: geeky error, 99.9999% of users won't see this
-#: ../client/pk-console.c:1998
+#: ../client/pk-console.c:2010
msgid "A transaction identifier (tid) is required"
msgstr "Wymagany jest identyfikator transakcji (tid)"
#. TRANSLATORS: The user did not specify a package name
-#: ../client/pk-console.c:2014
+#: ../client/pk-console.c:2026
msgid "A package name to resolve is required"
msgstr "Wymagana jest nazwa pakietu do rozwiÄ
zania"
#. TRANSLATORS: The user did not specify a repository (software source) name
-#: ../client/pk-console.c:2022 ../client/pk-console.c:2030
+#: ../client/pk-console.c:2034 ../client/pk-console.c:2042
msgid "A repository name is required"
msgstr "Wymagana jest nazwa repozytorium"
#. TRANSLATORS: The user didn't provide any data
-#: ../client/pk-console.c:2038
+#: ../client/pk-console.c:2050
msgid "A repo name, parameter and value are required"
msgstr "Wymagana jest nazwa, parametr i wartoÅÄ repozytorium"
#. TRANSLATORS: The user didn't specify what action to use
-#: ../client/pk-console.c:2051
+#: ../client/pk-console.c:2063
msgid "An action, e.g. 'update-system' is required"
msgstr "Wymagane jest dziaÅanie, np. \"update-system\""
#. TRANSLATORS: The user specified an invalid action
-#: ../client/pk-console.c:2057
+#: ../client/pk-console.c:2069
msgid "A correct role is required"
msgstr "Wymagana jest bieżÄ
ca rola"
#. TRANSLATORS: we keep a database updated with the time that an action was last executed
-#: ../client/pk-console.c:2063
+#: ../client/pk-console.c:2075
msgid "Failed to get the time since this action was last completed"
msgstr ""
"Uzyskanie czasu od ostatniego zakoÅczenia tego dziaÅania nie powiodÅo siÄ"
#. TRANSLATORS: The user did not provide a package name
#. TRANSLATORS: This is when the user fails to supply the package name
-#: ../client/pk-console.c:2072 ../client/pk-console.c:2083
-#: ../client/pk-console.c:2091 ../client/pk-console.c:2107
-#: ../client/pk-console.c:2115 ../client/pk-generate-pack.c:241
+#: ../client/pk-console.c:2084 ../client/pk-console.c:2095
+#: ../client/pk-console.c:2103 ../client/pk-console.c:2119
+#: ../client/pk-console.c:2127 ../client/pk-generate-pack.c:241
msgid "A package name is required"
msgstr "Wymagana jest nazwa pakietu"
#. TRANSLATORS: each package "provides" certain things, e.g. mime(gstreamer-decoder-mp3), the user didn't specify it
-#: ../client/pk-console.c:2099
+#: ../client/pk-console.c:2111
msgid "A package provide string is required"
msgstr "Wymagany jest ÅaÅcuch dostarczania pakietu"
#. TRANSLATORS: The user didn't specify a filename to create as a list
-#: ../client/pk-console.c:2123
+#: ../client/pk-console.c:2135
msgid "A list file name to create is required"
msgstr "Wymagana jest lista nazw plików do utworzenia"
#. TRANSLATORS: The user didn't specify a filename to open as a list
-#: ../client/pk-console.c:2132 ../client/pk-console.c:2141
+#: ../client/pk-console.c:2144 ../client/pk-console.c:2153
msgid "A list file to open is required"
msgstr "Wymagana jest lista plików do otwarcia"
#. TRANSLATORS: The user tried to use an unsupported option on the command line
-#: ../client/pk-console.c:2194
+#: ../client/pk-console.c:2206
#, c-format
msgid "Option '%s' is not supported"
msgstr "Opcja \"%s\" nie jest obsÅugiwana"
#. TRANSLATORS: User does not have permission to do this
-#: ../client/pk-console.c:2207
+#: ../client/pk-console.c:2219
msgid "Incorrect privileges for this operation"
msgstr "Niepoprawne uprawnienia dla tego dziaÅania"
#. TRANSLATORS: Generic failure of what they asked to do
-#: ../client/pk-console.c:2210
+#: ../client/pk-console.c:2222
msgid "Command failed"
msgstr "Polecenie nie powiodÅo siÄ"
commit 1b88395a170da9942384f7ec7a1fc531dd67bc5b
Author: Richard Hughes <richard at hughsie.com>
Date: Sun Jul 12 19:38:30 2009 +0100
Fix a crash with the new code, where the signal wasn't being disconnected in one error case
diff --git a/src/gdb.sh b/src/gdb.sh
index c6072eb..31e6b99 100755
--- a/src/gdb.sh
+++ b/src/gdb.sh
@@ -1,4 +1,4 @@
export G_DEBUG=fatal_criticals
sudo touch /etc/PackageKit/PackageKit.conf
-sudo gdb --args .libs/lt-packagekitd --verbose --backend=dummy --disable-timer
+sudo gdb --args .libs/lt-packagekitd --verbose --backend=yum --disable-timer
diff --git a/src/pk-transaction-extra.c b/src/pk-transaction-extra.c
index 35d7807..fdeeef3 100644
--- a/src/pk-transaction-extra.c
+++ b/src/pk-transaction-extra.c
@@ -641,7 +641,7 @@ gboolean
pk_transaction_extra_check_running_process (PkTransactionExtra *post, gchar **package_ids)
{
PkStore *store;
- guint signal_files;
+ guint signal_files = 0;
g_return_val_if_fail (PK_IS_POST_TRANS (post), FALSE);
@@ -721,7 +721,7 @@ gboolean
pk_transaction_extra_check_desktop_files (PkTransactionExtra *post, gchar **package_ids)
{
PkStore *store;
- guint signal_files;
+ guint signal_files = 0;
g_return_val_if_fail (PK_IS_POST_TRANS (post), FALSE);
@@ -933,7 +933,7 @@ gboolean
pk_transaction_extra_check_library_restart (PkTransactionExtra *post, gchar **package_ids)
{
PkStore *store;
- guint signal_files;
+ guint signal_files = 0;
gboolean ret = TRUE;
gchar **files = NULL;
GPtrArray *pids;
@@ -1000,10 +1000,10 @@ pk_transaction_extra_check_library_restart (PkTransactionExtra *post, gchar **pa
/* emit */
pk_transaction_extra_check_library_restart_emit (post, pids);
g_ptr_array_free (pids, TRUE);
-
- g_signal_handler_disconnect (post->priv->backend, signal_files);
- pk_transaction_extra_set_progress_changed (post, 100);
out:
+ pk_transaction_extra_set_progress_changed (post, 100);
+ if (signal_files > 0)
+ g_signal_handler_disconnect (post->priv->backend, signal_files);
g_strfreev (files);
return ret;
}
commit 176889ce5eaa097f7a4799b548dd60c82f565afc
Author: Richard Hughes <richard at hughsie.com>
Date: Sun Jul 12 19:09:31 2009 +0100
trivial: Relax the library checks a little to cope with lib64
diff --git a/src/pk-transaction-extra.c b/src/pk-transaction-extra.c
index 8bcc21b..35d7807 100644
--- a/src/pk-transaction-extra.c
+++ b/src/pk-transaction-extra.c
@@ -767,7 +767,7 @@ pk_transaction_extra_files_check_library_restart_cb (PkBackend *backend, const g
len = g_strv_length (files);
for (i=0; i<len; i++) {
/* not a system library */
- if (strstr (files[i], "/lib/") == NULL)
+ if (strstr (files[i], "/lib") == NULL)
continue;
/* not a shared object */
commit 3c4eb8412bb1160f0515fc59452eaaba5570b0e2
Author: Richard Hughes <richard at hughsie.com>
Date: Sun Jul 12 19:02:20 2009 +0100
Add three new status enums to better describe what we are doing in the new code
diff --git a/lib/packagekit-glib/pk-enum.c b/lib/packagekit-glib/pk-enum.c
index bd47602..3a8a15e 100644
--- a/lib/packagekit-glib/pk-enum.c
+++ b/lib/packagekit-glib/pk-enum.c
@@ -87,6 +87,9 @@ static const PkEnumMatch enum_status[] = {
{PK_STATUS_ENUM_GENERATE_PACKAGE_LIST, "generate-package-list"},
{PK_STATUS_ENUM_WAITING_FOR_LOCK, "waiting-for-lock"},
{PK_STATUS_ENUM_WAITING_FOR_AUTH, "waiting-for-auth"},
+ {PK_STATUS_ENUM_SCAN_PROCESS_LIST, "scan-process-list"},
+ {PK_STATUS_ENUM_CHECK_EXECUTABLE_FILES, "check-executable-files"},
+ {PK_STATUS_ENUM_CHECK_LIBRARIES, "check-libraries"},
{0, NULL}
};
diff --git a/lib/packagekit-glib/pk-enum.h b/lib/packagekit-glib/pk-enum.h
index 927a9dd..6ccf65f 100644
--- a/lib/packagekit-glib/pk-enum.h
+++ b/lib/packagekit-glib/pk-enum.h
@@ -136,6 +136,9 @@ typedef enum {
PK_STATUS_ENUM_GENERATE_PACKAGE_LIST,
PK_STATUS_ENUM_WAITING_FOR_LOCK,
PK_STATUS_ENUM_WAITING_FOR_AUTH,
+ PK_STATUS_ENUM_SCAN_PROCESS_LIST,
+ PK_STATUS_ENUM_CHECK_EXECUTABLE_FILES,
+ PK_STATUS_ENUM_CHECK_LIBRARIES,
PK_STATUS_ENUM_UNKNOWN
} PkStatusEnum;
diff --git a/src/pk-transaction-extra.c b/src/pk-transaction-extra.c
index 740ba8a..8bcc21b 100644
--- a/src/pk-transaction-extra.c
+++ b/src/pk-transaction-extra.c
@@ -650,7 +650,7 @@ pk_transaction_extra_check_running_process (PkTransactionExtra *post, gchar **pa
return FALSE;
}
- pk_transaction_extra_set_status_changed (post, PK_STATUS_ENUM_SCAN_APPLICATIONS);
+ pk_transaction_extra_set_status_changed (post, PK_STATUS_ENUM_CHECK_EXECUTABLE_FILES);
pk_transaction_extra_set_progress_changed (post, 101);
store = pk_backend_get_store (post->priv->backend);
@@ -949,6 +949,10 @@ pk_transaction_extra_check_library_restart (PkTransactionExtra *post, gchar **pa
g_ptr_array_foreach (post->priv->files_list, (GFunc) g_free, NULL);
g_ptr_array_set_size (post->priv->files_list, 0);
+ /* set status */
+ pk_transaction_extra_set_status_changed (post, PK_STATUS_ENUM_SCAN_PROCESS_LIST);
+ pk_transaction_extra_set_progress_changed (post, 101);
+
/* get list from lsof */
ret = pk_lsof_refresh (post->priv->lsof);
if (!ret) {
@@ -956,8 +960,8 @@ pk_transaction_extra_check_library_restart (PkTransactionExtra *post, gchar **pa
goto out;
}
- pk_transaction_extra_set_status_changed (post, PK_STATUS_ENUM_SCAN_APPLICATIONS);
- pk_transaction_extra_set_progress_changed (post, 101);
+ /* set status */
+ pk_transaction_extra_set_status_changed (post, PK_STATUS_ENUM_CHECK_LIBRARIES);
store = pk_backend_get_store (post->priv->backend);
signal_files = g_signal_connect (post->priv->backend, "files",
commit 5086f3a6fd979d68e3327afc25b69a86e19f1c7e
Author: Mounir Lamouri (volkmar) <mounir.lamouri at gmail.com>
Date: Sun Jul 12 14:57:39 2009 +0200
portage: update get-requires to let it works with svn portage version
diff --git a/backends/portage/portageBackend.py b/backends/portage/portageBackend.py
index ace0e60..51c0fe1 100755
--- a/backends/portage/portageBackend.py
+++ b/backends/portage/portageBackend.py
@@ -753,11 +753,13 @@ class PackageKitPortageBackend(PackageKitBaseBackend, PackagekitPackage):
myopts = {}
spinner = ""
favorites = []
- settings, trees, mtimedb = _emerge.load_emerge_config()
- spinner = _emerge.stdout_spinner()
- rootconfig = _emerge.RootConfig(self.portage_settings, trees["/"],
- portage._sets.load_default_config(
- self.portage_settings, trees["/"]))
+
+ spinner = _emerge.stdout_spinner.stdout_spinner()
+ settings, trees, _ = _emerge.actions.load_emerge_config()
+ rootconfig = _emerge.RootConfig.RootConfig(
+ self.portage_settings, trees["/"],
+ portage.sets.load_default_config(self.portage_settings,
+ trees["/"]))
for pkg in pkgs:
cpv = id_to_cpv(pkg)
@@ -774,7 +776,7 @@ class PackageKitPortageBackend(PackageKitBaseBackend, PackagekitPackage):
required_set_names = ("system", "world")
required_sets = {}
- args_set = portage._sets.base.InternalPackageSet()
+ args_set = portage.sets.base.InternalPackageSet()
args_set.update(["="+cpv]) # parameters is converted to atom
# or use portage.dep_expand
@@ -783,12 +785,13 @@ class PackageKitPortageBackend(PackageKitBaseBackend, PackagekitPackage):
"Was not able to generate atoms")
continue
- depgraph = _emerge.depgraph(settings, trees, myopts,
- _emerge.create_depgraph_params(myopts, "remove"), spinner)
- vardb = depgraph.trees["/"]["vartree"].dbapi
+ depgraph = _emerge.depgraph.depgraph(settings, trees, myopts,
+ _emerge.create_depgraph_params.create_depgraph_params(
+ myopts, "remove"), spinner)
+ vardb = depgraph._frozen_config.trees["/"]["vartree"].dbapi
for s in required_set_names:
- required_sets[s] = portage._sets.base.InternalPackageSet(
+ required_sets[s] = portage.sets.base.InternalPackageSet(
initial_atoms=rootconfig.setconfig.getSetAtoms(s))
# TODO: error/warning if world = null or system = null ?
@@ -796,7 +799,6 @@ class PackageKitPortageBackend(PackageKitBaseBackend, PackagekitPackage):
# TODO: not sure it's needed. for deselect in emerge...
required_sets["world"].clear()
for pkg in vardb:
- spinner.update()
try:
if args_set.findAtomForPackage(pkg) is None:
required_sets["world"].add("=" + pkg.cpv)
@@ -805,15 +807,15 @@ class PackageKitPortageBackend(PackageKitBaseBackend, PackagekitPackage):
set_args = {}
for s, pkg_set in required_sets.iteritems():
- set_atom = portage._sets.SETPREFIX + s
- set_arg = _emerge.SetArg(arg=set_atom, set=pkg_set,
- root_config=depgraph.roots[portage.settings["ROOT"]])
+ set_atom = portage.sets.SETPREFIX + s
+ set_arg = _emerge.SetArg.SetArg(arg=set_atom, set=pkg_set,
+ root_config=depgraph._frozen_config.roots[portage.settings["ROOT"]])
set_args[s] = set_arg
for atom in set_arg.set:
- depgraph._dep_stack.append(
- _emerge.Dependency(atom=atom, root=portage.settings["ROOT"],
+ depgraph._dynamic_config._dep_stack.append(
+ _emerge.Dependency.Dependency(atom=atom, root=portage.settings["ROOT"],
parent=set_arg))
- depgraph.digraph.add(set_arg, None)
+ depgraph._dynamic_config.digraph.add(set_arg, None)
if not depgraph._complete_graph():
self.error(ERROR_INTERNAL_ERROR, "Error when generating depgraph")
@@ -835,8 +837,8 @@ class PackageKitPortageBackend(PackageKitBaseBackend, PackagekitPackage):
except portage.exception.InvalidDependString:
continue
- if arg_atom and pkg in depgraph.digraph:
- parents = depgraph.digraph.parent_nodes(pkg)
+ if arg_atom and pkg in depgraph._dynamic_config.digraph:
+ parents = depgraph._dynamic_config.digraph.parent_nodes(pkg)
for node in parents:
self.package(node[2])
commit bf915c29df209e9dce55f9b5c154eccb13388e54
Author: Mounir Lamouri (volkmar) <mounir.lamouri at gmail.com>
Date: Sun Jul 12 12:59:52 2009 +0200
portage: get-depends filtering output, get-requires manages ERROR_CANNOT_GET_REQUIRES, comments and cosmetic
diff --git a/backends/portage/portageBackend.py b/backends/portage/portageBackend.py
index dab904b..ace0e60 100755
--- a/backends/portage/portageBackend.py
+++ b/backends/portage/portageBackend.py
@@ -527,7 +527,8 @@ class PackageKitPortageBackend(PackageKitBaseBackend, PackagekitPackage):
def get_depends(self, filters, pkgs, recursive):
# TODO: use only myparams ?
- # TODO: error management
+ # TODO: improve error management / info
+ # TODO: show DEPEND-only depends too
# FILTERS:
# - installed: ok
@@ -548,7 +549,7 @@ class PackageKitPortageBackend(PackageKitBaseBackend, PackagekitPackage):
if not self.is_cpv_valid(cpv):
self.error(ERROR_PACKAGE_NOT_FOUND,
"Package %s was not found" % pkg)
- return
+ continue
cpv_input.append('=' + cpv)
myopts = {}
@@ -558,11 +559,16 @@ class PackageKitPortageBackend(PackageKitBaseBackend, PackagekitPackage):
settings, trees, _ = _emerge.actions.load_emerge_config()
myparams = _emerge.create_depgraph_params.create_depgraph_params(
myopts, "")
- depgraph = _emerge.depgraph.depgraph(
- settings, trees, myopts, myparams, spinner)
- retval, fav = depgraph.select_files(cpv_input)
+
+ try:
+ self.block_output()
+ depgraph = _emerge.depgraph.depgraph(
+ settings, trees, myopts, myparams, spinner)
+ retval, fav = depgraph.select_files(cpv_input)
+ finally:
+ self.unblock_output()
+
if not retval:
- depgraph.display_problems()
self.error(ERROR_INTERNAL_ERROR,
"Wasn't able to get dependency graph")
return
@@ -740,7 +746,6 @@ class PackageKitPortageBackend(PackageKitBaseBackend, PackagekitPackage):
# TODO: filters
# TODO: recursive not implemented
# TODO: usefulness ? use cases
- # TODO: work only on installed packages
self.status(STATUS_RUNNING)
self.allow_cancel(True)
self.percentage(None)
@@ -751,16 +756,19 @@ class PackageKitPortageBackend(PackageKitBaseBackend, PackagekitPackage):
settings, trees, mtimedb = _emerge.load_emerge_config()
spinner = _emerge.stdout_spinner()
rootconfig = _emerge.RootConfig(self.portage_settings, trees["/"],
- portage._sets.load_default_config(self.portage_settings, trees["/"]))
+ portage._sets.load_default_config(
+ self.portage_settings, trees["/"]))
for pkg in pkgs:
cpv = id_to_cpv(pkg)
- # is cpv installed
- # TODO: keep error msg ?
- if not self.vardb.match(cpv):
- self.error(ERROR_PACKAGE_NOT_INSTALLED,
- "Package %s is not installed" % pkg)
+ if not self.is_cpv_valid(cpv):
+ self.error(ERROR_PACKAGE_NOT_FOUND,
+ "Package %s was not found" % pkg)
+ continue
+ if not self.is_installed(cpv):
+ self.error(ERROR_CANNOT_GET_REQUIRES,
+ "get-requires is only available for installed packages")
continue
required_set_names = ("system", "world")
@@ -771,7 +779,8 @@ class PackageKitPortageBackend(PackageKitBaseBackend, PackagekitPackage):
# or use portage.dep_expand
if not args_set:
- self.error(ERROR_INTERNAL_ERROR, "Was not able to generate atoms")
+ self.error(ERROR_INTERNAL_ERROR,
+ "Was not able to generate atoms")
continue
depgraph = _emerge.depgraph(settings, trees, myopts,
commit cdc781e22d9984cff6f5d07648e471c1360c92ee
Author: Mounir Lamouri (volkmar) <mounir.lamouri at gmail.com>
Date: Sun Jul 12 01:24:11 2009 +0200
portage: improve get-depends and manage filters
diff --git a/backends/portage/portageBackend.py b/backends/portage/portageBackend.py
index 223fe81..dab904b 100755
--- a/backends/portage/portageBackend.py
+++ b/backends/portage/portageBackend.py
@@ -30,6 +30,7 @@ import portage
import _emerge.actions
import _emerge.stdout_spinner
import _emerge.create_depgraph_params
+import _emerge.AtomArg
# layman imports
import layman.db
@@ -525,53 +526,97 @@ class PackageKitPortageBackend(PackageKitBaseBackend, PackagekitPackage):
PackageKitBaseBackend.package(self, self.cpv_to_id(cpv), info, desc)
def get_depends(self, filters, pkgs, recursive):
- # TODO: manage filters
- # TODO: optimize by using vardb for installed packages ?
- # TODO: use depgraph.select_files to select multiple files
- # TODO: print package in depends ?
+ # TODO: use only myparams ?
+ # TODO: error management
+
+ # FILTERS:
+ # - installed: ok
+ # - free: ok
+ # - newest: ignored because only one version of a package is installed
+
self.status(STATUS_INFO)
self.allow_cancel(True)
self.percentage(None)
+ fltlist = filters.split(';')
+
+ cpv_input = []
+ cpv_list = []
+
for pkg in pkgs:
cpv = id_to_cpv(pkg)
-
if not self.is_cpv_valid(cpv):
self.error(ERROR_PACKAGE_NOT_FOUND,
"Package %s was not found" % pkg)
- continue
+ return
+ cpv_input.append('=' + cpv)
- myopts = {}
- if recursive:
- myopts["--emptytree"] = True
- spinner = _emerge.stdout_spinner.stdout_spinner()
- settings, trees, _ = _emerge.actions.load_emerge_config()
- myparams = _emerge.create_depgraph_params.create_depgraph_params(
- myopts, "")
- depgraph = _emerge.depgraph.depgraph(
- settings, trees, myopts, myparams, spinner)
-
- retval, fav = depgraph.select_files(["="+cpv])
- if not retval:
- self.error(ERROR_INTERNAL_ERROR,
- "Wasn't able to get dependency graph")
- continue
+ myopts = {}
+ myopts["--selective"] = True
+ myopts["--deep"] = True
+ spinner = _emerge.stdout_spinner.stdout_spinner()
+ settings, trees, _ = _emerge.actions.load_emerge_config()
+ myparams = _emerge.create_depgraph_params.create_depgraph_params(
+ myopts, "")
+ depgraph = _emerge.depgraph.depgraph(
+ settings, trees, myopts, myparams, spinner)
+ retval, fav = depgraph.select_files(cpv_input)
+ if not retval:
+ depgraph.display_problems()
+ self.error(ERROR_INTERNAL_ERROR,
+ "Wasn't able to get dependency graph")
+ return
+
+ def _add_children_to_list(cpv_list, node):
+ for n in depgraph._dynamic_config.digraph.child_nodes(node):
+ if n not in cpv_list:
+ cpv_list.append(n)
+ _add_children_to_list(cpv_list, n)
+
+ for cpv in cpv_input:
+ for r in depgraph._dynamic_config.digraph.root_nodes():
+ if not isinstance(r, _emerge.AtomArg.AtomArg):
+ continue
+ if r.atom == cpv:
+ if recursive:
+ _add_children_to_list(cpv_list, r)
+ else:
+ for n in \
+ depgraph._dynamic_config.digraph.child_nodes(r):
+ for c in \
+ depgraph._dynamic_config.digraph.child_nodes(n):
+ cpv_list.append(c)
+
+ def _filter_uninstall(cpv):
+ return cpv[3] != 'uninstall'
+ def _filter_installed(cpv):
+ return cpv[0] == 'installed'
+ def _filter_not_installed(cpv):
+ return cpv[0] != 'installed'
+
+ # removing packages going to be uninstalled
+ cpv_list = filter(_filter_uninstall, cpv_list)
+
+ # install filter
+ if FILTER_INSTALLED in fltlist:
+ cpv_list = filter(_filter_installed, cpv_list)
+ if FILTER_NOT_INSTALLED in fltlist:
+ cpv_list = filter(_filter_not_installed, cpv_list)
- if recursive:
- # printing the whole tree
- for p in depgraph.altlist(reversed=1):
- if p[2] != cpv:
- self.package(p[2])
- else: # !recursive
- # only printing child of the root node
- # actually, we have "=cpv" -> "cpv" -> children
- root_node = depgraph._dynamic_config.digraph.root_nodes()[0] # =cpv
- root_node = depgraph._dynamic_config.digraph.child_nodes(
- root_node)[0] # cpv
- children = depgraph._dynamic_config.digraph.child_nodes(
- root_node)
- for child in children:
- self.package(child[2])
+ # now we can change cpv_list to a real cpv list
+ tmp_list = cpv_list[:]
+ cpv_list = []
+ for x in tmp_list:
+ cpv_list.append(x[2])
+ del tmp_list
+
+ # free filter
+ cpv_list = self.filter_free(cpv_list, fltlist)
+
+ for cpv in cpv_list:
+ # prevent showing input packages
+ if '=' + cpv not in cpv_input:
+ self.package(cpv)
def get_details(self, pkgs):
self.status(STATUS_INFO)
commit 52961029319579df9d20ab3a4f203f8d091bf99f
Author: Richard Hughes <richard at hughsie.com>
Date: Sat Jul 11 17:56:34 2009 +0100
One less FIXME, check the install-package for security updates
diff --git a/src/pk-transaction.c b/src/pk-transaction.c
index 0aa4e2a..697fbc6 100644
--- a/src/pk-transaction.c
+++ b/src/pk-transaction.c
@@ -1060,26 +1060,26 @@ pk_transaction_update_detail_cb (PkBackend *backend, const PkUpdateDetailObj *de
/**
* pk_transaction_pre_transaction_checks:
- *
- * TODO: also check if package in InstallPackages is in the update lists
- * and do the same check if this is so.
*/
static gboolean
-pk_transaction_pre_transaction_checks (PkTransaction *transaction)
+pk_transaction_pre_transaction_checks (PkTransaction *transaction, gchar **package_ids)
{
PkPackageList *updates;
const PkPackageObj *obj;
guint i;
+ guint j;
guint length;
gboolean ret = FALSE;
gchar *package_id;
- gchar **package_ids = NULL;
+ gchar **package_ids_security = NULL;
GPtrArray *list = NULL;
+ const gchar *package_id_tmp;
/* only do this for update actions */
if (transaction->priv->role != PK_ROLE_ENUM_UPDATE_SYSTEM &&
- transaction->priv->role != PK_ROLE_ENUM_UPDATE_PACKAGES) {
- egg_debug ("doing nothing, as not update");
+ transaction->priv->role != PK_ROLE_ENUM_UPDATE_PACKAGES &&
+ transaction->priv->role != PK_ROLE_ENUM_INSTALL_PACKAGES) {
+ egg_debug ("doing nothing, as not update or install");
goto out;
}
@@ -1109,11 +1109,33 @@ pk_transaction_pre_transaction_checks (PkTransaction *transaction)
}
}
+ /* is a security update we are installing */
+ if (transaction->priv->role == PK_ROLE_ENUM_INSTALL_PACKAGES) {
+ ret = FALSE;
+
+ /* do any of the packages we are updating match */
+ for (i=0; i < list->len; i++) {
+ package_id_tmp = g_ptr_array_index (list, i);
+ for (j=0; package_ids[j] != NULL; j++) {
+ if (g_strcmp0 (package_id_tmp, package_ids[j]) == 0) {
+ ret = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* nothing matched */
+ if (!ret) {
+ egg_debug ("not installing a security update package");
+ goto out;
+ }
+ }
+
/* find files in security updates */
- package_ids = pk_package_ids_from_array (list);
- ret = pk_transaction_extra_check_library_restart (transaction->priv->transaction_extra, package_ids);
+ package_ids_security = pk_package_ids_from_array (list);
+ ret = pk_transaction_extra_check_library_restart (transaction->priv->transaction_extra, package_ids_security);
out:
- g_strfreev (package_ids);
+ g_strfreev (package_ids_security);
if (list != NULL) {
g_ptr_array_foreach (list, (GFunc) g_free, NULL);
g_ptr_array_free (list, TRUE);
@@ -1157,7 +1179,7 @@ pk_transaction_set_running (PkTransaction *transaction)
egg_debug ("setting role for %s to %s", priv->tid, pk_role_enum_to_text (priv->role));
/* do any pre transaction checks */
- ret = pk_transaction_pre_transaction_checks (transaction);
+ ret = pk_transaction_pre_transaction_checks (transaction, priv->cached_package_ids);
/* might have to reset again if we used the backend */
if (ret)
commit 6e88599849d09fcd6fb08b6e86bfc1ea410d63a0
Author: Richard Hughes <richard at hughsie.com>
Date: Sat Jul 11 17:11:41 2009 +0100
Rename PkPostTrans to PkTransactionExtra as we're doing operations before the transactions now too
diff --git a/src/Makefile.am b/src/Makefile.am
index 6ada872..9a48b12 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -55,6 +55,8 @@ shared_SOURCES = \
pk-lsof.h \
pk-transaction.c \
pk-transaction.h \
+ pk-transaction-extra.c \
+ pk-transaction-extra.h \
pk-backend.c \
pk-backend.h \
pk-backend-internal.h \
@@ -62,8 +64,6 @@ shared_SOURCES = \
pk-network.h \
pk-shared.c \
pk-shared.h \
- pk-post-trans.c \
- pk-post-trans.h \
pk-time.h \
pk-time.c \
pk-network-stack.h \
diff --git a/src/pk-post-trans.c b/src/pk-post-trans.c
deleted file mode 100644
index 3021ff1..0000000
--- a/src/pk-post-trans.c
+++ /dev/null
@@ -1,1163 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2008 Richard Hughes <richard at hughsie.com>
- *
- * Licensed under the GNU General Public License Version 2
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <packagekit-glib/packagekit.h>
-#include <gio/gdesktopappinfo.h>
-#include <sqlite3.h>
-
-#include "egg-debug.h"
-
-#include "pk-post-trans.h"
-#include "pk-shared.h"
-#include "pk-marshal.h"
-#include "pk-backend-internal.h"
-#include "pk-lsof.h"
-
-#define PK_POST_TRANS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PK_TYPE_POST_TRANS, PkPostTransPrivate))
-
-struct PkPostTransPrivate
-{
- sqlite3 *db;
- PkBackend *backend;
- GMainLoop *loop;
- PkObjList *running_exec_list;
- PkPackageList *list;
- PkLsof *lsof;
- guint finished_id;
- guint package_id;
- GHashTable *hash;
- GPtrArray *files_list;
-};
-
-enum {
- PK_POST_TRANS_STATUS_CHANGED,
- PK_POST_TRANS_PROGRESS_CHANGED,
- PK_POST_TRANS_REQUIRE_RESTART,
- PK_POST_TRANS_LAST_SIGNAL
-};
-
-static guint signals [PK_POST_TRANS_LAST_SIGNAL] = { 0 };
-G_DEFINE_TYPE (PkPostTrans, pk_post_trans, G_TYPE_OBJECT)
-
-/**
- * pk_post_trans_finished_cb:
- **/
-static void
-pk_post_trans_finished_cb (PkBackend *backend, PkExitEnum exit_enum, PkPostTrans *post)
-{
- if (g_main_loop_is_running (post->priv->loop))
- g_main_loop_quit (post->priv->loop);
-}
-
-/**
- * pk_post_trans_package_cb:
- **/
-static void
-pk_post_trans_package_cb (PkBackend *backend, const PkPackageObj *obj, PkPostTrans *post)
-{
- pk_obj_list_add (PK_OBJ_LIST(post->priv->list), obj);
-}
-
-/**
- * pk_post_trans_set_require_restart:
- **/
-static void
-pk_post_trans_set_require_restart (PkPostTrans *post, PkRestartEnum restart, const gchar *package_id)
-{
- egg_debug ("emit require-restart %s, %s", pk_restart_enum_to_text (restart), package_id);
- g_signal_emit (post, signals [PK_POST_TRANS_REQUIRE_RESTART], 0, restart, package_id);
-}
-
-/**
- * pk_post_trans_set_status_changed:
- **/
-static void
-pk_post_trans_set_status_changed (PkPostTrans *post, PkStatusEnum status)
-{
- egg_debug ("emiting status-changed %s", pk_status_enum_to_text (status));
- g_signal_emit (post, signals [PK_POST_TRANS_STATUS_CHANGED], 0, status);
-}
-
-/**
- * pk_post_trans_set_progress_changed:
- **/
-static void
-pk_post_trans_set_progress_changed (PkPostTrans *post, guint percentage)
-{
- egg_debug ("emiting progress-changed %i", percentage);
- g_signal_emit (post, signals [PK_POST_TRANS_PROGRESS_CHANGED], 0, percentage, 0, 0, 0);
-}
-
-/**
- * pk_post_trans_get_installed_package_for_file:
- **/
-static const PkPackageObj *
-pk_post_trans_get_installed_package_for_file (PkPostTrans *post, const gchar *filename)
-{
- guint size;
- const PkPackageObj *obj = NULL;
- PkStore *store;
-
- /* use PK to find the correct package */
- pk_obj_list_clear (PK_OBJ_LIST(post->priv->list));
- pk_backend_reset (post->priv->backend);
- store = pk_backend_get_store (post->priv->backend);
- pk_store_set_uint (store, "filters", pk_bitfield_value (PK_FILTER_ENUM_INSTALLED));
- pk_store_set_string (store, "search", filename);
- post->priv->backend->desc->search_file (post->priv->backend, pk_bitfield_value (PK_FILTER_ENUM_INSTALLED), filename);
-
- /* wait for finished */
- g_main_loop_run (post->priv->loop);
-
- /* check that we only matched one package */
- size = pk_package_list_get_size (post->priv->list);
- if (size != 1) {
- egg_warning ("not correct size, %i", size);
- goto out;
- }
-
- /* get the obj */
- obj = pk_package_list_get_obj (post->priv->list, 0);
- if (obj == NULL) {
- egg_warning ("cannot get obj");
- goto out;
- }
-out:
- return obj;
-}
-
-/**
- * pk_post_trans_string_list_new:
- **/
-static PkObjList *
-pk_post_trans_string_list_new ()
-{
- PkObjList *list;
- list = pk_obj_list_new ();
- pk_obj_list_set_compare (list, (PkObjListCompareFunc) g_strcmp0);
- pk_obj_list_set_copy (list, (PkObjListCopyFunc) g_strdup);
- pk_obj_list_set_free (list, (PkObjListFreeFunc) g_free);
- pk_obj_list_set_to_string (list, (PkObjListToStringFunc) g_strdup);
- pk_obj_list_set_from_string (list, (PkObjListFromStringFunc) g_strdup);
- return list;
-}
-
-/**
- * pk_post_trans_get_filename_md5:
- **/
-static gchar *
-pk_post_trans_get_filename_md5 (const gchar *filename)
-{
- gchar *md5 = NULL;
- gchar *data = NULL;
- gsize length;
- GError *error = NULL;
- gboolean ret;
-
- /* check is no longer exists */
- ret = g_file_test (filename, G_FILE_TEST_EXISTS);
- if (!ret)
- goto out;
-
- /* get data */
- ret = g_file_get_contents (filename, &data, &length, &error);
- if (!ret) {
- egg_warning ("failed to open file %s: %s", filename, error->message);
- g_error_free (error);
- goto out;
- }
-
- /* check md5 is same */
- md5 = g_compute_checksum_for_data (G_CHECKSUM_MD5, (const guchar *) data, length);
-out:
- g_free (data);
- return md5;
-}
-
-/**
- * pk_post_trans_sqlite_remove_filename:
- **/
-static gint
-pk_post_trans_sqlite_remove_filename (PkPostTrans *post, const gchar *filename)
-{
- gchar *statement;
- gint rc;
-
- statement = g_strdup_printf ("DELETE FROM cache WHERE filename = '%s'", filename);
- rc = sqlite3_exec (post->priv->db, statement, NULL, NULL, NULL);
- g_free (statement);
- return rc;
-}
-
-/**
- * pk_post_trans_sqlite_add_filename_details:
- **/
-static gint
-pk_post_trans_sqlite_add_filename_details (PkPostTrans *post, const gchar *filename, const gchar *package, const gchar *md5)
-{
- gchar *statement;
- gchar *error_msg = NULL;
- sqlite3_stmt *sql_statement = NULL;
- gint rc = -1;
- gint show;
- GDesktopAppInfo *info;
-
- /* find out if we should show desktop file in menus */
- info = g_desktop_app_info_new_from_filename (filename);
- if (info == NULL) {
- egg_warning ("could not load desktop file %s", filename);
- goto out;
- }
- show = g_app_info_should_show (G_APP_INFO (info));
- g_object_unref (info);
-
- egg_debug ("add filename %s from %s with md5: %s (show: %i)", filename, package, md5, show);
-
- /* the row might already exist */
- statement = g_strdup_printf ("DELETE FROM cache WHERE filename = '%s'", filename);
- sqlite3_exec (post->priv->db, statement, NULL, NULL, NULL);
- g_free (statement);
-
- /* prepare the query, as we don't escape it */
- rc = sqlite3_prepare_v2 (post->priv->db, "INSERT INTO cache (filename, package, show, md5) VALUES (?, ?, ?, ?)", -1, &sql_statement, NULL);
- if (rc != SQLITE_OK) {
- egg_warning ("SQL failed to prepare: %s", sqlite3_errmsg (post->priv->db));
- goto out;
- }
-
- /* add data */
- sqlite3_bind_text (sql_statement, 1, filename, -1, SQLITE_STATIC);
- sqlite3_bind_text (sql_statement, 2, package, -1, SQLITE_STATIC);
- sqlite3_bind_int (sql_statement, 3, show);
- sqlite3_bind_text (sql_statement, 4, md5, -1, SQLITE_STATIC);
-
- /* save this */
- sqlite3_step (sql_statement);
- rc = sqlite3_finalize (sql_statement);
- if (rc != SQLITE_OK) {
- egg_warning ("SQL error: %s\n", error_msg);
- sqlite3_free (error_msg);
- goto out;
- }
-
-out:
- return rc;
-}
-
-/**
- * pk_post_trans_sqlite_add_filename:
- **/
-static gint
-pk_post_trans_sqlite_add_filename (PkPostTrans *post, const gchar *filename, const gchar *md5_opt)
-{
- gchar *md5 = NULL;
- gchar *package = NULL;
- gint rc = -1;
- const PkPackageObj *obj;
-
- /* if we've got it, use old data */
- if (md5_opt != NULL)
- md5 = g_strdup (md5_opt);
- else
- md5 = pk_post_trans_get_filename_md5 (filename);
-
- /* resolve */
- obj = pk_post_trans_get_installed_package_for_file (post, filename);
- if (obj == NULL) {
- egg_warning ("failed to get list");
- goto out;
- }
-
- /* add */
- rc = pk_post_trans_sqlite_add_filename_details (post, filename, obj->id->name, md5);
-out:
- g_free (md5);
- g_free (package);
- return rc;
-}
-
-/**
- * pk_post_trans_sqlite_cache_rescan_cb:
- **/
-static gint
-pk_post_trans_sqlite_cache_rescan_cb (void *data, gint argc, gchar **argv, gchar **col_name)
-{
- PkPostTrans *post = PK_POST_TRANS (data);
- const gchar *filename = NULL;
- const gchar *md5 = NULL;
- gchar *md5_calc = NULL;
- gint i;
-
- /* add the filename data to the array */
- for (i=0; i<argc; i++) {
- if (g_strcmp0 (col_name[i], "filename") == 0 && argv[i] != NULL)
- filename = argv[i];
- else if (g_strcmp0 (col_name[i], "md5") == 0 && argv[i] != NULL)
- md5 = argv[i];
- }
-
- /* sanity check */
- if (filename == NULL || md5 == NULL) {
- egg_warning ("filename %s and md5 %s)", filename, md5);
- goto out;
- }
-
- /* get md5 */
- md5_calc = pk_post_trans_get_filename_md5 (filename);
- if (md5_calc == NULL) {
- egg_debug ("remove of %s as no longer found", filename);
- pk_post_trans_sqlite_remove_filename (post, filename);
- goto out;
- }
-
- /* we've checked the file */
- g_hash_table_insert (post->priv->hash, g_strdup (filename), GUINT_TO_POINTER (1));
-
- /* check md5 is same */
- if (g_strcmp0 (md5, md5_calc) != 0) {
- egg_debug ("add of %s as md5 invalid (%s vs %s)", filename, md5, md5_calc);
- pk_post_trans_sqlite_add_filename (post, filename, md5_calc);
- }
-
- egg_debug ("existing filename %s valid, md5=%s", filename, md5);
-out:
- g_free (md5_calc);
- return 0;
-}
-
-/**
- * pk_post_trans_import_desktop_files:
- **/
-gboolean
-pk_post_trans_import_desktop_files (PkPostTrans *post)
-{
- gchar *statement;
- gchar *error_msg = NULL;
- gint rc;
- GError *error = NULL;
- GDir *dir;
- const gchar *filename;
- gpointer data;
- gchar *path;
- GPtrArray *array;
- gfloat step;
- guint i;
-
- g_return_val_if_fail (PK_IS_POST_TRANS (post), FALSE);
- g_return_val_if_fail (post->priv->db != NULL, FALSE);
-
- if (post->priv->backend->desc->search_file == NULL) {
- egg_debug ("cannot search files");
- return FALSE;
- }
-
- /* use a local backend instance */
- pk_backend_reset (post->priv->backend);
- pk_post_trans_set_status_changed (post, PK_STATUS_ENUM_SCAN_APPLICATIONS);
-
- /* reset hash */
- g_hash_table_remove_all (post->priv->hash);
- pk_post_trans_set_progress_changed (post, 101);
-
- /* first go through the existing data, and look for modifications and removals */
- statement = g_strdup ("SELECT filename, md5 FROM cache");
- rc = sqlite3_exec (post->priv->db, statement, pk_post_trans_sqlite_cache_rescan_cb, post, &error_msg);
- g_free (statement);
- if (rc != SQLITE_OK) {
- egg_warning ("SQL error: %s\n", error_msg);
- sqlite3_free (error_msg);
- }
-
- /* open directory */
- dir = g_dir_open (PK_DESKTOP_DEFAULT_APPLICATION_DIR, 0, &error);
- if (dir == NULL) {
- egg_warning ("failed to open file %s: %s", PK_DESKTOP_DEFAULT_APPLICATION_DIR, error->message);
- g_error_free (error);
- goto out;
- }
-
- /* go through desktop files and add them to an array if not present */
- filename = g_dir_read_name (dir);
- array = g_ptr_array_new ();
- while (filename != NULL) {
- if (g_str_has_suffix (filename, ".desktop")) {
- path = g_build_filename (PK_DESKTOP_DEFAULT_APPLICATION_DIR, filename, NULL);
- data = g_hash_table_lookup (post->priv->hash, path);
- if (data == NULL) {
- egg_debug ("add of %s as not present in db", path);
- g_ptr_array_add (array, g_strdup (path));
- }
- g_free (path);
- }
- filename = g_dir_read_name (dir);
- }
- g_dir_close (dir);
-
- step = 100.0f / array->len;
- pk_post_trans_set_status_changed (post, PK_STATUS_ENUM_GENERATE_PACKAGE_LIST);
-
- /* process files in an array */
- for (i=0; i<array->len; i++) {
- pk_post_trans_set_progress_changed (post, i * step);
- path = g_ptr_array_index (array, i);
- pk_post_trans_sqlite_add_filename (post, path, NULL);
- }
- g_ptr_array_foreach (array, (GFunc) g_free, NULL);
- g_ptr_array_free (array, TRUE);
-
-out:
- pk_post_trans_set_progress_changed (post, 100);
- pk_post_trans_set_status_changed (post, PK_STATUS_ENUM_FINISHED);
- return TRUE;
-}
-
-/**
- * pk_post_trans_update_package_list:
- **/
-gboolean
-pk_post_trans_update_package_list (PkPostTrans *post)
-{
- gboolean ret;
-
- g_return_val_if_fail (PK_IS_POST_TRANS (post), FALSE);
-
- if (post->priv->backend->desc->get_packages == NULL) {
- egg_debug ("cannot get packages");
- return FALSE;
- }
-
- egg_debug ("updating package lists");
-
- /* clear old list */
- pk_obj_list_clear (PK_OBJ_LIST(post->priv->list));
-
- /* update UI */
- pk_post_trans_set_status_changed (post, PK_STATUS_ENUM_GENERATE_PACKAGE_LIST);
- pk_post_trans_set_progress_changed (post, 101);
-
- /* get the new package list */
- pk_backend_reset (post->priv->backend);
- pk_store_set_uint (pk_backend_get_store (post->priv->backend), "filters", pk_bitfield_value (PK_FILTER_ENUM_NONE));
- post->priv->backend->desc->get_packages (post->priv->backend, PK_FILTER_ENUM_NONE);
-
- /* wait for finished */
- g_main_loop_run (post->priv->loop);
-
- /* update UI */
- pk_post_trans_set_progress_changed (post, 90);
-
- /* convert to a file */
- ret = pk_obj_list_to_file (PK_OBJ_LIST(post->priv->list), PK_SYSTEM_PACKAGE_LIST_FILENAME);
- if (!ret)
- egg_warning ("failed to save to file");
-
- /* update UI */
- pk_post_trans_set_progress_changed (post, 100);
- pk_post_trans_set_status_changed (post, PK_STATUS_ENUM_FINISHED);
-
- return ret;
-}
-
-/**
- * pk_post_trans_clear_firmware_requests:
- **/
-gboolean
-pk_post_trans_clear_firmware_requests (PkPostTrans *post)
-{
- gboolean ret;
- gchar *filename;
-
- g_return_val_if_fail (PK_IS_POST_TRANS (post), FALSE);
-
- /* clear the firmware requests directory */
- filename = g_build_filename (LOCALSTATEDIR, "run", "PackageKit", "udev", NULL);
- egg_debug ("clearing udev firmware requests at %s", filename);
- ret = pk_directory_remove_contents (filename);
- if (!ret)
- egg_warning ("failed to clear %s", filename);
- g_free (filename);
- return ret;
-}
-
-
-/**
- * pk_post_trans_update_files_check_running_cb:
- **/
-static void
-pk_post_trans_update_files_check_running_cb (PkBackend *backend, const gchar *package_id,
- const gchar *filelist, PkPostTrans *post)
-{
- guint i;
- guint len;
- gboolean ret;
- gchar **files;
- PkPackageId *id;
-
- id = pk_package_id_new_from_string (package_id);
- files = g_strsplit (filelist, ";", 0);
-
- /* check each file */
- len = g_strv_length (files);
- for (i=0; i<len; i++) {
- /* executable? */
- ret = g_file_test (files[i], G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_EXECUTABLE | G_FILE_TEST_EXISTS);
- if (!ret)
- continue;
-
- /* running? */
- ret = pk_obj_list_exists (PK_OBJ_LIST(post->priv->running_exec_list), files[i]);
- if (!ret)
- continue;
-
- /* TODO: findout if the executable has a desktop file, and if so,
- * suggest an application restart instead */
-
- /* send signal about session restart */
- egg_debug ("package %s updated, and %s is running", id->name, files[i]);
- pk_backend_require_restart (post->priv->backend, PK_RESTART_ENUM_SESSION, package_id);
- }
- g_strfreev (files);
- pk_package_id_free (id);
-}
-
-#ifdef USE_SECURITY_POLKIT
-/**
- * dkp_post_trans_get_cmdline:
- **/
-static gchar *
-dkp_post_trans_get_cmdline (guint pid)
-{
- gboolean ret;
- gchar *filename = NULL;
- gchar *cmdline = NULL;
- GError *error = NULL;
-
- /* get command line from proc */
- filename = g_strdup_printf ("/proc/%i/cmdline", pid);
- ret = g_file_get_contents (filename, &cmdline, NULL, &error);
- if (!ret) {
- egg_debug ("failed to get cmdline: %s", error->message);
- g_error_free (error);
- goto out;
- }
-out:
- g_free (filename);
- return cmdline;
-}
-#endif
-
-/**
- * pk_post_trans_update_process_list:
- **/
-static gboolean
-pk_post_trans_update_process_list (PkPostTrans *post)
-{
- GDir *dir;
- const gchar *name;
- gchar *offset;
- gchar *uid_file;
- gchar *contents;
- gboolean ret;
- guint uid;
- pid_t pid;
- gchar *exec;
-
- uid = getuid ();
- dir = g_dir_open ("/proc", 0, NULL);
- name = g_dir_read_name (dir);
- pk_obj_list_clear (PK_OBJ_LIST(post->priv->running_exec_list));
- while (name != NULL) {
- contents = NULL;
- uid_file = g_build_filename ("/proc", name, "loginuid", NULL);
-
- /* is a process file */
- if (!g_file_test (uid_file, G_FILE_TEST_EXISTS))
- goto out;
-
- /* able to get contents */
- ret = g_file_get_contents (uid_file, &contents, 0, NULL);
- if (!ret)
- goto out;
-
- /* is run by our UID */
- uid = atoi (contents);
-
- /* get the exec for the pid */
- pid = atoi (name);
-#ifdef USE_SECURITY_POLKIT
- exec = dkp_post_trans_get_cmdline (pid);
- if (exec == NULL)
- goto out;
-#else
- goto out;
-#endif
-
- /* can be /usr/libexec/notification-daemon.#prelink#.9sOhao */
- offset = g_strrstr (exec, ".#prelink#.");
- if (offset != NULL)
- *(offset) = '\0';
- egg_debug ("uid=%i, pid=%i, exec=%s", uid, pid, exec);
- pk_obj_list_add (PK_OBJ_LIST(post->priv->running_exec_list), exec);
-out:
- g_free (uid_file);
- g_free (contents);
- name = g_dir_read_name (dir);
- }
- g_dir_close (dir);
- return TRUE;
-}
-
-/**
- * pk_post_trans_check_running_process:
- **/
-gboolean
-pk_post_trans_check_running_process (PkPostTrans *post, gchar **package_ids)
-{
- PkStore *store;
- guint signal_files;
-
- g_return_val_if_fail (PK_IS_POST_TRANS (post), FALSE);
-
- if (post->priv->backend->desc->get_files == NULL) {
- egg_debug ("cannot get files");
- return FALSE;
- }
-
- pk_post_trans_set_status_changed (post, PK_STATUS_ENUM_SCAN_APPLICATIONS);
- pk_post_trans_set_progress_changed (post, 101);
-
- store = pk_backend_get_store (post->priv->backend);
- pk_post_trans_update_process_list (post);
-
- signal_files = g_signal_connect (post->priv->backend, "files",
- G_CALLBACK (pk_post_trans_update_files_check_running_cb), post);
-
- /* get all the files touched in the packages we just updated */
- pk_backend_reset (post->priv->backend);
- pk_store_set_strv (store, "package_ids", package_ids);
- post->priv->backend->desc->get_files (post->priv->backend, package_ids);
-
- /* wait for finished */
- g_main_loop_run (post->priv->loop);
-
- g_signal_handler_disconnect (post->priv->backend, signal_files);
- pk_post_trans_set_progress_changed (post, 100);
- return TRUE;
-}
-
-/**
- * pk_post_trans_update_files_check_desktop_cb:
- **/
-static void
-pk_post_trans_update_files_check_desktop_cb (PkBackend *backend, const gchar *package_id,
- const gchar *filelist, PkPostTrans *post)
-{
- guint i;
- guint len;
- gboolean ret;
- gchar **files;
- gchar **package;
- PkPackageId *id;
- gchar *md5;
-
- id = pk_package_id_new_from_string (package_id);
- files = g_strsplit (filelist, ";", 0);
- package = g_strsplit (package_id, ";", 0);
-
- /* check each file */
- len = g_strv_length (files);
- for (i=0; i<len; i++) {
- /* exists? */
- ret = g_file_test (files[i], G_FILE_TEST_EXISTS);
- if (!ret)
- continue;
-
- /* .desktop file? */
- ret = g_str_has_suffix (files[i], ".desktop");
- if (!ret)
- continue;
-
- egg_debug ("adding filename %s", files[i]);
- md5 = pk_post_trans_get_filename_md5 (files[i]);
- pk_post_trans_sqlite_add_filename_details (post, files[i], package[0], md5);
- g_free (md5);
- }
- g_strfreev (files);
- g_strfreev (package);
- pk_package_id_free (id);
-}
-
-/**
- * pk_post_trans_check_desktop_files:
- **/
-gboolean
-pk_post_trans_check_desktop_files (PkPostTrans *post, gchar **package_ids)
-{
- PkStore *store;
- guint signal_files;
-
- g_return_val_if_fail (PK_IS_POST_TRANS (post), FALSE);
-
- if (post->priv->backend->desc->get_files == NULL) {
- egg_debug ("cannot get files");
- return FALSE;
- }
-
- pk_post_trans_set_status_changed (post, PK_STATUS_ENUM_SCAN_APPLICATIONS);
- pk_post_trans_set_progress_changed (post, 101);
-
- store = pk_backend_get_store (post->priv->backend);
- signal_files = g_signal_connect (post->priv->backend, "files",
- G_CALLBACK (pk_post_trans_update_files_check_desktop_cb), post);
-
- /* get all the files touched in the packages we just updated */
- pk_backend_reset (post->priv->backend);
- pk_store_set_strv (store, "package_ids", package_ids);
- post->priv->backend->desc->get_files (post->priv->backend, package_ids);
-
- /* wait for finished */
- g_main_loop_run (post->priv->loop);
-
- g_signal_handler_disconnect (post->priv->backend, signal_files);
- pk_post_trans_set_progress_changed (post, 100);
- return TRUE;
-}
-
-/**
- * pk_post_trans_files_check_library_restart_cb:
- **/
-static void
-pk_post_trans_files_check_library_restart_cb (PkBackend *backend, const gchar *package_id,
- const gchar *filelist, PkPostTrans *post)
-{
- guint i;
- guint len;
- gchar **files = NULL;
-
- files = g_strsplit (filelist, ";", 0);
-
- /* check each file to see if it's a system shared library */
- len = g_strv_length (files);
- for (i=0; i<len; i++) {
- /* not a system library */
- if (strstr (files[i], "/lib/") == NULL)
- continue;
-
- /* not a shared object */
- if (strstr (files[i], ".so") == NULL)
- continue;
-
- /* add as it matches the criteria */
- egg_debug ("adding filename %s", files[i]);
- g_ptr_array_add (post->priv->files_list, g_strdup (files[i]));
- }
-}
-
-/**
- * pk_post_trans_get_cmdline:
- **/
-static gchar *
-pk_post_trans_get_cmdline (PkPostTrans *post, guint pid)
-{
- gboolean ret;
- gchar *filename = NULL;
- gchar *cmdline = NULL;
- GError *error = NULL;
-
- /* get command line from proc */
- filename = g_strdup_printf ("/proc/%i/cmdline", pid);
- ret = g_file_get_contents (filename, &cmdline, NULL, &error);
- if (!ret) {
- egg_warning ("failed to get cmdline: %s", error->message);
- g_error_free (error);
- goto out;
- }
-out:
- g_free (filename);
- return cmdline;
-}
-
-/**
- * pk_post_trans_get_uid:
- **/
-static gint
-pk_post_trans_get_uid (PkPostTrans *post, guint pid)
-{
- gboolean ret;
- gint uid = -1;
- gchar *filename = NULL;
- gchar *uid_text = NULL;
- GError *error = NULL;
-
- /* get command line from proc */
- filename = g_strdup_printf ("/proc/%i/loginuid", pid);
- ret = g_file_get_contents (filename, &uid_text, NULL, &error);
- if (!ret) {
- egg_warning ("failed to get cmdline: %s", error->message);
- g_error_free (error);
- goto out;
- }
-
- /* convert from text */
- uid = atoi (uid_text);
-out:
- g_free (filename);
- g_free (uid_text);
- return uid;
-}
-
-/**
- * pk_post_trans_check_library_restart_emit:
- **/
-static gboolean
-pk_post_trans_check_library_restart_emit (PkPostTrans *post, GPtrArray *pids)
-{
- gint uid;
- guint i;
- guint pid;
- gchar *filename;
- gchar *cmdline;
- gchar *cmdline_full;
- gchar *package_id;
- GPtrArray *files_session;
- GPtrArray *files_system;
- const PkPackageObj *obj;
-
- /* create arrays */
- files_session = g_ptr_array_new ();
- files_system = g_ptr_array_new ();
-
- /* find the package name of each pid */
- for (i=0; i<pids->len; i++) {
- pid = GPOINTER_TO_INT (g_ptr_array_index (pids, i));
-
- /* get user */
- uid = pk_post_trans_get_uid (post, pid);
- if (uid < 0)
- continue;
-
- /* get command line */
- cmdline = pk_post_trans_get_cmdline (post, pid);
- if (cmdline == NULL)
- continue;
-
- /* prepend path if it does not already exist */
- if (cmdline[0] == '/')
- cmdline_full = g_strdup (cmdline);
- else
- cmdline_full = g_strdup_printf ("/usr/bin/%s", cmdline);
-
- egg_warning ("pid=%i: %s (%i)", pid, cmdline_full, uid);
- if (uid < 500)
- g_ptr_array_add (files_system, cmdline_full);
- else
- g_ptr_array_add (files_session, cmdline_full);
- g_free (cmdline);
- }
-
- /* we found nothing */
- if (files_system->len == 0 && files_session->len == 0) {
- egg_warning ("no pids could be resolved");
- goto out;
- }
-
- /* process all session restarts */
- for (i=0; i<files_session->len; i++) {
- filename = g_ptr_array_index (files_session, i);
-
- obj = pk_post_trans_get_installed_package_for_file (post, filename);
- if (obj == NULL) {
- egg_warning ("failed to find package for %s", filename);
- continue;
- }
-
- package_id = pk_package_id_to_string (obj->id);
- pk_post_trans_set_require_restart (post, PK_RESTART_ENUM_SECURITY_SESSION, package_id);
- g_free (package_id);
- }
-
- /* process all system restarts */
- for (i=0; i<files_system->len; i++) {
- filename = g_ptr_array_index (files_system, i);
-
- obj = pk_post_trans_get_installed_package_for_file (post, filename);
- if (obj == NULL) {
- egg_warning ("failed to find package for %s", filename);
- continue;
- }
-
- package_id = pk_package_id_to_string (obj->id);
- pk_post_trans_set_require_restart (post, PK_RESTART_ENUM_SECURITY_SYSTEM, package_id);
- g_free (package_id);
- }
-
-out:
- g_ptr_array_foreach (files_session, (GFunc) g_free, NULL);
- g_ptr_array_foreach (files_system, (GFunc) g_free, NULL);
- g_ptr_array_free (files_session, TRUE);
- g_ptr_array_free (files_system, TRUE);
- return TRUE;
-}
-
-/**
- * pk_post_trans_check_library_restart:
- **/
-gboolean
-pk_post_trans_check_library_restart (PkPostTrans *post, gchar **package_ids)
-{
- PkStore *store;
- guint signal_files;
- gboolean ret = TRUE;
- gchar **files = NULL;
- GPtrArray *pids;
-
- g_return_val_if_fail (PK_IS_POST_TRANS (post), FALSE);
-
- if (post->priv->backend->desc->get_files == NULL) {
- egg_debug ("cannot get files");
- return FALSE;
- }
-
- /* reset */
- g_ptr_array_foreach (post->priv->files_list, (GFunc) g_free, NULL);
- g_ptr_array_set_size (post->priv->files_list, 0);
-
- /* get list from lsof */
- ret = pk_lsof_refresh (post->priv->lsof);
- if (!ret) {
- egg_warning ("failed to refresh");
- goto out;
- }
-
- pk_post_trans_set_status_changed (post, PK_STATUS_ENUM_SCAN_APPLICATIONS);
- pk_post_trans_set_progress_changed (post, 101);
-
- store = pk_backend_get_store (post->priv->backend);
- signal_files = g_signal_connect (post->priv->backend, "files",
- G_CALLBACK (pk_post_trans_files_check_library_restart_cb), post);
-
- /* get all the files touched in the packages we just updated */
- pk_backend_reset (post->priv->backend);
- pk_store_set_strv (store, "package_ids", package_ids);
- post->priv->backend->desc->get_files (post->priv->backend, package_ids);
-
- /* wait for finished */
- g_main_loop_run (post->priv->loop);
-
- /* nothing to do */
- if (post->priv->files_list->len == 0) {
- egg_warning ("no files");
- goto out;
- }
-
- /* get the list of PIDs */
- files = pk_ptr_array_to_strv (post->priv->files_list);
- pids = pk_lsof_get_pids_for_filenames (post->priv->lsof, files);
-
- /* nothing depends on these libraries */
- if (pids == NULL) {
- egg_warning ("failed to get process list");
- goto out;
- }
-
- /* nothing depends on these libraries */
- if (pids->len == 0) {
- egg_warning ("no processes depend on these libraries");
- goto out;
- }
-
- /* emit */
- pk_post_trans_check_library_restart_emit (post, pids);
- g_ptr_array_free (pids, TRUE);
-
- g_signal_handler_disconnect (post->priv->backend, signal_files);
- pk_post_trans_set_progress_changed (post, 100);
-out:
- g_strfreev (files);
- return ret;
-}
-
-/**
- * pk_post_trans_finalize:
- **/
-static void
-pk_post_trans_finalize (GObject *object)
-{
- PkPostTrans *post;
-
- g_return_if_fail (object != NULL);
- g_return_if_fail (PK_IS_POST_TRANS (object));
- post = PK_POST_TRANS (object);
-
- g_signal_handler_disconnect (post->priv->backend, post->priv->finished_id);
- g_signal_handler_disconnect (post->priv->backend, post->priv->package_id);
-
- if (g_main_loop_is_running (post->priv->loop))
- g_main_loop_quit (post->priv->loop);
- g_main_loop_unref (post->priv->loop);
- sqlite3_close (post->priv->db);
- g_hash_table_unref (post->priv->hash);
- g_ptr_array_foreach (post->priv->files_list, (GFunc) g_free, NULL);
- g_ptr_array_free (post->priv->files_list, TRUE);
-
- g_object_unref (post->priv->backend);
- g_object_unref (post->priv->lsof);
- g_object_unref (post->priv->list);
- g_object_unref (post->priv->running_exec_list);
-
- G_OBJECT_CLASS (pk_post_trans_parent_class)->finalize (object);
-}
-
-/**
- * pk_post_trans_class_init:
- **/
-static void
-pk_post_trans_class_init (PkPostTransClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = pk_post_trans_finalize;
- signals [PK_POST_TRANS_STATUS_CHANGED] =
- g_signal_new ("status-changed",
- G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
- 0, NULL, NULL, g_cclosure_marshal_VOID__UINT,
- G_TYPE_NONE, 1, G_TYPE_UINT);
- signals [PK_POST_TRANS_PROGRESS_CHANGED] =
- g_signal_new ("progress-changed",
- G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
- 0, NULL, NULL, pk_marshal_VOID__UINT_UINT_UINT_UINT,
- G_TYPE_NONE, 4, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
- signals [PK_POST_TRANS_REQUIRE_RESTART] =
- g_signal_new ("require-restart",
- G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
- 0, NULL, NULL, pk_marshal_VOID__UINT_STRING,
- G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
- g_type_class_add_private (klass, sizeof (PkPostTransPrivate));
-}
-
-/**
- * pk_post_trans_init:
- *
- * initializes the post_trans class. NOTE: We expect post_trans objects
- * to *NOT* be removed or added during the session.
- * We only control the first post_trans object if there are more than one.
- **/
-static void
-pk_post_trans_init (PkPostTrans *post)
-{
- gboolean ret;
- const gchar *statement;
- gchar *error_msg = NULL;
- gint rc;
-
- post->priv = PK_POST_TRANS_GET_PRIVATE (post);
- post->priv->running_exec_list = pk_post_trans_string_list_new ();
- post->priv->loop = g_main_loop_new (NULL, FALSE);
- post->priv->list = pk_package_list_new ();
- post->priv->backend = pk_backend_new ();
- post->priv->lsof = pk_lsof_new ();
- post->priv->db = NULL;
- post->priv->hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- post->priv->files_list = g_ptr_array_new ();
-
- post->priv->finished_id =
- g_signal_connect (post->priv->backend, "finished",
- G_CALLBACK (pk_post_trans_finished_cb), post);
- post->priv->package_id =
- g_signal_connect (post->priv->backend, "package",
- G_CALLBACK (pk_post_trans_package_cb), post);
-
- /* check if exists */
- ret = g_file_test (PK_DESKTOP_DEFAULT_DATABASE, G_FILE_TEST_EXISTS);
-
- egg_debug ("trying to open database '%s'", PK_DESKTOP_DEFAULT_DATABASE);
- rc = sqlite3_open (PK_DESKTOP_DEFAULT_DATABASE, &post->priv->db);
- if (rc != 0) {
- egg_warning ("Can't open database: %s\n", sqlite3_errmsg (post->priv->db));
- sqlite3_close (post->priv->db);
- post->priv->db = NULL;
- return;
- }
-
- /* create if not exists */
- if (!ret) {
- egg_debug ("creating database cache in %s", PK_DESKTOP_DEFAULT_DATABASE);
- statement = "CREATE TABLE cache ("
- "filename TEXT,"
- "package TEXT,"
- "show INTEGER,"
- "md5 TEXT);";
- rc = sqlite3_exec (post->priv->db, statement, NULL, NULL, &error_msg);
- if (rc != SQLITE_OK) {
- egg_warning ("SQL error: %s\n", error_msg);
- sqlite3_free (error_msg);
- }
- }
-
- /* we don't need to keep syncing */
- sqlite3_exec (post->priv->db, "PRAGMA synchronous=OFF", NULL, NULL, NULL);
-}
-
-/**
- * pk_post_trans_new:
- * Return value: A new post_trans class instance.
- **/
-PkPostTrans *
-pk_post_trans_new (void)
-{
- PkPostTrans *post;
- post = g_object_new (PK_TYPE_POST_TRANS, NULL);
- return PK_POST_TRANS (post);
-}
-
-/***************************************************************************
- *** MAKE CHECK TESTS ***
- ***************************************************************************/
-#ifdef EGG_TEST
-#include "egg-test.h"
-
-void
-egg_test_post_trans (EggTest *test)
-{
- PkPostTrans *post;
-
- if (!egg_test_start (test, "PkPostTrans"))
- return;
-
- /************************************************************/
- egg_test_title (test, "get an instance");
- post = pk_post_trans_new ();
- egg_test_assert (test, post != NULL);
-
- g_object_unref (post);
-
- egg_test_end (test);
-}
-#endif
-
diff --git a/src/pk-post-trans.h b/src/pk-post-trans.h
deleted file mode 100644
index 7f2fe9f..0000000
--- a/src/pk-post-trans.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2008 Richard Hughes <richard at hughsie.com>
- *
- * Licensed under the GNU General Public License Version 2
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __PK_POST_TRANS_H
-#define __PK_POST_TRANS_H
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define PK_TYPE_POST_TRANS (pk_post_trans_get_type ())
-#define PK_POST_TRANS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PK_TYPE_POST_TRANS, PkPostTrans))
-#define PK_POST_TRANS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PK_TYPE_POST_TRANS, PkPostTransClass))
-#define PK_IS_POST_TRANS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PK_TYPE_POST_TRANS))
-#define PK_IS_POST_TRANS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PK_TYPE_POST_TRANS))
-#define PK_POST_TRANS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PK_TYPE_POST_TRANS, PkPostTransClass))
-
-typedef struct PkPostTransPrivate PkPostTransPrivate;
-
-typedef struct
-{
- GObject parent;
- PkPostTransPrivate *priv;
-} PkPostTrans;
-
-typedef struct
-{
- GObjectClass parent_class;
-} PkPostTransClass;
-
-GType pk_post_trans_get_type (void);
-PkPostTrans *pk_post_trans_new (void);
-
-gboolean pk_post_trans_clear_firmware_requests (PkPostTrans *post);
-gboolean pk_post_trans_update_package_list (PkPostTrans *post);
-gboolean pk_post_trans_import_desktop_files (PkPostTrans *post);
-gboolean pk_post_trans_check_running_process (PkPostTrans *post,
- gchar **package_ids);
-gboolean pk_post_trans_check_desktop_files (PkPostTrans *post,
- gchar **package_ids);
-gboolean pk_post_trans_check_library_restart (PkPostTrans *post,
- gchar **package_ids);
-
-G_END_DECLS
-
-#endif /* __PK_POST_TRANS_H */
-
diff --git a/src/pk-transaction-extra.c b/src/pk-transaction-extra.c
new file mode 100644
index 0000000..740ba8a
--- /dev/null
+++ b/src/pk-transaction-extra.c
@@ -0,0 +1,1163 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008-2009 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <packagekit-glib/packagekit.h>
+#include <gio/gdesktopappinfo.h>
+#include <sqlite3.h>
+
+#include "egg-debug.h"
+
+#include "pk-transaction-extra.h"
+#include "pk-shared.h"
+#include "pk-marshal.h"
+#include "pk-backend-internal.h"
+#include "pk-lsof.h"
+
+#define PK_POST_TRANS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PK_TYPE_POST_TRANS, PkTransactionExtraPrivate))
+
+struct PkTransactionExtraPrivate
+{
+ sqlite3 *db;
+ PkBackend *backend;
+ GMainLoop *loop;
+ PkObjList *running_exec_list;
+ PkPackageList *list;
+ PkLsof *lsof;
+ guint finished_id;
+ guint package_id;
+ GHashTable *hash;
+ GPtrArray *files_list;
+};
+
+enum {
+ PK_POST_TRANS_STATUS_CHANGED,
+ PK_POST_TRANS_PROGRESS_CHANGED,
+ PK_POST_TRANS_REQUIRE_RESTART,
+ PK_POST_TRANS_LAST_SIGNAL
+};
+
+static guint signals [PK_POST_TRANS_LAST_SIGNAL] = { 0 };
+G_DEFINE_TYPE (PkTransactionExtra, pk_transaction_extra, G_TYPE_OBJECT)
+
+/**
+ * pk_transaction_extra_finished_cb:
+ **/
+static void
+pk_transaction_extra_finished_cb (PkBackend *backend, PkExitEnum exit_enum, PkTransactionExtra *post)
+{
+ if (g_main_loop_is_running (post->priv->loop))
+ g_main_loop_quit (post->priv->loop);
+}
+
+/**
+ * pk_transaction_extra_package_cb:
+ **/
+static void
+pk_transaction_extra_package_cb (PkBackend *backend, const PkPackageObj *obj, PkTransactionExtra *post)
+{
+ pk_obj_list_add (PK_OBJ_LIST(post->priv->list), obj);
+}
+
+/**
+ * pk_transaction_extra_set_require_restart:
+ **/
+static void
+pk_transaction_extra_set_require_restart (PkTransactionExtra *post, PkRestartEnum restart, const gchar *package_id)
+{
+ egg_debug ("emit require-restart %s, %s", pk_restart_enum_to_text (restart), package_id);
+ g_signal_emit (post, signals [PK_POST_TRANS_REQUIRE_RESTART], 0, restart, package_id);
+}
+
+/**
+ * pk_transaction_extra_set_status_changed:
+ **/
+static void
+pk_transaction_extra_set_status_changed (PkTransactionExtra *post, PkStatusEnum status)
+{
+ egg_debug ("emiting status-changed %s", pk_status_enum_to_text (status));
+ g_signal_emit (post, signals [PK_POST_TRANS_STATUS_CHANGED], 0, status);
+}
+
+/**
+ * pk_transaction_extra_set_progress_changed:
+ **/
+static void
+pk_transaction_extra_set_progress_changed (PkTransactionExtra *post, guint percentage)
+{
+ egg_debug ("emiting progress-changed %i", percentage);
+ g_signal_emit (post, signals [PK_POST_TRANS_PROGRESS_CHANGED], 0, percentage, 0, 0, 0);
+}
+
+/**
+ * pk_transaction_extra_get_installed_package_for_file:
+ **/
+static const PkPackageObj *
+pk_transaction_extra_get_installed_package_for_file (PkTransactionExtra *post, const gchar *filename)
+{
+ guint size;
+ const PkPackageObj *obj = NULL;
+ PkStore *store;
+
+ /* use PK to find the correct package */
+ pk_obj_list_clear (PK_OBJ_LIST(post->priv->list));
+ pk_backend_reset (post->priv->backend);
+ store = pk_backend_get_store (post->priv->backend);
+ pk_store_set_uint (store, "filters", pk_bitfield_value (PK_FILTER_ENUM_INSTALLED));
+ pk_store_set_string (store, "search", filename);
+ post->priv->backend->desc->search_file (post->priv->backend, pk_bitfield_value (PK_FILTER_ENUM_INSTALLED), filename);
+
+ /* wait for finished */
+ g_main_loop_run (post->priv->loop);
+
+ /* check that we only matched one package */
+ size = pk_package_list_get_size (post->priv->list);
+ if (size != 1) {
+ egg_warning ("not correct size, %i", size);
+ goto out;
+ }
+
+ /* get the obj */
+ obj = pk_package_list_get_obj (post->priv->list, 0);
+ if (obj == NULL) {
+ egg_warning ("cannot get obj");
+ goto out;
+ }
+out:
+ return obj;
+}
+
+/**
+ * pk_transaction_extra_string_list_new:
+ **/
+static PkObjList *
+pk_transaction_extra_string_list_new ()
+{
+ PkObjList *list;
+ list = pk_obj_list_new ();
+ pk_obj_list_set_compare (list, (PkObjListCompareFunc) g_strcmp0);
+ pk_obj_list_set_copy (list, (PkObjListCopyFunc) g_strdup);
+ pk_obj_list_set_free (list, (PkObjListFreeFunc) g_free);
+ pk_obj_list_set_to_string (list, (PkObjListToStringFunc) g_strdup);
+ pk_obj_list_set_from_string (list, (PkObjListFromStringFunc) g_strdup);
+ return list;
+}
+
+/**
+ * pk_transaction_extra_get_filename_md5:
+ **/
+static gchar *
+pk_transaction_extra_get_filename_md5 (const gchar *filename)
+{
+ gchar *md5 = NULL;
+ gchar *data = NULL;
+ gsize length;
+ GError *error = NULL;
+ gboolean ret;
+
+ /* check is no longer exists */
+ ret = g_file_test (filename, G_FILE_TEST_EXISTS);
+ if (!ret)
+ goto out;
+
+ /* get data */
+ ret = g_file_get_contents (filename, &data, &length, &error);
+ if (!ret) {
+ egg_warning ("failed to open file %s: %s", filename, error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* check md5 is same */
+ md5 = g_compute_checksum_for_data (G_CHECKSUM_MD5, (const guchar *) data, length);
+out:
+ g_free (data);
+ return md5;
+}
+
+/**
+ * pk_transaction_extra_sqlite_remove_filename:
+ **/
+static gint
+pk_transaction_extra_sqlite_remove_filename (PkTransactionExtra *post, const gchar *filename)
+{
+ gchar *statement;
+ gint rc;
+
+ statement = g_strdup_printf ("DELETE FROM cache WHERE filename = '%s'", filename);
+ rc = sqlite3_exec (post->priv->db, statement, NULL, NULL, NULL);
+ g_free (statement);
+ return rc;
+}
+
+/**
+ * pk_transaction_extra_sqlite_add_filename_details:
+ **/
+static gint
+pk_transaction_extra_sqlite_add_filename_details (PkTransactionExtra *post, const gchar *filename, const gchar *package, const gchar *md5)
+{
+ gchar *statement;
+ gchar *error_msg = NULL;
+ sqlite3_stmt *sql_statement = NULL;
+ gint rc = -1;
+ gint show;
+ GDesktopAppInfo *info;
+
+ /* find out if we should show desktop file in menus */
+ info = g_desktop_app_info_new_from_filename (filename);
+ if (info == NULL) {
+ egg_warning ("could not load desktop file %s", filename);
+ goto out;
+ }
+ show = g_app_info_should_show (G_APP_INFO (info));
+ g_object_unref (info);
+
+ egg_debug ("add filename %s from %s with md5: %s (show: %i)", filename, package, md5, show);
+
+ /* the row might already exist */
+ statement = g_strdup_printf ("DELETE FROM cache WHERE filename = '%s'", filename);
+ sqlite3_exec (post->priv->db, statement, NULL, NULL, NULL);
+ g_free (statement);
+
+ /* prepare the query, as we don't escape it */
+ rc = sqlite3_prepare_v2 (post->priv->db, "INSERT INTO cache (filename, package, show, md5) VALUES (?, ?, ?, ?)", -1, &sql_statement, NULL);
+ if (rc != SQLITE_OK) {
+ egg_warning ("SQL failed to prepare: %s", sqlite3_errmsg (post->priv->db));
+ goto out;
+ }
+
+ /* add data */
+ sqlite3_bind_text (sql_statement, 1, filename, -1, SQLITE_STATIC);
+ sqlite3_bind_text (sql_statement, 2, package, -1, SQLITE_STATIC);
+ sqlite3_bind_int (sql_statement, 3, show);
+ sqlite3_bind_text (sql_statement, 4, md5, -1, SQLITE_STATIC);
+
+ /* save this */
+ sqlite3_step (sql_statement);
+ rc = sqlite3_finalize (sql_statement);
+ if (rc != SQLITE_OK) {
+ egg_warning ("SQL error: %s\n", error_msg);
+ sqlite3_free (error_msg);
+ goto out;
+ }
+
+out:
+ return rc;
+}
+
+/**
+ * pk_transaction_extra_sqlite_add_filename:
+ **/
+static gint
+pk_transaction_extra_sqlite_add_filename (PkTransactionExtra *post, const gchar *filename, const gchar *md5_opt)
+{
+ gchar *md5 = NULL;
+ gchar *package = NULL;
+ gint rc = -1;
+ const PkPackageObj *obj;
+
+ /* if we've got it, use old data */
+ if (md5_opt != NULL)
+ md5 = g_strdup (md5_opt);
+ else
+ md5 = pk_transaction_extra_get_filename_md5 (filename);
+
+ /* resolve */
+ obj = pk_transaction_extra_get_installed_package_for_file (post, filename);
+ if (obj == NULL) {
+ egg_warning ("failed to get list");
+ goto out;
+ }
+
+ /* add */
+ rc = pk_transaction_extra_sqlite_add_filename_details (post, filename, obj->id->name, md5);
+out:
+ g_free (md5);
+ g_free (package);
+ return rc;
+}
+
+/**
+ * pk_transaction_extra_sqlite_cache_rescan_cb:
+ **/
+static gint
+pk_transaction_extra_sqlite_cache_rescan_cb (void *data, gint argc, gchar **argv, gchar **col_name)
+{
+ PkTransactionExtra *post = PK_POST_TRANS (data);
+ const gchar *filename = NULL;
+ const gchar *md5 = NULL;
+ gchar *md5_calc = NULL;
+ gint i;
+
+ /* add the filename data to the array */
+ for (i=0; i<argc; i++) {
+ if (g_strcmp0 (col_name[i], "filename") == 0 && argv[i] != NULL)
+ filename = argv[i];
+ else if (g_strcmp0 (col_name[i], "md5") == 0 && argv[i] != NULL)
+ md5 = argv[i];
+ }
+
+ /* sanity check */
+ if (filename == NULL || md5 == NULL) {
+ egg_warning ("filename %s and md5 %s)", filename, md5);
+ goto out;
+ }
+
+ /* get md5 */
+ md5_calc = pk_transaction_extra_get_filename_md5 (filename);
+ if (md5_calc == NULL) {
+ egg_debug ("remove of %s as no longer found", filename);
+ pk_transaction_extra_sqlite_remove_filename (post, filename);
+ goto out;
+ }
+
+ /* we've checked the file */
+ g_hash_table_insert (post->priv->hash, g_strdup (filename), GUINT_TO_POINTER (1));
+
+ /* check md5 is same */
+ if (g_strcmp0 (md5, md5_calc) != 0) {
+ egg_debug ("add of %s as md5 invalid (%s vs %s)", filename, md5, md5_calc);
+ pk_transaction_extra_sqlite_add_filename (post, filename, md5_calc);
+ }
+
+ egg_debug ("existing filename %s valid, md5=%s", filename, md5);
+out:
+ g_free (md5_calc);
+ return 0;
+}
+
+/**
+ * pk_transaction_extra_import_desktop_files:
+ **/
+gboolean
+pk_transaction_extra_import_desktop_files (PkTransactionExtra *post)
+{
+ gchar *statement;
+ gchar *error_msg = NULL;
+ gint rc;
+ GError *error = NULL;
+ GDir *dir;
+ const gchar *filename;
+ gpointer data;
+ gchar *path;
+ GPtrArray *array;
+ gfloat step;
+ guint i;
+
+ g_return_val_if_fail (PK_IS_POST_TRANS (post), FALSE);
+ g_return_val_if_fail (post->priv->db != NULL, FALSE);
+
+ if (post->priv->backend->desc->search_file == NULL) {
+ egg_debug ("cannot search files");
+ return FALSE;
+ }
+
+ /* use a local backend instance */
+ pk_backend_reset (post->priv->backend);
+ pk_transaction_extra_set_status_changed (post, PK_STATUS_ENUM_SCAN_APPLICATIONS);
+
+ /* reset hash */
+ g_hash_table_remove_all (post->priv->hash);
+ pk_transaction_extra_set_progress_changed (post, 101);
+
+ /* first go through the existing data, and look for modifications and removals */
+ statement = g_strdup ("SELECT filename, md5 FROM cache");
+ rc = sqlite3_exec (post->priv->db, statement, pk_transaction_extra_sqlite_cache_rescan_cb, post, &error_msg);
+ g_free (statement);
+ if (rc != SQLITE_OK) {
+ egg_warning ("SQL error: %s\n", error_msg);
+ sqlite3_free (error_msg);
+ }
+
+ /* open directory */
+ dir = g_dir_open (PK_DESKTOP_DEFAULT_APPLICATION_DIR, 0, &error);
+ if (dir == NULL) {
+ egg_warning ("failed to open file %s: %s", PK_DESKTOP_DEFAULT_APPLICATION_DIR, error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* go through desktop files and add them to an array if not present */
+ filename = g_dir_read_name (dir);
+ array = g_ptr_array_new ();
+ while (filename != NULL) {
+ if (g_str_has_suffix (filename, ".desktop")) {
+ path = g_build_filename (PK_DESKTOP_DEFAULT_APPLICATION_DIR, filename, NULL);
+ data = g_hash_table_lookup (post->priv->hash, path);
+ if (data == NULL) {
+ egg_debug ("add of %s as not present in db", path);
+ g_ptr_array_add (array, g_strdup (path));
+ }
+ g_free (path);
+ }
+ filename = g_dir_read_name (dir);
+ }
+ g_dir_close (dir);
+
+ step = 100.0f / array->len;
+ pk_transaction_extra_set_status_changed (post, PK_STATUS_ENUM_GENERATE_PACKAGE_LIST);
+
+ /* process files in an array */
+ for (i=0; i<array->len; i++) {
+ pk_transaction_extra_set_progress_changed (post, i * step);
+ path = g_ptr_array_index (array, i);
+ pk_transaction_extra_sqlite_add_filename (post, path, NULL);
+ }
+ g_ptr_array_foreach (array, (GFunc) g_free, NULL);
+ g_ptr_array_free (array, TRUE);
+
+out:
+ pk_transaction_extra_set_progress_changed (post, 100);
+ pk_transaction_extra_set_status_changed (post, PK_STATUS_ENUM_FINISHED);
+ return TRUE;
+}
+
+/**
+ * pk_transaction_extra_update_package_list:
+ **/
+gboolean
+pk_transaction_extra_update_package_list (PkTransactionExtra *post)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (PK_IS_POST_TRANS (post), FALSE);
+
+ if (post->priv->backend->desc->get_packages == NULL) {
+ egg_debug ("cannot get packages");
+ return FALSE;
+ }
+
+ egg_debug ("updating package lists");
+
+ /* clear old list */
+ pk_obj_list_clear (PK_OBJ_LIST(post->priv->list));
+
+ /* update UI */
+ pk_transaction_extra_set_status_changed (post, PK_STATUS_ENUM_GENERATE_PACKAGE_LIST);
+ pk_transaction_extra_set_progress_changed (post, 101);
+
+ /* get the new package list */
+ pk_backend_reset (post->priv->backend);
+ pk_store_set_uint (pk_backend_get_store (post->priv->backend), "filters", pk_bitfield_value (PK_FILTER_ENUM_NONE));
+ post->priv->backend->desc->get_packages (post->priv->backend, PK_FILTER_ENUM_NONE);
+
+ /* wait for finished */
+ g_main_loop_run (post->priv->loop);
+
+ /* update UI */
+ pk_transaction_extra_set_progress_changed (post, 90);
+
+ /* convert to a file */
+ ret = pk_obj_list_to_file (PK_OBJ_LIST(post->priv->list), PK_SYSTEM_PACKAGE_LIST_FILENAME);
+ if (!ret)
+ egg_warning ("failed to save to file");
+
+ /* update UI */
+ pk_transaction_extra_set_progress_changed (post, 100);
+ pk_transaction_extra_set_status_changed (post, PK_STATUS_ENUM_FINISHED);
+
+ return ret;
+}
+
+/**
+ * pk_transaction_extra_clear_firmware_requests:
+ **/
+gboolean
+pk_transaction_extra_clear_firmware_requests (PkTransactionExtra *post)
+{
+ gboolean ret;
+ gchar *filename;
+
+ g_return_val_if_fail (PK_IS_POST_TRANS (post), FALSE);
+
+ /* clear the firmware requests directory */
+ filename = g_build_filename (LOCALSTATEDIR, "run", "PackageKit", "udev", NULL);
+ egg_debug ("clearing udev firmware requests at %s", filename);
+ ret = pk_directory_remove_contents (filename);
+ if (!ret)
+ egg_warning ("failed to clear %s", filename);
+ g_free (filename);
+ return ret;
+}
+
+
+/**
+ * pk_transaction_extra_update_files_check_running_cb:
+ **/
+static void
+pk_transaction_extra_update_files_check_running_cb (PkBackend *backend, const gchar *package_id,
+ const gchar *filelist, PkTransactionExtra *post)
+{
+ guint i;
+ guint len;
+ gboolean ret;
+ gchar **files;
+ PkPackageId *id;
+
+ id = pk_package_id_new_from_string (package_id);
+ files = g_strsplit (filelist, ";", 0);
+
+ /* check each file */
+ len = g_strv_length (files);
+ for (i=0; i<len; i++) {
+ /* executable? */
+ ret = g_file_test (files[i], G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_EXECUTABLE | G_FILE_TEST_EXISTS);
+ if (!ret)
+ continue;
+
+ /* running? */
+ ret = pk_obj_list_exists (PK_OBJ_LIST(post->priv->running_exec_list), files[i]);
+ if (!ret)
+ continue;
+
+ /* TODO: findout if the executable has a desktop file, and if so,
+ * suggest an application restart instead */
+
+ /* send signal about session restart */
+ egg_debug ("package %s updated, and %s is running", id->name, files[i]);
+ pk_backend_require_restart (post->priv->backend, PK_RESTART_ENUM_SESSION, package_id);
+ }
+ g_strfreev (files);
+ pk_package_id_free (id);
+}
+
+#ifdef USE_SECURITY_POLKIT
+/**
+ * dkp_post_trans_get_cmdline:
+ **/
+static gchar *
+dkp_post_trans_get_cmdline (guint pid)
+{
+ gboolean ret;
+ gchar *filename = NULL;
+ gchar *cmdline = NULL;
+ GError *error = NULL;
+
+ /* get command line from proc */
+ filename = g_strdup_printf ("/proc/%i/cmdline", pid);
+ ret = g_file_get_contents (filename, &cmdline, NULL, &error);
+ if (!ret) {
+ egg_debug ("failed to get cmdline: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+out:
+ g_free (filename);
+ return cmdline;
+}
+#endif
+
+/**
+ * pk_transaction_extra_update_process_list:
+ **/
+static gboolean
+pk_transaction_extra_update_process_list (PkTransactionExtra *post)
+{
+ GDir *dir;
+ const gchar *name;
+ gchar *offset;
+ gchar *uid_file;
+ gchar *contents;
+ gboolean ret;
+ guint uid;
+ pid_t pid;
+ gchar *exec;
+
+ uid = getuid ();
+ dir = g_dir_open ("/proc", 0, NULL);
+ name = g_dir_read_name (dir);
+ pk_obj_list_clear (PK_OBJ_LIST(post->priv->running_exec_list));
+ while (name != NULL) {
+ contents = NULL;
+ uid_file = g_build_filename ("/proc", name, "loginuid", NULL);
+
+ /* is a process file */
+ if (!g_file_test (uid_file, G_FILE_TEST_EXISTS))
+ goto out;
+
+ /* able to get contents */
+ ret = g_file_get_contents (uid_file, &contents, 0, NULL);
+ if (!ret)
+ goto out;
+
+ /* is run by our UID */
+ uid = atoi (contents);
+
+ /* get the exec for the pid */
+ pid = atoi (name);
+#ifdef USE_SECURITY_POLKIT
+ exec = dkp_post_trans_get_cmdline (pid);
+ if (exec == NULL)
+ goto out;
+#else
+ goto out;
+#endif
+
+ /* can be /usr/libexec/notification-daemon.#prelink#.9sOhao */
+ offset = g_strrstr (exec, ".#prelink#.");
+ if (offset != NULL)
+ *(offset) = '\0';
+ egg_debug ("uid=%i, pid=%i, exec=%s", uid, pid, exec);
+ pk_obj_list_add (PK_OBJ_LIST(post->priv->running_exec_list), exec);
+out:
+ g_free (uid_file);
+ g_free (contents);
+ name = g_dir_read_name (dir);
+ }
+ g_dir_close (dir);
+ return TRUE;
+}
+
+/**
+ * pk_transaction_extra_check_running_process:
+ **/
+gboolean
+pk_transaction_extra_check_running_process (PkTransactionExtra *post, gchar **package_ids)
+{
+ PkStore *store;
+ guint signal_files;
+
+ g_return_val_if_fail (PK_IS_POST_TRANS (post), FALSE);
+
+ if (post->priv->backend->desc->get_files == NULL) {
+ egg_debug ("cannot get files");
+ return FALSE;
+ }
+
+ pk_transaction_extra_set_status_changed (post, PK_STATUS_ENUM_SCAN_APPLICATIONS);
+ pk_transaction_extra_set_progress_changed (post, 101);
+
+ store = pk_backend_get_store (post->priv->backend);
+ pk_transaction_extra_update_process_list (post);
+
+ signal_files = g_signal_connect (post->priv->backend, "files",
+ G_CALLBACK (pk_transaction_extra_update_files_check_running_cb), post);
+
+ /* get all the files touched in the packages we just updated */
+ pk_backend_reset (post->priv->backend);
+ pk_store_set_strv (store, "package_ids", package_ids);
+ post->priv->backend->desc->get_files (post->priv->backend, package_ids);
+
+ /* wait for finished */
+ g_main_loop_run (post->priv->loop);
+
+ g_signal_handler_disconnect (post->priv->backend, signal_files);
+ pk_transaction_extra_set_progress_changed (post, 100);
+ return TRUE;
+}
+
+/**
+ * pk_transaction_extra_update_files_check_desktop_cb:
+ **/
+static void
+pk_transaction_extra_update_files_check_desktop_cb (PkBackend *backend, const gchar *package_id,
+ const gchar *filelist, PkTransactionExtra *post)
+{
+ guint i;
+ guint len;
+ gboolean ret;
+ gchar **files;
+ gchar **package;
+ PkPackageId *id;
+ gchar *md5;
+
+ id = pk_package_id_new_from_string (package_id);
+ files = g_strsplit (filelist, ";", 0);
+ package = g_strsplit (package_id, ";", 0);
+
+ /* check each file */
+ len = g_strv_length (files);
+ for (i=0; i<len; i++) {
+ /* exists? */
+ ret = g_file_test (files[i], G_FILE_TEST_EXISTS);
+ if (!ret)
+ continue;
+
+ /* .desktop file? */
+ ret = g_str_has_suffix (files[i], ".desktop");
+ if (!ret)
+ continue;
+
+ egg_debug ("adding filename %s", files[i]);
+ md5 = pk_transaction_extra_get_filename_md5 (files[i]);
+ pk_transaction_extra_sqlite_add_filename_details (post, files[i], package[0], md5);
+ g_free (md5);
+ }
+ g_strfreev (files);
+ g_strfreev (package);
+ pk_package_id_free (id);
+}
+
+/**
+ * pk_transaction_extra_check_desktop_files:
+ **/
+gboolean
+pk_transaction_extra_check_desktop_files (PkTransactionExtra *post, gchar **package_ids)
+{
+ PkStore *store;
+ guint signal_files;
+
+ g_return_val_if_fail (PK_IS_POST_TRANS (post), FALSE);
+
+ if (post->priv->backend->desc->get_files == NULL) {
+ egg_debug ("cannot get files");
+ return FALSE;
+ }
+
+ pk_transaction_extra_set_status_changed (post, PK_STATUS_ENUM_SCAN_APPLICATIONS);
+ pk_transaction_extra_set_progress_changed (post, 101);
+
+ store = pk_backend_get_store (post->priv->backend);
+ signal_files = g_signal_connect (post->priv->backend, "files",
+ G_CALLBACK (pk_transaction_extra_update_files_check_desktop_cb), post);
+
+ /* get all the files touched in the packages we just updated */
+ pk_backend_reset (post->priv->backend);
+ pk_store_set_strv (store, "package_ids", package_ids);
+ post->priv->backend->desc->get_files (post->priv->backend, package_ids);
+
+ /* wait for finished */
+ g_main_loop_run (post->priv->loop);
+
+ g_signal_handler_disconnect (post->priv->backend, signal_files);
+ pk_transaction_extra_set_progress_changed (post, 100);
+ return TRUE;
+}
+
+/**
+ * pk_transaction_extra_files_check_library_restart_cb:
+ **/
+static void
+pk_transaction_extra_files_check_library_restart_cb (PkBackend *backend, const gchar *package_id,
+ const gchar *filelist, PkTransactionExtra *post)
+{
+ guint i;
+ guint len;
+ gchar **files = NULL;
+
+ files = g_strsplit (filelist, ";", 0);
+
+ /* check each file to see if it's a system shared library */
+ len = g_strv_length (files);
+ for (i=0; i<len; i++) {
+ /* not a system library */
+ if (strstr (files[i], "/lib/") == NULL)
+ continue;
+
+ /* not a shared object */
+ if (strstr (files[i], ".so") == NULL)
+ continue;
+
+ /* add as it matches the criteria */
+ egg_debug ("adding filename %s", files[i]);
+ g_ptr_array_add (post->priv->files_list, g_strdup (files[i]));
+ }
+}
+
+/**
+ * pk_transaction_extra_get_cmdline:
+ **/
+static gchar *
+pk_transaction_extra_get_cmdline (PkTransactionExtra *post, guint pid)
+{
+ gboolean ret;
+ gchar *filename = NULL;
+ gchar *cmdline = NULL;
+ GError *error = NULL;
+
+ /* get command line from proc */
+ filename = g_strdup_printf ("/proc/%i/cmdline", pid);
+ ret = g_file_get_contents (filename, &cmdline, NULL, &error);
+ if (!ret) {
+ egg_warning ("failed to get cmdline: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+out:
+ g_free (filename);
+ return cmdline;
+}
+
+/**
+ * pk_transaction_extra_get_uid:
+ **/
+static gint
+pk_transaction_extra_get_uid (PkTransactionExtra *post, guint pid)
+{
+ gboolean ret;
+ gint uid = -1;
+ gchar *filename = NULL;
+ gchar *uid_text = NULL;
+ GError *error = NULL;
+
+ /* get command line from proc */
+ filename = g_strdup_printf ("/proc/%i/loginuid", pid);
+ ret = g_file_get_contents (filename, &uid_text, NULL, &error);
+ if (!ret) {
+ egg_warning ("failed to get cmdline: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* convert from text */
+ uid = atoi (uid_text);
+out:
+ g_free (filename);
+ g_free (uid_text);
+ return uid;
+}
+
+/**
+ * pk_transaction_extra_check_library_restart_emit:
+ **/
+static gboolean
+pk_transaction_extra_check_library_restart_emit (PkTransactionExtra *post, GPtrArray *pids)
+{
+ gint uid;
+ guint i;
+ guint pid;
+ gchar *filename;
+ gchar *cmdline;
+ gchar *cmdline_full;
+ gchar *package_id;
+ GPtrArray *files_session;
+ GPtrArray *files_system;
+ const PkPackageObj *obj;
+
+ /* create arrays */
+ files_session = g_ptr_array_new ();
+ files_system = g_ptr_array_new ();
+
+ /* find the package name of each pid */
+ for (i=0; i<pids->len; i++) {
+ pid = GPOINTER_TO_INT (g_ptr_array_index (pids, i));
+
+ /* get user */
+ uid = pk_transaction_extra_get_uid (post, pid);
+ if (uid < 0)
+ continue;
+
+ /* get command line */
+ cmdline = pk_transaction_extra_get_cmdline (post, pid);
+ if (cmdline == NULL)
+ continue;
+
+ /* prepend path if it does not already exist */
+ if (cmdline[0] == '/')
+ cmdline_full = g_strdup (cmdline);
+ else
+ cmdline_full = g_strdup_printf ("/usr/bin/%s", cmdline);
+
+ egg_warning ("pid=%i: %s (%i)", pid, cmdline_full, uid);
+ if (uid < 500)
+ g_ptr_array_add (files_system, cmdline_full);
+ else
+ g_ptr_array_add (files_session, cmdline_full);
+ g_free (cmdline);
+ }
+
+ /* we found nothing */
+ if (files_system->len == 0 && files_session->len == 0) {
+ egg_warning ("no pids could be resolved");
+ goto out;
+ }
+
+ /* process all session restarts */
+ for (i=0; i<files_session->len; i++) {
+ filename = g_ptr_array_index (files_session, i);
+
+ obj = pk_transaction_extra_get_installed_package_for_file (post, filename);
+ if (obj == NULL) {
+ egg_warning ("failed to find package for %s", filename);
+ continue;
+ }
+
+ package_id = pk_package_id_to_string (obj->id);
+ pk_transaction_extra_set_require_restart (post, PK_RESTART_ENUM_SECURITY_SESSION, package_id);
+ g_free (package_id);
+ }
+
+ /* process all system restarts */
+ for (i=0; i<files_system->len; i++) {
+ filename = g_ptr_array_index (files_system, i);
+
+ obj = pk_transaction_extra_get_installed_package_for_file (post, filename);
+ if (obj == NULL) {
+ egg_warning ("failed to find package for %s", filename);
+ continue;
+ }
+
+ package_id = pk_package_id_to_string (obj->id);
+ pk_transaction_extra_set_require_restart (post, PK_RESTART_ENUM_SECURITY_SYSTEM, package_id);
+ g_free (package_id);
+ }
+
+out:
+ g_ptr_array_foreach (files_session, (GFunc) g_free, NULL);
+ g_ptr_array_foreach (files_system, (GFunc) g_free, NULL);
+ g_ptr_array_free (files_session, TRUE);
+ g_ptr_array_free (files_system, TRUE);
+ return TRUE;
+}
+
+/**
+ * pk_transaction_extra_check_library_restart:
+ **/
+gboolean
+pk_transaction_extra_check_library_restart (PkTransactionExtra *post, gchar **package_ids)
+{
+ PkStore *store;
+ guint signal_files;
+ gboolean ret = TRUE;
+ gchar **files = NULL;
+ GPtrArray *pids;
+
+ g_return_val_if_fail (PK_IS_POST_TRANS (post), FALSE);
+
+ if (post->priv->backend->desc->get_files == NULL) {
+ egg_debug ("cannot get files");
+ return FALSE;
+ }
+
+ /* reset */
+ g_ptr_array_foreach (post->priv->files_list, (GFunc) g_free, NULL);
+ g_ptr_array_set_size (post->priv->files_list, 0);
+
+ /* get list from lsof */
+ ret = pk_lsof_refresh (post->priv->lsof);
+ if (!ret) {
+ egg_warning ("failed to refresh");
+ goto out;
+ }
+
+ pk_transaction_extra_set_status_changed (post, PK_STATUS_ENUM_SCAN_APPLICATIONS);
+ pk_transaction_extra_set_progress_changed (post, 101);
+
+ store = pk_backend_get_store (post->priv->backend);
+ signal_files = g_signal_connect (post->priv->backend, "files",
+ G_CALLBACK (pk_transaction_extra_files_check_library_restart_cb), post);
+
+ /* get all the files touched in the packages we just updated */
+ pk_backend_reset (post->priv->backend);
+ pk_store_set_strv (store, "package_ids", package_ids);
+ post->priv->backend->desc->get_files (post->priv->backend, package_ids);
+
+ /* wait for finished */
+ g_main_loop_run (post->priv->loop);
+
+ /* nothing to do */
+ if (post->priv->files_list->len == 0) {
+ egg_warning ("no files");
+ goto out;
+ }
+
+ /* get the list of PIDs */
+ files = pk_ptr_array_to_strv (post->priv->files_list);
+ pids = pk_lsof_get_pids_for_filenames (post->priv->lsof, files);
+
+ /* nothing depends on these libraries */
+ if (pids == NULL) {
+ egg_warning ("failed to get process list");
+ goto out;
+ }
+
+ /* nothing depends on these libraries */
+ if (pids->len == 0) {
+ egg_warning ("no processes depend on these libraries");
+ goto out;
+ }
+
+ /* emit */
+ pk_transaction_extra_check_library_restart_emit (post, pids);
+ g_ptr_array_free (pids, TRUE);
+
+ g_signal_handler_disconnect (post->priv->backend, signal_files);
+ pk_transaction_extra_set_progress_changed (post, 100);
+out:
+ g_strfreev (files);
+ return ret;
+}
+
+/**
+ * pk_transaction_extra_finalize:
+ **/
+static void
+pk_transaction_extra_finalize (GObject *object)
+{
+ PkTransactionExtra *post;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (PK_IS_POST_TRANS (object));
+ post = PK_POST_TRANS (object);
+
+ g_signal_handler_disconnect (post->priv->backend, post->priv->finished_id);
+ g_signal_handler_disconnect (post->priv->backend, post->priv->package_id);
+
+ if (g_main_loop_is_running (post->priv->loop))
+ g_main_loop_quit (post->priv->loop);
+ g_main_loop_unref (post->priv->loop);
+ sqlite3_close (post->priv->db);
+ g_hash_table_unref (post->priv->hash);
+ g_ptr_array_foreach (post->priv->files_list, (GFunc) g_free, NULL);
+ g_ptr_array_free (post->priv->files_list, TRUE);
+
+ g_object_unref (post->priv->backend);
+ g_object_unref (post->priv->lsof);
+ g_object_unref (post->priv->list);
+ g_object_unref (post->priv->running_exec_list);
+
+ G_OBJECT_CLASS (pk_transaction_extra_parent_class)->finalize (object);
+}
+
+/**
+ * pk_transaction_extra_class_init:
+ **/
+static void
+pk_transaction_extra_class_init (PkTransactionExtraClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = pk_transaction_extra_finalize;
+ signals [PK_POST_TRANS_STATUS_CHANGED] =
+ g_signal_new ("status-changed",
+ G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE, 1, G_TYPE_UINT);
+ signals [PK_POST_TRANS_PROGRESS_CHANGED] =
+ g_signal_new ("progress-changed",
+ G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, pk_marshal_VOID__UINT_UINT_UINT_UINT,
+ G_TYPE_NONE, 4, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
+ signals [PK_POST_TRANS_REQUIRE_RESTART] =
+ g_signal_new ("require-restart",
+ G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, pk_marshal_VOID__UINT_STRING,
+ G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
+ g_type_class_add_private (klass, sizeof (PkTransactionExtraPrivate));
+}
+
+/**
+ * pk_transaction_extra_init:
+ *
+ * initializes the post_trans class. NOTE: We expect post_trans objects
+ * to *NOT* be removed or added during the session.
+ * We only control the first post_trans object if there are more than one.
+ **/
+static void
+pk_transaction_extra_init (PkTransactionExtra *post)
+{
+ gboolean ret;
+ const gchar *statement;
+ gchar *error_msg = NULL;
+ gint rc;
+
+ post->priv = PK_POST_TRANS_GET_PRIVATE (post);
+ post->priv->running_exec_list = pk_transaction_extra_string_list_new ();
+ post->priv->loop = g_main_loop_new (NULL, FALSE);
+ post->priv->list = pk_package_list_new ();
+ post->priv->backend = pk_backend_new ();
+ post->priv->lsof = pk_lsof_new ();
+ post->priv->db = NULL;
+ post->priv->hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ post->priv->files_list = g_ptr_array_new ();
+
+ post->priv->finished_id =
+ g_signal_connect (post->priv->backend, "finished",
+ G_CALLBACK (pk_transaction_extra_finished_cb), post);
+ post->priv->package_id =
+ g_signal_connect (post->priv->backend, "package",
+ G_CALLBACK (pk_transaction_extra_package_cb), post);
+
+ /* check if exists */
+ ret = g_file_test (PK_DESKTOP_DEFAULT_DATABASE, G_FILE_TEST_EXISTS);
+
+ egg_debug ("trying to open database '%s'", PK_DESKTOP_DEFAULT_DATABASE);
+ rc = sqlite3_open (PK_DESKTOP_DEFAULT_DATABASE, &post->priv->db);
+ if (rc != 0) {
+ egg_warning ("Can't open database: %s\n", sqlite3_errmsg (post->priv->db));
+ sqlite3_close (post->priv->db);
+ post->priv->db = NULL;
+ return;
+ }
+
+ /* create if not exists */
+ if (!ret) {
+ egg_debug ("creating database cache in %s", PK_DESKTOP_DEFAULT_DATABASE);
+ statement = "CREATE TABLE cache ("
+ "filename TEXT,"
+ "package TEXT,"
+ "show INTEGER,"
+ "md5 TEXT);";
+ rc = sqlite3_exec (post->priv->db, statement, NULL, NULL, &error_msg);
+ if (rc != SQLITE_OK) {
+ egg_warning ("SQL error: %s\n", error_msg);
+ sqlite3_free (error_msg);
+ }
+ }
+
+ /* we don't need to keep syncing */
+ sqlite3_exec (post->priv->db, "PRAGMA synchronous=OFF", NULL, NULL, NULL);
+}
+
+/**
+ * pk_transaction_extra_new:
+ * Return value: A new post_trans class instance.
+ **/
+PkTransactionExtra *
+pk_transaction_extra_new (void)
+{
+ PkTransactionExtra *post;
+ post = g_object_new (PK_TYPE_POST_TRANS, NULL);
+ return PK_POST_TRANS (post);
+}
+
+/***************************************************************************
+ *** MAKE CHECK TESTS ***
+ ***************************************************************************/
+#ifdef EGG_TEST
+#include "egg-test.h"
+
+void
+egg_test_post_trans (EggTest *test)
+{
+ PkTransactionExtra *post;
+
+ if (!egg_test_start (test, "PkTransactionExtra"))
+ return;
+
+ /************************************************************/
+ egg_test_title (test, "get an instance");
+ post = pk_transaction_extra_new ();
+ egg_test_assert (test, post != NULL);
+
+ g_object_unref (post);
+
+ egg_test_end (test);
+}
+#endif
+
diff --git a/src/pk-transaction-extra.h b/src/pk-transaction-extra.h
new file mode 100644
index 0000000..8a4160c
--- /dev/null
+++ b/src/pk-transaction-extra.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008-2009 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PK_POST_TRANS_H
+#define __PK_POST_TRANS_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define PK_TYPE_POST_TRANS (pk_transaction_extra_get_type ())
+#define PK_POST_TRANS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PK_TYPE_POST_TRANS, PkTransactionExtra))
+#define PK_POST_TRANS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PK_TYPE_POST_TRANS, PkTransactionExtraClass))
+#define PK_IS_POST_TRANS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PK_TYPE_POST_TRANS))
+#define PK_IS_POST_TRANS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PK_TYPE_POST_TRANS))
+#define PK_POST_TRANS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PK_TYPE_POST_TRANS, PkTransactionExtraClass))
+
+typedef struct PkTransactionExtraPrivate PkTransactionExtraPrivate;
+
+typedef struct
+{
+ GObject parent;
+ PkTransactionExtraPrivate *priv;
+} PkTransactionExtra;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} PkTransactionExtraClass;
+
+GType pk_transaction_extra_get_type (void);
+PkTransactionExtra *pk_transaction_extra_new (void);
+
+gboolean pk_transaction_extra_clear_firmware_requests (PkTransactionExtra *post);
+gboolean pk_transaction_extra_update_package_list (PkTransactionExtra *post);
+gboolean pk_transaction_extra_import_desktop_files (PkTransactionExtra *post);
+gboolean pk_transaction_extra_check_running_process (PkTransactionExtra *post,
+ gchar **package_ids);
+gboolean pk_transaction_extra_check_desktop_files (PkTransactionExtra *post,
+ gchar **package_ids);
+gboolean pk_transaction_extra_check_library_restart (PkTransactionExtra *post,
+ gchar **package_ids);
+
+G_END_DECLS
+
+#endif /* __PK_POST_TRANS_H */
+
diff --git a/src/pk-transaction.c b/src/pk-transaction.c
index b1400f2..0aa4e2a 100644
--- a/src/pk-transaction.c
+++ b/src/pk-transaction.c
@@ -61,7 +61,7 @@
#include "pk-shared.h"
#include "pk-cache.h"
#include "pk-notify.h"
-#include "pk-post-trans.h"
+#include "pk-transaction-extra.h"
#include "pk-syslog.h"
static void pk_transaction_finalize (GObject *object);
@@ -107,7 +107,7 @@ struct PkTransactionPrivate
#endif
DBusGConnection *connection;
DBusGProxy *proxy_pid;
- PkPostTrans *post_trans;
+ PkTransactionExtra *transaction_extra;
PkSyslog *syslog;
/* needed for gui coldplugging */
@@ -610,7 +610,7 @@ pk_transaction_finished_cb (PkBackend *backend, PkExitEnum exit_enum, PkTransact
/* process file lists on these packages */
if (list->len > 0) {
package_ids = pk_package_ids_from_array (list);
- pk_post_trans_check_running_process (transaction->priv->post_trans, package_ids);
+ pk_transaction_extra_check_running_process (transaction->priv->transaction_extra, package_ids);
g_strfreev (package_ids);
}
g_ptr_array_foreach (list, (GFunc) g_free, NULL);
@@ -642,7 +642,7 @@ pk_transaction_finished_cb (PkBackend *backend, PkExitEnum exit_enum, PkTransact
/* process file lists on these packages */
if (list->len > 0) {
package_ids = pk_package_ids_from_array (list);
- pk_post_trans_check_desktop_files (transaction->priv->post_trans, package_ids);
+ pk_transaction_extra_check_desktop_files (transaction->priv->transaction_extra, package_ids);
g_strfreev (package_ids);
}
g_ptr_array_foreach (list, (GFunc) g_free, NULL);
@@ -664,15 +664,15 @@ pk_transaction_finished_cb (PkBackend *backend, PkExitEnum exit_enum, PkTransact
/* generate the package list */
ret = pk_conf_get_bool (transaction->priv->conf, "UpdatePackageList");
if (ret)
- pk_post_trans_update_package_list (transaction->priv->post_trans);
+ pk_transaction_extra_update_package_list (transaction->priv->transaction_extra);
/* refresh the desktop icon cache */
ret = pk_conf_get_bool (transaction->priv->conf, "ScanDesktopFiles");
if (ret)
- pk_post_trans_import_desktop_files (transaction->priv->post_trans);
+ pk_transaction_extra_import_desktop_files (transaction->priv->transaction_extra);
/* clear the firmware requests directory */
- pk_post_trans_clear_firmware_requests (transaction->priv->post_trans);
+ pk_transaction_extra_clear_firmware_requests (transaction->priv->transaction_extra);
}
/* if we did not send this, ensure the GUI has the right state */
@@ -1111,7 +1111,7 @@ pk_transaction_pre_transaction_checks (PkTransaction *transaction)
/* find files in security updates */
package_ids = pk_package_ids_from_array (list);
- ret = pk_post_trans_check_library_restart (transaction->priv->post_trans, package_ids);
+ ret = pk_transaction_extra_check_library_restart (transaction->priv->transaction_extra, package_ids);
out:
g_strfreev (package_ids);
if (list != NULL) {
@@ -4312,12 +4312,12 @@ pk_transaction_init (PkTransaction *transaction)
transaction->priv->cancellable = g_cancellable_new ();
#endif
- transaction->priv->post_trans = pk_post_trans_new ();
- g_signal_connect (transaction->priv->post_trans, "status-changed",
+ transaction->priv->transaction_extra = pk_transaction_extra_new ();
+ g_signal_connect (transaction->priv->transaction_extra, "status-changed",
G_CALLBACK (pk_transaction_status_changed_cb), transaction);
- g_signal_connect (transaction->priv->post_trans, "progress-changed",
+ g_signal_connect (transaction->priv->transaction_extra, "progress-changed",
G_CALLBACK (pk_transaction_progress_changed_cb), transaction);
- g_signal_connect (transaction->priv->post_trans, "require-restart",
+ g_signal_connect (transaction->priv->transaction_extra, "require-restart",
G_CALLBACK (pk_transaction_require_restart_cb), transaction);
transaction->priv->transaction_db = pk_transaction_db_new ();
@@ -4418,7 +4418,7 @@ pk_transaction_finalize (GObject *object)
g_object_unref (transaction->priv->proxy_pid);
g_object_unref (transaction->priv->notify);
g_object_unref (transaction->priv->syslog);
- g_object_unref (transaction->priv->post_trans);
+ g_object_unref (transaction->priv->transaction_extra);
#ifdef USE_SECURITY_POLKIT
// g_object_unref (transaction->priv->authority);
g_object_unref (transaction->priv->cancellable);
commit 79b00617cf9808a1b61448354403d325820e6ea3
Author: Richard Hughes <richard at hughsie.com>
Date: Sat Jul 11 17:02:50 2009 +0100
Add functionality to detect when shared libraries are being used that are updated in a security update
diff --git a/src/pk-post-trans.c b/src/pk-post-trans.c
index 52556a5..3021ff1 100644
--- a/src/pk-post-trans.c
+++ b/src/pk-post-trans.c
@@ -38,6 +38,7 @@
#include "pk-shared.h"
#include "pk-marshal.h"
#include "pk-backend-internal.h"
+#include "pk-lsof.h"
#define PK_POST_TRANS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PK_TYPE_POST_TRANS, PkPostTransPrivate))
@@ -48,14 +49,17 @@ struct PkPostTransPrivate
GMainLoop *loop;
PkObjList *running_exec_list;
PkPackageList *list;
+ PkLsof *lsof;
guint finished_id;
guint package_id;
GHashTable *hash;
+ GPtrArray *files_list;
};
enum {
PK_POST_TRANS_STATUS_CHANGED,
PK_POST_TRANS_PROGRESS_CHANGED,
+ PK_POST_TRANS_REQUIRE_RESTART,
PK_POST_TRANS_LAST_SIGNAL
};
@@ -82,6 +86,16 @@ pk_post_trans_package_cb (PkBackend *backend, const PkPackageObj *obj, PkPostTra
}
/**
+ * pk_post_trans_set_require_restart:
+ **/
+static void
+pk_post_trans_set_require_restart (PkPostTrans *post, PkRestartEnum restart, const gchar *package_id)
+{
+ egg_debug ("emit require-restart %s, %s", pk_restart_enum_to_text (restart), package_id);
+ g_signal_emit (post, signals [PK_POST_TRANS_REQUIRE_RESTART], 0, restart, package_id);
+}
+
+/**
* pk_post_trans_set_status_changed:
**/
static void
@@ -737,6 +751,260 @@ pk_post_trans_check_desktop_files (PkPostTrans *post, gchar **package_ids)
}
/**
+ * pk_post_trans_files_check_library_restart_cb:
+ **/
+static void
+pk_post_trans_files_check_library_restart_cb (PkBackend *backend, const gchar *package_id,
+ const gchar *filelist, PkPostTrans *post)
+{
+ guint i;
+ guint len;
+ gchar **files = NULL;
+
+ files = g_strsplit (filelist, ";", 0);
+
+ /* check each file to see if it's a system shared library */
+ len = g_strv_length (files);
+ for (i=0; i<len; i++) {
+ /* not a system library */
+ if (strstr (files[i], "/lib/") == NULL)
+ continue;
+
+ /* not a shared object */
+ if (strstr (files[i], ".so") == NULL)
+ continue;
+
+ /* add as it matches the criteria */
+ egg_debug ("adding filename %s", files[i]);
+ g_ptr_array_add (post->priv->files_list, g_strdup (files[i]));
+ }
+}
+
+/**
+ * pk_post_trans_get_cmdline:
+ **/
+static gchar *
+pk_post_trans_get_cmdline (PkPostTrans *post, guint pid)
+{
+ gboolean ret;
+ gchar *filename = NULL;
+ gchar *cmdline = NULL;
+ GError *error = NULL;
+
+ /* get command line from proc */
+ filename = g_strdup_printf ("/proc/%i/cmdline", pid);
+ ret = g_file_get_contents (filename, &cmdline, NULL, &error);
+ if (!ret) {
+ egg_warning ("failed to get cmdline: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+out:
+ g_free (filename);
+ return cmdline;
+}
+
+/**
+ * pk_post_trans_get_uid:
+ **/
+static gint
+pk_post_trans_get_uid (PkPostTrans *post, guint pid)
+{
+ gboolean ret;
+ gint uid = -1;
+ gchar *filename = NULL;
+ gchar *uid_text = NULL;
+ GError *error = NULL;
+
+ /* get command line from proc */
+ filename = g_strdup_printf ("/proc/%i/loginuid", pid);
+ ret = g_file_get_contents (filename, &uid_text, NULL, &error);
+ if (!ret) {
+ egg_warning ("failed to get cmdline: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* convert from text */
+ uid = atoi (uid_text);
+out:
+ g_free (filename);
+ g_free (uid_text);
+ return uid;
+}
+
+/**
+ * pk_post_trans_check_library_restart_emit:
+ **/
+static gboolean
+pk_post_trans_check_library_restart_emit (PkPostTrans *post, GPtrArray *pids)
+{
+ gint uid;
+ guint i;
+ guint pid;
+ gchar *filename;
+ gchar *cmdline;
+ gchar *cmdline_full;
+ gchar *package_id;
+ GPtrArray *files_session;
+ GPtrArray *files_system;
+ const PkPackageObj *obj;
+
+ /* create arrays */
+ files_session = g_ptr_array_new ();
+ files_system = g_ptr_array_new ();
+
+ /* find the package name of each pid */
+ for (i=0; i<pids->len; i++) {
+ pid = GPOINTER_TO_INT (g_ptr_array_index (pids, i));
+
+ /* get user */
+ uid = pk_post_trans_get_uid (post, pid);
+ if (uid < 0)
+ continue;
+
+ /* get command line */
+ cmdline = pk_post_trans_get_cmdline (post, pid);
+ if (cmdline == NULL)
+ continue;
+
+ /* prepend path if it does not already exist */
+ if (cmdline[0] == '/')
+ cmdline_full = g_strdup (cmdline);
+ else
+ cmdline_full = g_strdup_printf ("/usr/bin/%s", cmdline);
+
+ egg_warning ("pid=%i: %s (%i)", pid, cmdline_full, uid);
+ if (uid < 500)
+ g_ptr_array_add (files_system, cmdline_full);
+ else
+ g_ptr_array_add (files_session, cmdline_full);
+ g_free (cmdline);
+ }
+
+ /* we found nothing */
+ if (files_system->len == 0 && files_session->len == 0) {
+ egg_warning ("no pids could be resolved");
+ goto out;
+ }
+
+ /* process all session restarts */
+ for (i=0; i<files_session->len; i++) {
+ filename = g_ptr_array_index (files_session, i);
+
+ obj = pk_post_trans_get_installed_package_for_file (post, filename);
+ if (obj == NULL) {
+ egg_warning ("failed to find package for %s", filename);
+ continue;
+ }
+
+ package_id = pk_package_id_to_string (obj->id);
+ pk_post_trans_set_require_restart (post, PK_RESTART_ENUM_SECURITY_SESSION, package_id);
+ g_free (package_id);
+ }
+
+ /* process all system restarts */
+ for (i=0; i<files_system->len; i++) {
+ filename = g_ptr_array_index (files_system, i);
+
+ obj = pk_post_trans_get_installed_package_for_file (post, filename);
+ if (obj == NULL) {
+ egg_warning ("failed to find package for %s", filename);
+ continue;
+ }
+
+ package_id = pk_package_id_to_string (obj->id);
+ pk_post_trans_set_require_restart (post, PK_RESTART_ENUM_SECURITY_SYSTEM, package_id);
+ g_free (package_id);
+ }
+
+out:
+ g_ptr_array_foreach (files_session, (GFunc) g_free, NULL);
+ g_ptr_array_foreach (files_system, (GFunc) g_free, NULL);
+ g_ptr_array_free (files_session, TRUE);
+ g_ptr_array_free (files_system, TRUE);
+ return TRUE;
+}
+
+/**
+ * pk_post_trans_check_library_restart:
+ **/
+gboolean
+pk_post_trans_check_library_restart (PkPostTrans *post, gchar **package_ids)
+{
+ PkStore *store;
+ guint signal_files;
+ gboolean ret = TRUE;
+ gchar **files = NULL;
+ GPtrArray *pids;
+
+ g_return_val_if_fail (PK_IS_POST_TRANS (post), FALSE);
+
+ if (post->priv->backend->desc->get_files == NULL) {
+ egg_debug ("cannot get files");
+ return FALSE;
+ }
+
+ /* reset */
+ g_ptr_array_foreach (post->priv->files_list, (GFunc) g_free, NULL);
+ g_ptr_array_set_size (post->priv->files_list, 0);
+
+ /* get list from lsof */
+ ret = pk_lsof_refresh (post->priv->lsof);
+ if (!ret) {
+ egg_warning ("failed to refresh");
+ goto out;
+ }
+
+ pk_post_trans_set_status_changed (post, PK_STATUS_ENUM_SCAN_APPLICATIONS);
+ pk_post_trans_set_progress_changed (post, 101);
+
+ store = pk_backend_get_store (post->priv->backend);
+ signal_files = g_signal_connect (post->priv->backend, "files",
+ G_CALLBACK (pk_post_trans_files_check_library_restart_cb), post);
+
+ /* get all the files touched in the packages we just updated */
+ pk_backend_reset (post->priv->backend);
+ pk_store_set_strv (store, "package_ids", package_ids);
+ post->priv->backend->desc->get_files (post->priv->backend, package_ids);
+
+ /* wait for finished */
+ g_main_loop_run (post->priv->loop);
+
+ /* nothing to do */
+ if (post->priv->files_list->len == 0) {
+ egg_warning ("no files");
+ goto out;
+ }
+
+ /* get the list of PIDs */
+ files = pk_ptr_array_to_strv (post->priv->files_list);
+ pids = pk_lsof_get_pids_for_filenames (post->priv->lsof, files);
+
+ /* nothing depends on these libraries */
+ if (pids == NULL) {
+ egg_warning ("failed to get process list");
+ goto out;
+ }
+
+ /* nothing depends on these libraries */
+ if (pids->len == 0) {
+ egg_warning ("no processes depend on these libraries");
+ goto out;
+ }
+
+ /* emit */
+ pk_post_trans_check_library_restart_emit (post, pids);
+ g_ptr_array_free (pids, TRUE);
+
+ g_signal_handler_disconnect (post->priv->backend, signal_files);
+ pk_post_trans_set_progress_changed (post, 100);
+out:
+ g_strfreev (files);
+ return ret;
+}
+
+/**
* pk_post_trans_finalize:
**/
static void
@@ -756,8 +1024,11 @@ pk_post_trans_finalize (GObject *object)
g_main_loop_unref (post->priv->loop);
sqlite3_close (post->priv->db);
g_hash_table_unref (post->priv->hash);
+ g_ptr_array_foreach (post->priv->files_list, (GFunc) g_free, NULL);
+ g_ptr_array_free (post->priv->files_list, TRUE);
g_object_unref (post->priv->backend);
+ g_object_unref (post->priv->lsof);
g_object_unref (post->priv->list);
g_object_unref (post->priv->running_exec_list);
@@ -782,6 +1053,11 @@ pk_post_trans_class_init (PkPostTransClass *klass)
G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
0, NULL, NULL, pk_marshal_VOID__UINT_UINT_UINT_UINT,
G_TYPE_NONE, 4, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
+ signals [PK_POST_TRANS_REQUIRE_RESTART] =
+ g_signal_new ("require-restart",
+ G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, pk_marshal_VOID__UINT_STRING,
+ G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
g_type_class_add_private (klass, sizeof (PkPostTransPrivate));
}
@@ -805,8 +1081,10 @@ pk_post_trans_init (PkPostTrans *post)
post->priv->loop = g_main_loop_new (NULL, FALSE);
post->priv->list = pk_package_list_new ();
post->priv->backend = pk_backend_new ();
+ post->priv->lsof = pk_lsof_new ();
post->priv->db = NULL;
post->priv->hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ post->priv->files_list = g_ptr_array_new ();
post->priv->finished_id =
g_signal_connect (post->priv->backend, "finished",
diff --git a/src/pk-post-trans.h b/src/pk-post-trans.h
index 66abd14..7f2fe9f 100644
--- a/src/pk-post-trans.h
+++ b/src/pk-post-trans.h
@@ -56,6 +56,8 @@ gboolean pk_post_trans_check_running_process (PkPostTrans *post,
gchar **package_ids);
gboolean pk_post_trans_check_desktop_files (PkPostTrans *post,
gchar **package_ids);
+gboolean pk_post_trans_check_library_restart (PkPostTrans *post,
+ gchar **package_ids);
G_END_DECLS
diff --git a/src/pk-transaction.c b/src/pk-transaction.c
index 2b451e8..b1400f2 100644
--- a/src/pk-transaction.c
+++ b/src/pk-transaction.c
@@ -1059,11 +1059,75 @@ pk_transaction_update_detail_cb (PkBackend *backend, const PkUpdateDetailObj *de
}
/**
+ * pk_transaction_pre_transaction_checks:
+ *
+ * TODO: also check if package in InstallPackages is in the update lists
+ * and do the same check if this is so.
+ */
+static gboolean
+pk_transaction_pre_transaction_checks (PkTransaction *transaction)
+{
+ PkPackageList *updates;
+ const PkPackageObj *obj;
+ guint i;
+ guint length;
+ gboolean ret = FALSE;
+ gchar *package_id;
+ gchar **package_ids = NULL;
+ GPtrArray *list = NULL;
+
+ /* only do this for update actions */
+ if (transaction->priv->role != PK_ROLE_ENUM_UPDATE_SYSTEM &&
+ transaction->priv->role != PK_ROLE_ENUM_UPDATE_PACKAGES) {
+ egg_debug ("doing nothing, as not update");
+ goto out;
+ }
+
+ /* do we want to enable this codepath? */
+ ret = pk_conf_get_bool (transaction->priv->conf, "CheckSharedLibrariesInUse");
+ if (!ret) {
+ egg_warning ("not checking for library restarts");
+ goto out;
+ }
+
+ /* do we have a cache */
+ updates = pk_cache_get_updates (transaction->priv->cache);
+ if (updates == NULL) {
+ egg_warning ("no updates cache");
+ goto out;
+ }
+
+ /* find security update packages */
+ list = g_ptr_array_new ();
+ length = pk_package_list_get_size (updates);
+ for (i=0; i<length; i++) {
+ obj = pk_package_list_get_obj (updates, i);
+ if (obj->info == PK_INFO_ENUM_SECURITY) {
+ package_id = pk_package_id_to_string (obj->id);
+ egg_debug ("security update: %s", package_id);
+ g_ptr_array_add (list, package_id);
+ }
+ }
+
+ /* find files in security updates */
+ package_ids = pk_package_ids_from_array (list);
+ ret = pk_post_trans_check_library_restart (transaction->priv->post_trans, package_ids);
+out:
+ g_strfreev (package_ids);
+ if (list != NULL) {
+ g_ptr_array_foreach (list, (GFunc) g_free, NULL);
+ g_ptr_array_free (list, TRUE);
+ }
+ return ret;
+}
+
+/**
* pk_transaction_set_running:
*/
G_GNUC_WARN_UNUSED_RESULT static gboolean
pk_transaction_set_running (PkTransaction *transaction)
{
+ gboolean ret;
PkBackendDesc *desc;
PkStore *store;
PkTransactionPrivate *priv = PK_TRANSACTION_GET_PRIVATE (transaction);
@@ -1092,6 +1156,13 @@ pk_transaction_set_running (PkTransaction *transaction)
pk_backend_set_role (priv->backend, priv->role);
egg_debug ("setting role for %s to %s", priv->tid, pk_role_enum_to_text (priv->role));
+ /* do any pre transaction checks */
+ ret = pk_transaction_pre_transaction_checks (transaction);
+
+ /* might have to reset again if we used the backend */
+ if (ret)
+ pk_backend_reset (transaction->priv->backend);
+
/* connect up the signals */
transaction->priv->signal_allow_cancel =
g_signal_connect (transaction->priv->backend, "allow-cancel",
@@ -4246,6 +4317,8 @@ pk_transaction_init (PkTransaction *transaction)
G_CALLBACK (pk_transaction_status_changed_cb), transaction);
g_signal_connect (transaction->priv->post_trans, "progress-changed",
G_CALLBACK (pk_transaction_progress_changed_cb), transaction);
+ g_signal_connect (transaction->priv->post_trans, "require-restart",
+ G_CALLBACK (pk_transaction_require_restart_cb), transaction);
transaction->priv->transaction_db = pk_transaction_db_new ();
g_signal_connect (transaction->priv->transaction_db, "transaction",
commit 6e38b8aa7a45dbeb117eabf5a427526bd00562cd
Author: Richard Hughes <richard at hughsie.com>
Date: Sat Jul 11 17:01:57 2009 +0100
Add the new restart enums into pkcon
diff --git a/client/pk-console.c b/client/pk-console.c
index 43a32ca..be0f167 100644
--- a/client/pk-console.c
+++ b/client/pk-console.c
@@ -518,6 +518,12 @@ pk_console_require_restart_cb (PkClient *client, const PkRequireRestartObj *obj,
} else if (obj->restart == PK_RESTART_ENUM_SESSION) {
/* TRANSLATORS: a package requires the session to be restarted */
g_print ("%s %s-%s.%s\n", _("Session restart required:"), obj->id->name, obj->id->version, obj->id->arch);
+ } else if (obj->restart == PK_RESTART_ENUM_SECURITY_SYSTEM) {
+ /* TRANSLATORS: a package requires the system to be restarted due to a security update*/
+ g_print ("%s %s-%s.%s\n", _("System restart (security) required by:"), obj->id->name, obj->id->version, obj->id->arch);
+ } else if (obj->restart == PK_RESTART_ENUM_SECURITY_SESSION) {
+ /* TRANSLATORS: a package requires the session to be restarted due to a security update */
+ g_print ("%s %s-%s.%s\n", _("Session restart (security) required:"), obj->id->name, obj->id->version, obj->id->arch);
} else if (obj->restart == PK_RESTART_ENUM_APPLICATION) {
/* TRANSLATORS: a package requires the application to be restarted */
g_print ("%s %s-%s.%s\n", _("Application restart required by:"), obj->id->name, obj->id->version, obj->id->arch);
@@ -574,7 +580,7 @@ pk_console_finished_cb (PkClient *client, PkExitEnum exit_enum, guint runtime, g
/* is there any restart to notify the user? */
restart = pk_client_get_require_restart (client);
if (restart == PK_RESTART_ENUM_SYSTEM) {
- /* TRANSLATORS: a package needs to restart they system */
+ /* TRANSLATORS: a package needs to restart their system */
g_print ("%s\n", _("Please restart the computer to complete the update."));
} else if (restart == PK_RESTART_ENUM_SESSION) {
/* TRANSLATORS: a package needs to restart the session */
@@ -582,6 +588,12 @@ pk_console_finished_cb (PkClient *client, PkExitEnum exit_enum, guint runtime, g
} else if (restart == PK_RESTART_ENUM_APPLICATION) {
/* TRANSLATORS: a package needs to restart the application */
g_print ("%s\n", _("Please restart the application as it is being used."));
+ } else if (restart == PK_RESTART_ENUM_SECURITY_SYSTEM) {
+ /* TRANSLATORS: a package needs to restart their system (due to security) */
+ g_print ("%s\n", _("Please restart the computer to complete the update as important security updates have been installed."));
+ } else if (restart == PK_RESTART_ENUM_SECURITY_SESSION) {
+ /* TRANSLATORS: a package needs to restart the session (due to security) */
+ g_print ("%s\n", _("Please logout and login to complete the update as important security updates have been installed."));
}
/* need to handle retry with only_trusted=FALSE */
commit 5de0bfac9a63f520b5ff4175012222d7c7aa9af4
Author: Richard Hughes <richard at hughsie.com>
Date: Sat Jul 11 16:54:32 2009 +0100
Add two more require-restart constants needed for future code
diff --git a/lib/packagekit-glib/pk-enum.c b/lib/packagekit-glib/pk-enum.c
index 806e9c6..bd47602 100644
--- a/lib/packagekit-glib/pk-enum.c
+++ b/lib/packagekit-glib/pk-enum.c
@@ -190,6 +190,8 @@ static const PkEnumMatch enum_restart[] = {
{PK_RESTART_ENUM_SYSTEM, "system"},
{PK_RESTART_ENUM_SESSION, "session"},
{PK_RESTART_ENUM_APPLICATION, "application"},
+ {PK_RESTART_ENUM_SECURITY_SYSTEM, "security-system"},
+ {PK_RESTART_ENUM_SECURITY_SESSION, "security-session"},
{0, NULL}
};
diff --git a/lib/packagekit-glib/pk-enum.h b/lib/packagekit-glib/pk-enum.h
index 9bf6c48..927a9dd 100644
--- a/lib/packagekit-glib/pk-enum.h
+++ b/lib/packagekit-glib/pk-enum.h
@@ -205,13 +205,15 @@ typedef enum {
/**
* PkRestartEnum:
*
- * What restart we need to after a transaction
+ * What restart we need to after a transaction, ordered by severity
**/
typedef enum {
PK_RESTART_ENUM_NONE,
PK_RESTART_ENUM_APPLICATION,
PK_RESTART_ENUM_SESSION,
PK_RESTART_ENUM_SYSTEM,
+ PK_RESTART_ENUM_SECURITY_SESSION, /* a library that is being used by this package has been updated for security */
+ PK_RESTART_ENUM_SECURITY_SYSTEM,
PK_RESTART_ENUM_UNKNOWN
} PkRestartEnum;
commit 1551df1bb3b319b6fbe3da34d98e8a1fee7fdbae
Author: Richard Hughes <richard at hughsie.com>
Date: Sat Jul 11 16:26:38 2009 +0100
Add a config file entry for future shared library use
diff --git a/etc/PackageKit.conf.in b/etc/PackageKit.conf.in
index aba3b06..259a752 100644
--- a/etc/PackageKit.conf.in
+++ b/etc/PackageKit.conf.in
@@ -116,6 +116,15 @@ UpdatePackageList=true
# default=true
UpdateCheckProcesses=true
+# Check for shared libraries that are in use, that are replaced by packages
+# that are marked as security updates.
+#
+# NOTE: Don't enable this for backends that are slow doing GetFiles() on
+# installed files.
+#
+# default=true
+CheckSharedLibrariesInUse=true
+
# Check for updates in testing repositories when we check for updates
#
# NOTE: Don't enable this if you do not want testing updates to be checked
commit 0b849cb9e39cc11d145312629399da822614ce72
Author: Richard Hughes <richard at hughsie.com>
Date: Sat Jul 11 16:24:56 2009 +0100
use lsof -Fpfn which is designed for machines to read
diff --git a/src/pk-lsof.c b/src/pk-lsof.c
index 5130728..1211cc9 100644
--- a/src/pk-lsof.c
+++ b/src/pk-lsof.c
@@ -94,6 +94,43 @@ pk_lsof_data_new (guint pid, const gchar *filename)
return data;
}
+typedef enum {
+ PK_LSOF_TYPE_MEM,
+ PK_LSOF_TYPE_DEL,
+ PK_LSOF_TYPE_TXT,
+ PK_LSOF_TYPE_UNKNOWN
+} PkLsofType;
+
+/**
+ * pk_lsof_type_to_text:
+ **/
+static const gchar *
+pk_lsof_type_to_text (PkLsofType type)
+{
+ if (type == PK_LSOF_TYPE_MEM)
+ return "mem";
+ if (type == PK_LSOF_TYPE_TXT)
+ return "txt";
+ if (type == PK_LSOF_TYPE_DEL)
+ return "del";
+ return "unknown";
+}
+
+/**
+ * pk_lsof_type_from_text:
+ **/
+static PkLsofType
+pk_lsof_type_from_text (const gchar *type)
+{
+ if (g_ascii_strcasecmp (type, "mem") == 0)
+ return PK_LSOF_TYPE_MEM;
+ if (g_ascii_strcasecmp (type, "txt") == 0)
+ return PK_LSOF_TYPE_TXT;
+ if (g_ascii_strcasecmp (type, "del") == 0)
+ return PK_LSOF_TYPE_DEL;
+ return PK_LSOF_TYPE_UNKNOWN;
+}
+
/**
* pk_lsof_refresh:
**/
@@ -107,14 +144,15 @@ pk_lsof_refresh (PkLsof *lsof)
PkLsofData *data;
gchar **lines = NULL;
guint i;
- const gchar *pid_text;
- const gchar *type;
- const gchar *filename;
+ const gchar *value;
+ gchar mode;
+ gint pid = -1;
+ PkLsofType type = PK_LSOF_TYPE_UNKNOWN;
g_return_val_if_fail (PK_IS_LSOF (lsof), FALSE);
/* run lsof to get all data */
- ret = g_spawn_command_line_sync ("/usr/sbin/lsof", &stdout, &stderr, NULL, &error);
+ ret = g_spawn_command_line_sync ("/usr/sbin/lsof -Fpfn", &stdout, &stderr, NULL, &error);
if (!ret) {
egg_warning ("failed to get pids: %s", error->message);
g_error_free (error);
@@ -129,28 +167,40 @@ pk_lsof_refresh (PkLsof *lsof)
lines = g_strsplit (stdout, "\n", -1);
for (i=0; lines[i] != NULL; i++) {
- /* parse: devhelp 11328 hughsie mem REG 8,2 65840 161702 /usr/lib/gio/modules/libgioremote-volume-monitor.so */
- lines[i][17] = '\0';
- lines[i][36] = '\0';
- pid_text = &lines[i][10];
- type = &lines[i][27];
- filename = &lines[i][69+3];
-
- /* only add memory mapped entries */
- if (!g_str_has_prefix (type, "mem"))
+ /* get mode */
+ mode = lines[i][0];
+ if (mode == '\0')
continue;
- /* not a system library */
- if (strstr (filename, "/lib/") == NULL)
- continue;
+ value = &lines[i][1];
+ switch (mode) {
+ case 'p':
+ pid = atoi (value);
+ break;
+ case 'f':
+ type = pk_lsof_type_from_text (value);
+ break;
+ case 'n':
+ if (type == PK_LSOF_TYPE_DEL ||
+ type == PK_LSOF_TYPE_MEM) {
- /* not a shared object */
- if (strstr (filename, ".so") == NULL)
- continue;
+ /* not a system library */
+ if (strstr (value, "/lib/") == NULL)
+ break;
- /* add to array */
- data = pk_lsof_data_new (atoi (pid_text), filename);
- g_ptr_array_add (lsof->priv->list_data, data);
+ /* not a shared object */
+ if (strstr (value, ".so") == NULL)
+ break;
+
+ /* add to array */
+ data = pk_lsof_data_new (pid, value);
+ g_ptr_array_add (lsof->priv->list_data, data);
+ }
+ break;
+ default:
+ egg_debug ("ignoring %c=%s (type=%s)", mode, value, pk_lsof_type_to_text (type));
+ break;
+ }
}
out:
g_strfreev (lines);
commit 4d2e71a7079d00870e6af1e436872655eababc21
Author: Richard Hughes <richard at hughsie.com>
Date: Sat Jul 11 15:27:10 2009 +0100
Prevent duplicate require-restart signal from being sent from the daemon
diff --git a/src/pk-transaction.c b/src/pk-transaction.c
index 1bfa076..2b451e8 100644
--- a/src/pk-transaction.c
+++ b/src/pk-transaction.c
@@ -115,6 +115,7 @@ struct PkTransactionPrivate
gchar *tid;
gchar *sender;
gchar *cmdline;
+ GPtrArray *require_restart_list;
PkPackageList *package_list;
PkTransactionList *transaction_list;
PkTransactionDb *transaction_db;
@@ -957,11 +958,35 @@ static void
pk_transaction_require_restart_cb (PkBackend *backend, PkRestartEnum restart, const gchar *package_id, PkTransaction *transaction)
{
const gchar *restart_text;
+ const gchar *package_id_tmp;
+ GPtrArray *list;
+ gboolean found = FALSE;
+ guint i;
g_return_if_fail (PK_IS_TRANSACTION (transaction));
g_return_if_fail (transaction->priv->tid != NULL);
restart_text = pk_restart_enum_to_text (restart);
+
+ /* filter out duplicates */
+ list = transaction->priv->require_restart_list;
+ for (i=0; i<list->len; i++) {
+ package_id_tmp = g_ptr_array_index (list, i);
+ if (g_strcmp0 (package_id, package_id_tmp) == 0) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ /* ignore */
+ if (found) {
+ egg_debug ("ignoring %s (%s) as already sent", restart_text, package_id);
+ return;
+ }
+
+ /* add to duplicate list */
+ g_ptr_array_add (list, g_strdup (package_id));
+
egg_debug ("emitting require-restart %s, '%s'", restart_text, package_id);
g_signal_emit (transaction, signals [PK_TRANSACTION_REQUIRE_RESTART], 0, restart_text, package_id);
}
@@ -1045,6 +1070,10 @@ pk_transaction_set_running (PkTransaction *transaction)
g_return_val_if_fail (PK_IS_TRANSACTION (transaction), FALSE);
g_return_val_if_fail (transaction->priv->tid != NULL, FALSE);
+ /* reset the require-restart list */
+ g_ptr_array_foreach (transaction->priv->require_restart_list, (GFunc) g_free, NULL);
+ g_ptr_array_set_size (transaction->priv->require_restart_list, 0);
+
/* prepare for use; the transaction list ensures this is safe */
pk_backend_reset (transaction->priv->backend);
@@ -4198,6 +4227,7 @@ pk_transaction_init (PkTransaction *transaction)
transaction->priv->subpercentage = PK_BACKEND_PERCENTAGE_INVALID;
transaction->priv->elapsed = 0;
transaction->priv->remaining = 0;
+ transaction->priv->require_restart_list = g_ptr_array_new ();
transaction->priv->backend = pk_backend_new ();
transaction->priv->cache = pk_cache_new ();
transaction->priv->conf = pk_conf_new ();
@@ -4286,6 +4316,9 @@ pk_transaction_finalize (GObject *object)
g_object_unref (transaction->priv->subject);
#endif
+ g_ptr_array_foreach (transaction->priv->require_restart_list, (GFunc) g_free, NULL);
+ g_ptr_array_free (transaction->priv->require_restart_list, TRUE);
+
g_free (transaction->priv->last_package_id);
g_free (transaction->priv->locale);
g_free (transaction->priv->cached_package_id);
commit f96ab45df8458eea676c030942555a20b8e97809
Author: Richard Hughes <richard at hughsie.com>
Date: Sat Jul 11 15:20:27 2009 +0100
trivial: make pk_post_trans_get_installed_package_for_file() more generic
diff --git a/src/pk-post-trans.c b/src/pk-post-trans.c
index 4575c53..52556a5 100644
--- a/src/pk-post-trans.c
+++ b/src/pk-post-trans.c
@@ -102,14 +102,13 @@ pk_post_trans_set_progress_changed (PkPostTrans *post, guint percentage)
}
/**
- * pk_post_trans_import_desktop_files_get_package:
+ * pk_post_trans_get_installed_package_for_file:
**/
-static gchar *
-pk_post_trans_import_desktop_files_get_package (PkPostTrans *post, const gchar *filename)
+static const PkPackageObj *
+pk_post_trans_get_installed_package_for_file (PkPostTrans *post, const gchar *filename)
{
guint size;
- gchar *name = NULL;
- const PkPackageObj *obj;
+ const PkPackageObj *obj = NULL;
PkStore *store;
/* use PK to find the correct package */
@@ -136,12 +135,8 @@ pk_post_trans_import_desktop_files_get_package (PkPostTrans *post, const gchar *
egg_warning ("cannot get obj");
goto out;
}
-
- /* strip the name */
- name = g_strdup (obj->id->name);
-
out:
- return name;
+ return obj;
}
/**
@@ -271,6 +266,7 @@ pk_post_trans_sqlite_add_filename (PkPostTrans *post, const gchar *filename, con
gchar *md5 = NULL;
gchar *package = NULL;
gint rc = -1;
+ const PkPackageObj *obj;
/* if we've got it, use old data */
if (md5_opt != NULL)
@@ -279,14 +275,14 @@ pk_post_trans_sqlite_add_filename (PkPostTrans *post, const gchar *filename, con
md5 = pk_post_trans_get_filename_md5 (filename);
/* resolve */
- package = pk_post_trans_import_desktop_files_get_package (post, filename);
- if (package == NULL) {
+ obj = pk_post_trans_get_installed_package_for_file (post, filename);
+ if (obj == NULL) {
egg_warning ("failed to get list");
goto out;
}
/* add */
- rc = pk_post_trans_sqlite_add_filename_details (post, filename, package, md5);
+ rc = pk_post_trans_sqlite_add_filename_details (post, filename, obj->id->name, md5);
out:
g_free (md5);
g_free (package);
commit f904fd4fe9fe6e4b1d5cffe643ee1ec023d89be0
Author: Richard Hughes <richard at hughsie.com>
Date: Sat Jul 11 15:11:43 2009 +0100
Add a thin cached wrapper around lsof so we can track what applications are using open libraries
diff --git a/src/Makefile.am b/src/Makefile.am
index 30ad4e5..6ada872 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -51,6 +51,8 @@ shared_SOURCES = \
egg-dbus-monitor.h \
pk-marshal.c \
pk-marshal.h \
+ pk-lsof.c \
+ pk-lsof.h \
pk-transaction.c \
pk-transaction.h \
pk-backend.c \
diff --git a/src/pk-lsof.c b/src/pk-lsof.c
new file mode 100644
index 0000000..5130728
--- /dev/null
+++ b/src/pk-lsof.c
@@ -0,0 +1,294 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <glib.h>
+
+#include "egg-debug.h"
+
+#include "pk-lsof.h"
+
+#define PK_LSOF_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PK_TYPE_LSOF, PkLsofPrivate))
+
+struct PkLsofPrivate
+{
+ GPtrArray *list_data;
+};
+
+G_DEFINE_TYPE (PkLsof, pk_lsof, G_TYPE_OBJECT)
+
+typedef struct {
+ guint pid;
+ gchar *filename;
+} PkLsofData;
+
+/**
+ * pk_lsof_add_pid:
+ **/
+static gboolean
+pk_lsof_add_pid (GPtrArray *array, guint pid)
+{
+ guint i;
+ guint pid_tmp;
+ gboolean found = FALSE;
+
+ /* search already list */
+ for (i=0; i<array->len; i++) {
+ pid_tmp = GPOINTER_TO_INT (g_ptr_array_index (array, i));
+ if (pid_tmp == pid) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ /* not found, so add */
+ if (!found) {
+ g_ptr_array_add (array, GINT_TO_POINTER (pid));
+ }
+ return !found;
+}
+
+/**
+ * pk_lsof_data_free:
+ **/
+static void
+pk_lsof_data_free (PkLsofData *lsof)
+{
+ g_free (lsof->filename);
+ g_free (lsof);
+}
+
+/**
+ * pk_lsof_data_new:
+ **/
+static PkLsofData *
+pk_lsof_data_new (guint pid, const gchar *filename)
+{
+ PkLsofData *data;
+ data = g_new0 (PkLsofData, 1);
+ data->pid = pid;
+ data->filename = g_strdup (filename);
+ return data;
+}
+
+/**
+ * pk_lsof_refresh:
+ **/
+gboolean
+pk_lsof_refresh (PkLsof *lsof)
+{
+ gboolean ret;
+ GError *error = NULL;
+ gchar *stdout = NULL;
+ gchar *stderr = NULL;
+ PkLsofData *data;
+ gchar **lines = NULL;
+ guint i;
+ const gchar *pid_text;
+ const gchar *type;
+ const gchar *filename;
+
+ g_return_val_if_fail (PK_IS_LSOF (lsof), FALSE);
+
+ /* run lsof to get all data */
+ ret = g_spawn_command_line_sync ("/usr/sbin/lsof", &stdout, &stderr, NULL, &error);
+ if (!ret) {
+ egg_warning ("failed to get pids: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* clear */
+ g_ptr_array_foreach (lsof->priv->list_data, (GFunc) pk_lsof_data_free, NULL);
+ g_ptr_array_set_size (lsof->priv->list_data, 0);
+
+ /* split into lines */
+ lines = g_strsplit (stdout, "\n", -1);
+ for (i=0; lines[i] != NULL; i++) {
+
+ /* parse: devhelp 11328 hughsie mem REG 8,2 65840 161702 /usr/lib/gio/modules/libgioremote-volume-monitor.so */
+ lines[i][17] = '\0';
+ lines[i][36] = '\0';
+ pid_text = &lines[i][10];
+ type = &lines[i][27];
+ filename = &lines[i][69+3];
+
+ /* only add memory mapped entries */
+ if (!g_str_has_prefix (type, "mem"))
+ continue;
+
+ /* not a system library */
+ if (strstr (filename, "/lib/") == NULL)
+ continue;
+
+ /* not a shared object */
+ if (strstr (filename, ".so") == NULL)
+ continue;
+
+ /* add to array */
+ data = pk_lsof_data_new (atoi (pid_text), filename);
+ g_ptr_array_add (lsof->priv->list_data, data);
+ }
+out:
+ g_strfreev (lines);
+ g_free (stdout);
+ g_free (stderr);
+ return ret;
+}
+
+/**
+ * pk_lsof_get_pids_for_filenames:
+ **/
+GPtrArray *
+pk_lsof_get_pids_for_filenames (PkLsof *lsof, gchar **filenames)
+{
+ guint i;
+ guint j;
+ gboolean ret;
+ GPtrArray *list_data;
+ GPtrArray *pids = NULL;
+ const PkLsofData *data;
+
+ g_return_val_if_fail (PK_IS_LSOF (lsof), NULL);
+
+ /* might not have been refreshed ever */
+ list_data = lsof->priv->list_data;
+ if (list_data->len == 0) {
+ ret = pk_lsof_refresh (lsof);
+ if (!ret) {
+ egg_warning ("failed to refresh");
+ goto out;
+ }
+ }
+
+ /* create array of pids that are using this library */
+ pids = g_ptr_array_new ();
+ for (i=0; filenames[i] != NULL; i++) {
+ for (j=0; j < list_data->len; j++) {
+ data = g_ptr_array_index (list_data, j);
+ if (g_strcmp0 (filenames[i], data->filename) == 0) {
+ pk_lsof_add_pid (pids, data->pid);
+ }
+ }
+ }
+out:
+ return pids;
+}
+
+/**
+ * pk_lsof_finalize:
+ **/
+static void
+pk_lsof_finalize (GObject *object)
+{
+ PkLsof *lsof;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (PK_IS_LSOF (object));
+ lsof = PK_LSOF (object);
+
+ g_ptr_array_foreach (lsof->priv->list_data, (GFunc) pk_lsof_data_free, NULL);
+ g_ptr_array_free (lsof->priv->list_data, TRUE);
+
+ G_OBJECT_CLASS (pk_lsof_parent_class)->finalize (object);
+}
+
+/**
+ * pk_lsof_class_init:
+ **/
+static void
+pk_lsof_class_init (PkLsofClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = pk_lsof_finalize;
+ g_type_class_add_private (klass, sizeof (PkLsofPrivate));
+}
+
+/**
+ * pk_lsof_init:
+ *
+ * initializes the lsof class. NOTE: We expect lsof objects
+ * to *NOT* be removed or added during the session.
+ * We only control the first lsof object if there are more than one.
+ **/
+static void
+pk_lsof_init (PkLsof *lsof)
+{
+ lsof->priv = PK_LSOF_GET_PRIVATE (lsof);
+ lsof->priv->list_data = g_ptr_array_new ();
+}
+
+/**
+ * pk_lsof_new:
+ * Return value: A new lsof class instance.
+ **/
+PkLsof *
+pk_lsof_new (void)
+{
+ PkLsof *lsof;
+ lsof = g_object_new (PK_TYPE_LSOF, NULL);
+ return PK_LSOF (lsof);
+}
+
+/***************************************************************************
+ *** MAKE CHECK TESTS ***
+ ***************************************************************************/
+#ifdef EGG_TEST
+#include "egg-test.h"
+
+void
+pk_lsof_test (EggTest *test)
+{
+ gboolean ret;
+ PkLsof *lsof;
+ GPtrArray *pids;
+ gchar *files[] = { "/lib/libssl3.so", NULL };
+
+ if (!egg_test_start (test, "PkLsof"))
+ return;
+
+ /************************************************************/
+ egg_test_title (test, "get an instance");
+ lsof = pk_lsof_new ();
+ egg_test_assert (test, lsof != NULL);
+
+ /************************************************************/
+ egg_test_title (test, "refresh lsof data");
+ ret = pk_lsof_refresh (lsof);
+ egg_test_assert (test, ret);
+
+ /************************************************************/
+ egg_test_title (test, "get pids for files");
+ pids = pk_lsof_get_pids_for_filenames (lsof, files);
+ egg_test_assert (test, pids->len > 0);
+ g_ptr_array_free (pids, TRUE);
+
+ g_object_unref (lsof);
+
+ egg_test_end (test);
+}
+#endif
+
diff --git a/src/pk-lsof.h b/src/pk-lsof.h
new file mode 100644
index 0000000..d6de46f
--- /dev/null
+++ b/src/pk-lsof.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PK_LSOF_H
+#define __PK_LSOF_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define PK_TYPE_LSOF (pk_lsof_get_type ())
+#define PK_LSOF(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PK_TYPE_LSOF, PkLsof))
+#define PK_LSOF_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PK_TYPE_LSOF, PkLsofClass))
+#define PK_IS_LSOF(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PK_TYPE_LSOF))
+#define PK_IS_LSOF_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PK_TYPE_LSOF))
+#define PK_LSOF_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PK_TYPE_LSOF, PkLsofClass))
+
+typedef struct PkLsofPrivate PkLsofPrivate;
+
+typedef struct
+{
+ GObject parent;
+ PkLsofPrivate *priv;
+} PkLsof;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} PkLsofClass;
+
+GType pk_lsof_get_type (void);
+PkLsof *pk_lsof_new (void);
+
+gboolean pk_lsof_refresh (PkLsof *lsof);
+GPtrArray *pk_lsof_get_pids_for_filenames (PkLsof *lsof,
+ gchar **filenames);
+
+G_END_DECLS
+
+#endif /* __PK_LSOF_H */
+
diff --git a/src/pk-self-test.c b/src/pk-self-test.c
index ccaf919..753541a 100644
--- a/src/pk-self-test.c
+++ b/src/pk-self-test.c
@@ -26,6 +26,7 @@
/* prototypes */
void egg_string_test (EggTest *test);
+void pk_lsof_test (EggTest *test);
void pk_conf_test (EggTest *test);
void pk_store_test (EggTest *test);
void pk_inhibit_test (EggTest *test);
@@ -53,6 +54,7 @@ main (int argc, char **argv)
egg_string_test (test);
/* components */
+ pk_lsof_test (test);
pk_file_monitor_test (test);
pk_time_test (test);
pk_conf_test (test);
commit 76b59120698415cfbd399ad2860290d4a4239627
Author: Richard Hughes <richard at hughsie.com>
Date: Sat Jul 11 15:09:32 2009 +0100
dummy: add to the file list for the new lsof functionality testing
diff --git a/backends/dummy/pk-backend-dummy.c b/backends/dummy/pk-backend-dummy.c
index bbc46db..aad1fe6 100644
--- a/backends/dummy/pk-backend-dummy.c
+++ b/backends/dummy/pk-backend-dummy.c
@@ -243,7 +243,7 @@ backend_get_files (PkBackend *backend, gchar **package_ids)
else if (egg_strequal (package_id, "kernel;2.6.23-0.115.rc3.git1.fc8;i386;installed"))
pk_backend_files (backend, package_id, "/usr/share/man/man1;/usr/share/man/man1/gnome-power-manager.1.gz");
else if (egg_strequal (package_id, "gtkhtml2;2.19.1-4.fc8;i386;fedora"))
- pk_backend_files (backend, package_id, "/usr/share/man/man1;/usr/bin/ck-xinit-session");
+ pk_backend_files (backend, package_id, "/usr/share/man/man1;/usr/bin/ck-xinit-session;/lib/libselinux.so.1");
else
pk_backend_files (backend, package_id, "/usr/share/gnome-power-manager;/usr/bin/ck-xinit-session");
}
More information about the PackageKit-commit
mailing list