From 6e5688421ab4988e4fc14b340a3931555a02d2c0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 19 Apr 2011 15:43:46 +0200 Subject: remaned some .cpp files to .c in src/daemon/ Signed-off-by: Denys Vlasenko --- src/daemon/CommLayerServerDBus.c | 280 ++++++++++++++++++++++++++++++++++ src/daemon/CommLayerServerDBus.cpp | 280 ---------------------------------- src/daemon/Daemon.cpp | 3 - src/daemon/Makefile.am | 6 +- src/daemon/MiddleWare.c | 295 ++++++++++++++++++++++++++++++++++++ src/daemon/MiddleWare.cpp | 297 ------------------------------------- src/daemon/MiddleWare.h | 10 +- src/daemon/Settings.h | 3 - src/daemon/comm_layer_inner.c | 61 ++++++++ src/daemon/comm_layer_inner.cpp | 61 -------- 10 files changed, 648 insertions(+), 648 deletions(-) create mode 100644 src/daemon/CommLayerServerDBus.c delete mode 100644 src/daemon/CommLayerServerDBus.cpp create mode 100644 src/daemon/MiddleWare.c delete mode 100644 src/daemon/MiddleWare.cpp create mode 100644 src/daemon/comm_layer_inner.c delete mode 100644 src/daemon/comm_layer_inner.cpp (limited to 'src') diff --git a/src/daemon/CommLayerServerDBus.c b/src/daemon/CommLayerServerDBus.c new file mode 100644 index 00000000..9d6b6a1f --- /dev/null +++ b/src/daemon/CommLayerServerDBus.c @@ -0,0 +1,280 @@ +/* + Copyright (C) 2010 ABRT team + Copyright (C) 2010 RedHat Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include "abrtlib.h" +#include "abrt_dbus.h" +#include "comm_layer_inner.h" +#include "MiddleWare.h" +#include "Settings.h" +#include "CommLayerServerDBus.h" + +/* + * DBus signal emitters + */ + +/* helpers */ +static DBusMessage* new_signal_msg(const char* member, const char* peer) +{ + /* path, interface, member name */ + DBusMessage* msg = dbus_message_new_signal(ABRTD_DBUS_PATH, ABRTD_DBUS_IFACE, member); + if (!msg) + die_out_of_memory(); + /* Send unicast dbus signal if peer is known */ + if (peer && !dbus_message_set_destination(msg, peer)) + die_out_of_memory(); + return msg; +} +static void send_flush_and_unref(DBusMessage* msg) +{ + if (!g_dbus_conn) + { + /* Not logging this, it may recurse */ + return; + } + if (!dbus_connection_send(g_dbus_conn, msg, NULL /* &serial */)) + error_msg_and_die("Error sending DBus message"); + dbus_connection_flush(g_dbus_conn); + VERB3 log("DBus message sent"); + dbus_message_unref(msg); +} + +/* Notify the clients (UI) about a new crash */ +void send_dbus_sig_Crash(const char *package_name, + const char *dir, + const char *uid_str +) { + DBusMessage* msg = new_signal_msg("Crash", NULL); + if (uid_str) + { + dbus_message_append_args(msg, + DBUS_TYPE_STRING, &package_name, + DBUS_TYPE_STRING, &dir, + DBUS_TYPE_STRING, &uid_str, + DBUS_TYPE_INVALID); + VERB2 log("Sending signal Crash('%s','%s','%s')", package_name, dir, uid_str); + } + else + { + dbus_message_append_args(msg, + DBUS_TYPE_STRING, &package_name, + DBUS_TYPE_STRING, &dir, + DBUS_TYPE_INVALID); + VERB2 log("Sending signal Crash('%s','%s')", package_name, dir); + } + send_flush_and_unref(msg); +} + +void send_dbus_sig_QuotaExceeded(const char* str) +{ + DBusMessage* msg = new_signal_msg("QuotaExceeded", NULL); + dbus_message_append_args(msg, + DBUS_TYPE_STRING, &str, + DBUS_TYPE_INVALID); + VERB2 log("Sending signal QuotaExceeded('%s')", str); + send_flush_and_unref(msg); +} + +void send_dbus_sig_Update(const char* pMessage, const char* peer) +{ + DBusMessage* msg = new_signal_msg("Update", peer); + dbus_message_append_args(msg, + DBUS_TYPE_STRING, &pMessage, + DBUS_TYPE_INVALID); + send_flush_and_unref(msg); +} + +void send_dbus_sig_Warning(const char* pMessage, const char* peer) +{ + DBusMessage* msg = new_signal_msg("Warning", peer); + dbus_message_append_args(msg, + DBUS_TYPE_STRING, &pMessage, + DBUS_TYPE_INVALID); + send_flush_and_unref(msg); +} + + +/* + * DBus call handlers + */ + +static long get_remote_uid(DBusMessage* call, const char** ppSender) +{ + DBusError err; + dbus_error_init(&err); + const char* sender = dbus_message_get_sender(call); + if (ppSender) + *ppSender = sender; + long uid = dbus_bus_get_unix_user(g_dbus_conn, sender, &err); + if (dbus_error_is_set(&err)) + { + dbus_error_free(&err); + error_msg("Can't determine remote uid, assuming 0"); + return 0; + } + return uid; +} + +static int handle_DeleteDebugDump(DBusMessage* call, DBusMessage* reply) +{ + int r; + DBusMessageIter in_iter; + dbus_message_iter_init(call, &in_iter); + const char* crash_id; + r = load_charp(&in_iter, &crash_id); + if (r != ABRT_DBUS_LAST_FIELD) + { + error_msg("dbus call %s: parameter type mismatch", __func__ + 7); + return -1; + } + + long unix_uid = get_remote_uid(call, NULL); + int32_t result = DeleteDebugDump(crash_id, unix_uid); + + DBusMessageIter out_iter; + dbus_message_iter_init_append(reply, &out_iter); + store_int32(&out_iter, result); + + send_flush_and_unref(reply); + return 0; +} + +/* + * Glib integration machinery + */ + +/* Callback: "a message is received to a registered object path" */ +static DBusHandlerResult message_received(DBusConnection* conn, DBusMessage* msg, void* data) +{ + const char* member = dbus_message_get_member(msg); + VERB1 log("%s(method:'%s')", __func__, member); + + set_client_name(dbus_message_get_sender(msg)); + + DBusMessage* reply = dbus_message_new_method_return(msg); + int r = -1; + if (strcmp(member, "DeleteDebugDump") == 0) + r = handle_DeleteDebugDump(msg, reply); + +// NB: C++ binding also handles "Introspect" method, which returns a string. +// It was sending "dummy" introspection answer whick looks like this: +// "\n" +// "\n" +// "\n" +// Apart from a warning from abrt-gui, just sending error back works as well. +// NB2: we may want to handle "Disconnected" here too. + + if (r < 0) + { + /* handle_XXX experienced an error (and did not send any reply) */ + dbus_message_unref(reply); + if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL) + { + /* Create and send error reply */ + reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, "not supported"); + if (!reply) + die_out_of_memory(); + send_flush_and_unref(reply); + } + } + + set_client_name(NULL); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static void handle_dbus_err(bool error_flag, DBusError *err) +{ + if (dbus_error_is_set(err)) + { + error_msg("dbus error: %s", err->message); + /* dbus_error_free(&err); */ + error_flag = true; + } + if (!error_flag) + return; + error_msg_and_die( + "Error requesting DBus name %s, possible reasons: " + "abrt run by non-root; dbus config is incorrect; " + "or dbus daemon needs to be restarted to reload dbus config", + ABRTD_DBUS_NAME); +} + +int init_dbus() +{ + DBusConnection* conn; + DBusError err; + + dbus_error_init(&err); + VERB3 log("dbus_bus_get"); + conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); + handle_dbus_err(conn == NULL, &err); + // dbus api says: + // "If dbus_bus_get obtains a new connection object never before returned + // from dbus_bus_get(), it will call dbus_connection_set_exit_on_disconnect(), + // so the application will exit if the connection closes. You can undo this + // by calling dbus_connection_set_exit_on_disconnect() yourself after you get + // the connection." + // ... + // "When a connection is disconnected, you are guaranteed to get a signal + // "Disconnected" from the interface DBUS_INTERFACE_LOCAL, path DBUS_PATH_LOCAL" + // + // dbus-daemon drops connections if it recvs a malformed message + // (we actually observed this when we sent bad UTF-8 string). + // Currently, in this case abrtd just exits with exit code 1. + // (symptom: last two log messages are "abrtd: remove_watch()") + // If we want to have better logging or other nontrivial handling, + // here we need to do: + // + //dbus_connection_set_exit_on_disconnect(conn, FALSE); + //dbus_connection_add_filter(conn, handle_message, NULL, NULL); + // + // and need to code up handle_message to check for "Disconnected" dbus signal + + /* Also sets g_dbus_conn to conn. */ + attach_dbus_conn_to_glib_main_loop(conn, "/com/redhat/abrt", message_received); + + VERB3 log("dbus_bus_request_name"); + int rc = dbus_bus_request_name(conn, ABRTD_DBUS_NAME, DBUS_NAME_FLAG_REPLACE_EXISTING, &err); +//maybe check that r == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER instead? + handle_dbus_err(rc < 0, &err); + VERB3 log("dbus init done"); + + /* dbus_bus_request_name can already read some data. For example, + * if we were autostarted, the call which caused autostart arrives + * at this moment. Thus while dbus fd hasn't any data anymore, + * dbus library can buffer a message or two. + * If we don't do this, the data won't be processed + * until next dbus data arrives. + */ + int cnt = 10; + while (dbus_connection_dispatch(conn) != DBUS_DISPATCH_COMPLETE && --cnt) + VERB3 log("processed initial buffered dbus message"); + + return 0; +} + +void deinit_dbus() +{ + if (g_dbus_conn != NULL) + { + dbus_connection_unref(g_dbus_conn); + g_dbus_conn = NULL; + } +} diff --git a/src/daemon/CommLayerServerDBus.cpp b/src/daemon/CommLayerServerDBus.cpp deleted file mode 100644 index 3e0a6a78..00000000 --- a/src/daemon/CommLayerServerDBus.cpp +++ /dev/null @@ -1,280 +0,0 @@ -/* - Copyright (C) 2010 ABRT team - Copyright (C) 2010 RedHat Inc - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ -#include -#include "abrtlib.h" -#include "abrt_dbus.h" -#include "comm_layer_inner.h" -#include "MiddleWare.h" -#include "Settings.h" -#include "CommLayerServerDBus.h" - -/* - * DBus signal emitters - */ - -/* helpers */ -static DBusMessage* new_signal_msg(const char* member, const char* peer = NULL) -{ - /* path, interface, member name */ - DBusMessage* msg = dbus_message_new_signal(ABRTD_DBUS_PATH, ABRTD_DBUS_IFACE, member); - if (!msg) - die_out_of_memory(); - /* Send unicast dbus signal if peer is known */ - if (peer && !dbus_message_set_destination(msg, peer)) - die_out_of_memory(); - return msg; -} -static void send_flush_and_unref(DBusMessage* msg) -{ - if (!g_dbus_conn) - { - /* Not logging this, it may recurse */ - return; - } - if (!dbus_connection_send(g_dbus_conn, msg, NULL /* &serial */)) - error_msg_and_die("Error sending DBus message"); - dbus_connection_flush(g_dbus_conn); - VERB3 log("DBus message sent"); - dbus_message_unref(msg); -} - -/* Notify the clients (UI) about a new crash */ -void send_dbus_sig_Crash(const char *package_name, - const char *dir, - const char *uid_str -) { - DBusMessage* msg = new_signal_msg("Crash"); - if (uid_str) - { - dbus_message_append_args(msg, - DBUS_TYPE_STRING, &package_name, - DBUS_TYPE_STRING, &dir, - DBUS_TYPE_STRING, &uid_str, - DBUS_TYPE_INVALID); - VERB2 log("Sending signal Crash('%s','%s','%s')", package_name, dir, uid_str); - } - else - { - dbus_message_append_args(msg, - DBUS_TYPE_STRING, &package_name, - DBUS_TYPE_STRING, &dir, - DBUS_TYPE_INVALID); - VERB2 log("Sending signal Crash('%s','%s')", package_name, dir); - } - send_flush_and_unref(msg); -} - -void send_dbus_sig_QuotaExceeded(const char* str) -{ - DBusMessage* msg = new_signal_msg("QuotaExceeded"); - dbus_message_append_args(msg, - DBUS_TYPE_STRING, &str, - DBUS_TYPE_INVALID); - VERB2 log("Sending signal QuotaExceeded('%s')", str); - send_flush_and_unref(msg); -} - -void send_dbus_sig_Update(const char* pMessage, const char* peer) -{ - DBusMessage* msg = new_signal_msg("Update", peer); - dbus_message_append_args(msg, - DBUS_TYPE_STRING, &pMessage, - DBUS_TYPE_INVALID); - send_flush_and_unref(msg); -} - -void send_dbus_sig_Warning(const char* pMessage, const char* peer) -{ - DBusMessage* msg = new_signal_msg("Warning", peer); - dbus_message_append_args(msg, - DBUS_TYPE_STRING, &pMessage, - DBUS_TYPE_INVALID); - send_flush_and_unref(msg); -} - - -/* - * DBus call handlers - */ - -static long get_remote_uid(DBusMessage* call, const char** ppSender = NULL) -{ - DBusError err; - dbus_error_init(&err); - const char* sender = dbus_message_get_sender(call); - if (ppSender) - *ppSender = sender; - long uid = dbus_bus_get_unix_user(g_dbus_conn, sender, &err); - if (dbus_error_is_set(&err)) - { - dbus_error_free(&err); - error_msg("Can't determine remote uid, assuming 0"); - return 0; - } - return uid; -} - -static int handle_DeleteDebugDump(DBusMessage* call, DBusMessage* reply) -{ - int r; - DBusMessageIter in_iter; - dbus_message_iter_init(call, &in_iter); - const char* crash_id; - r = load_val(&in_iter, crash_id); - if (r != ABRT_DBUS_LAST_FIELD) - { - error_msg("dbus call %s: parameter type mismatch", __func__ + 7); - return -1; - } - - long unix_uid = get_remote_uid(call); - int32_t result = DeleteDebugDump(crash_id, unix_uid); - - DBusMessageIter out_iter; - dbus_message_iter_init_append(reply, &out_iter); - store_val(&out_iter, result); - - send_flush_and_unref(reply); - return 0; -} - -/* - * Glib integration machinery - */ - -/* Callback: "a message is received to a registered object path" */ -static DBusHandlerResult message_received(DBusConnection* conn, DBusMessage* msg, void* data) -{ - const char* member = dbus_message_get_member(msg); - VERB1 log("%s(method:'%s')", __func__, member); - - set_client_name(dbus_message_get_sender(msg)); - - DBusMessage* reply = dbus_message_new_method_return(msg); - int r = -1; - if (strcmp(member, "DeleteDebugDump") == 0) - r = handle_DeleteDebugDump(msg, reply); - -// NB: C++ binding also handles "Introspect" method, which returns a string. -// It was sending "dummy" introspection answer whick looks like this: -// "\n" -// "\n" -// "\n" -// Apart from a warning from abrt-gui, just sending error back works as well. -// NB2: we may want to handle "Disconnected" here too. - - if (r < 0) - { - /* handle_XXX experienced an error (and did not send any reply) */ - dbus_message_unref(reply); - if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL) - { - /* Create and send error reply */ - reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, "not supported"); - if (!reply) - die_out_of_memory(); - send_flush_and_unref(reply); - } - } - - set_client_name(NULL); - - return DBUS_HANDLER_RESULT_HANDLED; -} - -static void handle_dbus_err(bool error_flag, DBusError *err) -{ - if (dbus_error_is_set(err)) - { - error_msg("dbus error: %s", err->message); - /* dbus_error_free(&err); */ - error_flag = true; - } - if (!error_flag) - return; - error_msg_and_die( - "Error requesting DBus name %s, possible reasons: " - "abrt run by non-root; dbus config is incorrect; " - "or dbus daemon needs to be restarted to reload dbus config", - ABRTD_DBUS_NAME); -} - -int init_dbus() -{ - DBusConnection* conn; - DBusError err; - - dbus_error_init(&err); - VERB3 log("dbus_bus_get"); - conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); - handle_dbus_err(conn == NULL, &err); - // dbus api says: - // "If dbus_bus_get obtains a new connection object never before returned - // from dbus_bus_get(), it will call dbus_connection_set_exit_on_disconnect(), - // so the application will exit if the connection closes. You can undo this - // by calling dbus_connection_set_exit_on_disconnect() yourself after you get - // the connection." - // ... - // "When a connection is disconnected, you are guaranteed to get a signal - // "Disconnected" from the interface DBUS_INTERFACE_LOCAL, path DBUS_PATH_LOCAL" - // - // dbus-daemon drops connections if it recvs a malformed message - // (we actually observed this when we sent bad UTF-8 string). - // Currently, in this case abrtd just exits with exit code 1. - // (symptom: last two log messages are "abrtd: remove_watch()") - // If we want to have better logging or other nontrivial handling, - // here we need to do: - // - //dbus_connection_set_exit_on_disconnect(conn, FALSE); - //dbus_connection_add_filter(conn, handle_message, NULL, NULL); - // - // and need to code up handle_message to check for "Disconnected" dbus signal - - /* Also sets g_dbus_conn to conn. */ - attach_dbus_conn_to_glib_main_loop(conn, "/com/redhat/abrt", message_received); - - VERB3 log("dbus_bus_request_name"); - int rc = dbus_bus_request_name(conn, ABRTD_DBUS_NAME, DBUS_NAME_FLAG_REPLACE_EXISTING, &err); -//maybe check that r == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER instead? - handle_dbus_err(rc < 0, &err); - VERB3 log("dbus init done"); - - /* dbus_bus_request_name can already read some data. For example, - * if we were autostarted, the call which caused autostart arrives - * at this moment. Thus while dbus fd hasn't any data anymore, - * dbus library can buffer a message or two. - * If we don't do this, the data won't be processed - * until next dbus data arrives. - */ - int cnt = 10; - while (dbus_connection_dispatch(conn) != DBUS_DISPATCH_COMPLETE && --cnt) - VERB3 log("processed initial buffered dbus message"); - - return 0; -} - -void deinit_dbus() -{ - if (g_dbus_conn != NULL) - { - dbus_connection_unref(g_dbus_conn); - g_dbus_conn = NULL; - } -} diff --git a/src/daemon/Daemon.cpp b/src/daemon/Daemon.cpp index b6735daa..3ac53aeb 100644 --- a/src/daemon/Daemon.cpp +++ b/src/daemon/Daemon.cpp @@ -52,9 +52,6 @@ using namespace std; * * DBus methods we have: * - DeleteDebugDump(crash_id): delete it from DB and delete corresponding /var/spool/abrt/DIR - * - RegisterPlugin(PluginName): returns void - * - UnRegisterPlugin(PluginName): returns void - * - SetSettings(map_abrt_settings_t): returns void * * DBus signals we emit: * - Crash(progname, crash_id, dir, uid) - a new crash occurred (new /var/spool/abrt/DIR is found) diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am index df5198bd..97e6fb5f 100644 --- a/src/daemon/Makefile.am +++ b/src/daemon/Makefile.am @@ -10,10 +10,10 @@ sbin_PROGRAMS = \ abrt-server abrtd_SOURCES = \ - MiddleWare.h MiddleWare.cpp \ - CommLayerServerDBus.h CommLayerServerDBus.cpp \ + MiddleWare.h MiddleWare.c \ + CommLayerServerDBus.h CommLayerServerDBus.c \ Settings.h Settings.cpp \ - comm_layer_inner.h comm_layer_inner.cpp \ + comm_layer_inner.h comm_layer_inner.c \ Daemon.cpp abrtd_CPPFLAGS = \ -I$(srcdir)/../include/report -I$(srcdir)/../include \ diff --git a/src/daemon/MiddleWare.c b/src/daemon/MiddleWare.c new file mode 100644 index 00000000..cff5d785 --- /dev/null +++ b/src/daemon/MiddleWare.c @@ -0,0 +1,295 @@ +/* + MiddleWare.cpp + + Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com) + Copyright (C) 2009 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "abrtlib.h" +#include "Settings.h" +#include "comm_layer_inner.h" +#include "CommLayerServerDBus.h" +#include "MiddleWare.h" + +/** + * Get one crash info. If getting is successful, + * then crash info is filled. + * @param dump_dir_name A dump dir containing all necessary data. + * @param pCrashData A crash info. + * @return It return results of operation. See mw_result_t. + */ +static crash_data_t *FillCrashInfo(const char *dump_dir_name); + + +struct logging_state { + char *last_line; +}; + +static char *do_log_and_save_line(char *log_line, void *param) +{ + struct logging_state *l_state = (struct logging_state *)param; + + VERB1 log("%s", log_line); + update_client("%s", log_line); + free(l_state->last_line); + l_state->last_line = log_line; + return NULL; +} + + +/* We need to share some data between LoadDebugDump and is_crash_a_dup: */ +struct cdump_state { + char *uid; /* filled by LoadDebugDump */ + char *uuid; /* filled by is_crash_a_dup */ + char *crash_dump_dup_name; /* filled by is_crash_a_dup */ +}; + +static int is_crash_a_dup(const char *dump_dir_name, void *param) +{ + struct cdump_state *state = (struct cdump_state *)param; + + if (state->uuid) + return 0; /* we already checked it, don't do it again */ + + struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); + if (!dd) + return 0; /* wtf? (error, but will be handled elsewhere later) */ + state->uuid = dd_load_text_ext(dd, FILENAME_UUID, + DD_FAIL_QUIETLY_ENOENT + DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE + ); + dd_close(dd); + if (!state->uuid) + { + return 0; /* no uuid (yet), "run_event, please continue iterating" */ + } + + /* Scan crash dumps looking for a dup */ +//TODO: explain why this is safe wrt concurrent runs + DIR *dir = opendir(DEBUG_DUMPS_DIR); + if (dir != NULL) + { + struct dirent *dent; + while ((dent = readdir(dir)) != NULL) + { + if (dot_or_dotdot(dent->d_name)) + continue; /* skip "." and ".." */ + + int different; + char *uid, *uuid; + char *dump_dir_name2 = concat_path_file(DEBUG_DUMPS_DIR, dent->d_name); + + if (strcmp(dump_dir_name, dump_dir_name2) == 0) + goto next; /* we are never a dup of ourself */ + + dd = dd_opendir(dump_dir_name2, /*flags:*/ DD_FAIL_QUIETLY_ENOENT); + if (!dd) + goto next; + uid = dd_load_text(dd, FILENAME_UID); + uuid = dd_load_text(dd, FILENAME_UUID); + dd_close(dd); + different = strcmp(state->uid, uid) || strcmp(state->uuid, uuid); + free(uid); + free(uuid); + if (different) + goto next; + + state->crash_dump_dup_name = dump_dir_name2; + /* "run_event, please stop iterating": */ + return 1; + + next: + free(dump_dir_name2); + } + closedir(dir); + } + + /* No dup found */ + return 0; /* "run_event, please continue iterating" */ +} + +static char *do_log(char *log_line, void *param) +{ + VERB1 log("%s", log_line); + //update_client("%s", log_line); + return log_line; +} + +mw_result_t LoadDebugDump(const char *dump_dir_name, crash_data_t **crash_data) +{ + mw_result_t res; + + struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); + if (!dd) + return MW_ERROR; + struct cdump_state state; + state.uid = dd_load_text(dd, FILENAME_UID); + state.uuid = NULL; + state.crash_dump_dup_name = NULL; + char *analyzer = dd_load_text(dd, FILENAME_ANALYZER); + dd_close(dd); + + res = MW_ERROR; + + /* Run post-create event handler(s) */ + struct run_event_state *run_state = new_run_event_state(); + run_state->post_run_callback = is_crash_a_dup; + run_state->post_run_param = &state; + run_state->logging_callback = do_log; + int r = run_event_on_dir_name(run_state, dump_dir_name, "post-create"); + free_run_event_state(run_state); + +//TODO: consider this case: +// new dump is created, post-create detects that it is a dup, +// but then FillCrashInfo(dup_name) *FAILS*. +// In this case, we later delete damaged dup_name (right?) +// but new dump never gets its FILENAME_COUNT set! + + /* Is crash a dup? (In this case, is_crash_a_dup() should have + * aborted "post-create" event processing as soon as it saw uuid + * and determined that there is another crash with same uuid. + * In this case it sets state.crash_dump_dup_name) + */ + if (!state.crash_dump_dup_name) + { + /* No. Was there error on one of processing steps in run_event? */ + if (r != 0) + goto ret; /* yes */ + + /* Was uuid created after all? (In this case, is_crash_a_dup() + * should have fetched it and created state.uuid) + */ + if (!state.uuid) + { + /* no */ + log("Dump directory '%s' has no UUID element", dump_dir_name); + goto ret; + } + } + else + { + dump_dir_name = state.crash_dump_dup_name; + } + + /* Loads crash_data (from the *first debugdump dir* if this one is a dup) + * Returns: + * MW_OCCURRED: "crash count is != 1" (iow: it is > 1 - dup) + * MW_OK: "crash count is 1" (iow: this is a new crash, not a dup) + * else: an error code + */ + { + dd = dd_opendir(dump_dir_name, /*flags:*/ 0); + if (!dd) + { + res = MW_ERROR; + goto ret; + } + + /* Reset mode/uig/gid to correct values for all files created by event run */ + dd_sanitize_mode_and_owner(dd); + + /* Update count */ + char *count_str = dd_load_text_ext(dd, FILENAME_COUNT, DD_FAIL_QUIETLY_ENOENT); + unsigned long count = strtoul(count_str, NULL, 10); + count++; + char new_count_str[sizeof(long)*3 + 2]; + sprintf(new_count_str, "%lu", count); + dd_save_text(dd, FILENAME_COUNT, new_count_str); + dd_close(dd); + + *crash_data = FillCrashInfo(dump_dir_name); + if (*crash_data != NULL) + { + res = MW_OK; + if (count > 1) + { + log("Dump directory is a duplicate of %s", dump_dir_name); + res = MW_OCCURRED; + } + } + } + + ret: + free(state.uuid); + free(state.uid); + free(state.crash_dump_dup_name); + free(analyzer); + + return res; +} + +static crash_data_t *FillCrashInfo(const char *dump_dir_name) +{ + struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); + if (!dd) + return NULL; + + crash_data_t *crash_data = create_crash_data_from_dump_dir(dd); + char *events = list_possible_events(dd, NULL, ""); + dd_close(dd); + + add_to_crash_data_ext(crash_data, CD_EVENTS, events, + CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE); + free(events); + + add_to_crash_data_ext(crash_data, CD_DUMPDIR, dump_dir_name, + CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE); + + return crash_data; +} + +/* Remove dump dir */ +int DeleteDebugDump(const char *dump_dir_name, long caller_uid) +{ + /* If doesn't start with "DEBUG_DUMPS_DIR/"... */ + if (strncmp(dump_dir_name, DEBUG_DUMPS_DIR"/", strlen(DEBUG_DUMPS_DIR"/")) != 0 + /* or contains "/." anywhere (-> might contain ".." component) */ + || strstr(dump_dir_name + strlen(DEBUG_DUMPS_DIR), "/.") + ) { + /* Then refuse to operate on it (someone is attacking us??) */ + error_msg("Bad dump directory name '%s', not deleting", dump_dir_name); + return MW_ERROR; + } + + struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); + if (!dd) + return MW_NOENT_ERROR; + + if (caller_uid != 0) /* not called by root */ + { + char caller_uid_str[sizeof(long) * 3 + 2]; + sprintf(caller_uid_str, "%ld", caller_uid); + + char *uid = dd_load_text_ext(dd, FILENAME_UID, DD_FAIL_QUIETLY_ENOENT | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE); + /* we assume that the dump_dir can be handled by everyone if uid == NULL + * e.g: kerneloops + */ + if (uid != NULL) + { + bool uid_matches = (strcmp(uid, caller_uid_str) == 0); + free(uid); + if (!uid_matches) + { + dd_close(dd); + error_msg("Dump directory '%s' can't be accessed by user with uid %ld", dump_dir_name, caller_uid); + return 1; + } + } + } + + dd_delete(dd); + + return 0; /* success */ +} diff --git a/src/daemon/MiddleWare.cpp b/src/daemon/MiddleWare.cpp deleted file mode 100644 index d0ee40df..00000000 --- a/src/daemon/MiddleWare.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* - MiddleWare.cpp - - Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com) - Copyright (C) 2009 RedHat inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ -#include "abrtlib.h" -#include "Settings.h" -#include "comm_layer_inner.h" -#include "CommLayerServerDBus.h" -#include "MiddleWare.h" - -using namespace std; - -/** - * Get one crash info. If getting is successful, - * then crash info is filled. - * @param dump_dir_name A dump dir containing all necessary data. - * @param pCrashData A crash info. - * @return It return results of operation. See mw_result_t. - */ -static crash_data_t *FillCrashInfo(const char *dump_dir_name); - - -struct logging_state { - char *last_line; -}; - -static char *do_log_and_save_line(char *log_line, void *param) -{ - struct logging_state *l_state = (struct logging_state *)param; - - VERB1 log("%s", log_line); - update_client("%s", log_line); - free(l_state->last_line); - l_state->last_line = log_line; - return NULL; -} - - -/* We need to share some data between LoadDebugDump and is_crash_a_dup: */ -struct cdump_state { - char *uid; /* filled by LoadDebugDump */ - char *uuid; /* filled by is_crash_a_dup */ - char *crash_dump_dup_name; /* filled by is_crash_a_dup */ -}; - -static int is_crash_a_dup(const char *dump_dir_name, void *param) -{ - struct cdump_state *state = (struct cdump_state *)param; - - if (state->uuid) - return 0; /* we already checked it, don't do it again */ - - struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); - if (!dd) - return 0; /* wtf? (error, but will be handled elsewhere later) */ - state->uuid = dd_load_text_ext(dd, FILENAME_UUID, - DD_FAIL_QUIETLY_ENOENT + DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE - ); - dd_close(dd); - if (!state->uuid) - { - return 0; /* no uuid (yet), "run_event, please continue iterating" */ - } - - /* Scan crash dumps looking for a dup */ -//TODO: explain why this is safe wrt concurrent runs - DIR *dir = opendir(DEBUG_DUMPS_DIR); - if (dir != NULL) - { - struct dirent *dent; - while ((dent = readdir(dir)) != NULL) - { - if (dot_or_dotdot(dent->d_name)) - continue; /* skip "." and ".." */ - - int different; - char *uid, *uuid; - char *dump_dir_name2 = concat_path_file(DEBUG_DUMPS_DIR, dent->d_name); - - if (strcmp(dump_dir_name, dump_dir_name2) == 0) - goto next; /* we are never a dup of ourself */ - - dd = dd_opendir(dump_dir_name2, /*flags:*/ DD_FAIL_QUIETLY_ENOENT); - if (!dd) - goto next; - uid = dd_load_text(dd, FILENAME_UID); - uuid = dd_load_text(dd, FILENAME_UUID); - dd_close(dd); - different = strcmp(state->uid, uid) || strcmp(state->uuid, uuid); - free(uid); - free(uuid); - if (different) - goto next; - - state->crash_dump_dup_name = dump_dir_name2; - /* "run_event, please stop iterating": */ - return 1; - - next: - free(dump_dir_name2); - } - closedir(dir); - } - - /* No dup found */ - return 0; /* "run_event, please continue iterating" */ -} - -static char *do_log(char *log_line, void *param) -{ - VERB1 log("%s", log_line); - //update_client("%s", log_line); - return log_line; -} - -mw_result_t LoadDebugDump(const char *dump_dir_name, crash_data_t **crash_data) -{ - mw_result_t res; - - struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); - if (!dd) - return MW_ERROR; - struct cdump_state state; - state.uid = dd_load_text(dd, FILENAME_UID); - state.uuid = NULL; - state.crash_dump_dup_name = NULL; - char *analyzer = dd_load_text(dd, FILENAME_ANALYZER); - dd_close(dd); - - res = MW_ERROR; - - /* Run post-create event handler(s) */ - struct run_event_state *run_state = new_run_event_state(); - run_state->post_run_callback = is_crash_a_dup; - run_state->post_run_param = &state; - run_state->logging_callback = do_log; - int r = run_event_on_dir_name(run_state, dump_dir_name, "post-create"); - free_run_event_state(run_state); - -//TODO: consider this case: -// new dump is created, post-create detects that it is a dup, -// but then FillCrashInfo(dup_name) *FAILS*. -// In this case, we later delete damaged dup_name (right?) -// but new dump never gets its FILENAME_COUNT set! - - /* Is crash a dup? (In this case, is_crash_a_dup() should have - * aborted "post-create" event processing as soon as it saw uuid - * and determined that there is another crash with same uuid. - * In this case it sets state.crash_dump_dup_name) - */ - if (!state.crash_dump_dup_name) - { - /* No. Was there error on one of processing steps in run_event? */ - if (r != 0) - goto ret; /* yes */ - - /* Was uuid created after all? (In this case, is_crash_a_dup() - * should have fetched it and created state.uuid) - */ - if (!state.uuid) - { - /* no */ - log("Dump directory '%s' has no UUID element", dump_dir_name); - goto ret; - } - } - else - { - dump_dir_name = state.crash_dump_dup_name; - } - - /* Loads crash_data (from the *first debugdump dir* if this one is a dup) - * Returns: - * MW_OCCURRED: "crash count is != 1" (iow: it is > 1 - dup) - * MW_OK: "crash count is 1" (iow: this is a new crash, not a dup) - * else: an error code - */ - { - dd = dd_opendir(dump_dir_name, /*flags:*/ 0); - if (!dd) - { - res = MW_ERROR; - goto ret; - } - - /* Reset mode/uig/gid to correct values for all files created by event run */ - dd_sanitize_mode_and_owner(dd); - - /* Update count */ - char *count_str = dd_load_text_ext(dd, FILENAME_COUNT, DD_FAIL_QUIETLY_ENOENT); - unsigned long count = strtoul(count_str, NULL, 10); - count++; - char new_count_str[sizeof(long)*3 + 2]; - sprintf(new_count_str, "%lu", count); - dd_save_text(dd, FILENAME_COUNT, new_count_str); - dd_close(dd); - - *crash_data = FillCrashInfo(dump_dir_name); - if (*crash_data != NULL) - { - res = MW_OK; - if (count > 1) - { - log("Dump directory is a duplicate of %s", dump_dir_name); - res = MW_OCCURRED; - } - } - } - - ret: - free(state.uuid); - free(state.uid); - free(state.crash_dump_dup_name); - free(analyzer); - - return res; -} - -static crash_data_t *FillCrashInfo(const char *dump_dir_name) -{ - struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); - if (!dd) - return NULL; - - crash_data_t *crash_data = create_crash_data_from_dump_dir(dd); - char *events = list_possible_events(dd, NULL, ""); - dd_close(dd); - - add_to_crash_data_ext(crash_data, CD_EVENTS, events, - CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE); - free(events); - - add_to_crash_data_ext(crash_data, CD_DUMPDIR, dump_dir_name, - CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE); - - return crash_data; -} - -/* Remove dump dir */ -int DeleteDebugDump(const char *dump_dir_name, long caller_uid) -{ - /* If doesn't start with "DEBUG_DUMPS_DIR/"... */ - if (strncmp(dump_dir_name, DEBUG_DUMPS_DIR"/", strlen(DEBUG_DUMPS_DIR"/")) != 0 - /* or contains "/." anywhere (-> might contain ".." component) */ - || strstr(dump_dir_name + strlen(DEBUG_DUMPS_DIR), "/.") - ) { - /* Then refuse to operate on it (someone is attacking us??) */ - error_msg("Bad dump directory name '%s', not deleting", dump_dir_name); - return MW_ERROR; - } - - struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); - if (!dd) - return MW_NOENT_ERROR; - - if (caller_uid != 0) /* not called by root */ - { - char caller_uid_str[sizeof(long) * 3 + 2]; - sprintf(caller_uid_str, "%ld", caller_uid); - - char *uid = dd_load_text_ext(dd, FILENAME_UID, DD_FAIL_QUIETLY_ENOENT | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE); - /* we assume that the dump_dir can be handled by everyone if uid == NULL - * e.g: kerneloops - */ - if (uid != NULL) - { - bool uid_matches = (strcmp(uid, caller_uid_str) == 0); - free(uid); - if (!uid_matches) - { - dd_close(dd); - error_msg("Dump directory '%s' can't be accessed by user with uid %ld", dump_dir_name, caller_uid); - return 1; - } - } - } - - dd_delete(dd); - - return 0; /* success */ -} diff --git a/src/daemon/MiddleWare.h b/src/daemon/MiddleWare.h index 45055274..ef246aaf 100644 --- a/src/daemon/MiddleWare.h +++ b/src/daemon/MiddleWare.h @@ -24,6 +24,10 @@ #include "abrt_types.h" +#ifdef __cplusplus +extern "C" { +#endif + /** * An enum contains all return codes. */ @@ -48,6 +52,10 @@ typedef enum { */ mw_result_t LoadDebugDump(const char *dump_dir_name, crash_data_t **crash_data); -int DeleteDebugDump(const char *dump_dir_name, long caller_uid); +int DeleteDebugDump(const char *dump_dir_name, long caller_uid); + +#ifdef __cplusplus +} +#endif #endif /*MIDDLEWARE_H_*/ diff --git a/src/daemon/Settings.h b/src/daemon/Settings.h index 3f8af8f6..a869cfcc 100644 --- a/src/daemon/Settings.h +++ b/src/daemon/Settings.h @@ -22,9 +22,6 @@ #include "abrt_types.h" #ifdef __cplusplus - -typedef map_map_string_t map_abrt_settings_t; - extern "C" { #endif diff --git a/src/daemon/comm_layer_inner.c b/src/daemon/comm_layer_inner.c new file mode 100644 index 00000000..7cba1c9e --- /dev/null +++ b/src/daemon/comm_layer_inner.c @@ -0,0 +1,61 @@ +/* + Copyright (C) 2010 ABRT team + Copyright (C) 2010 RedHat Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "abrtlib.h" +#include "CommLayerServerDBus.h" +#include "comm_layer_inner.h" + +static char *client_name = NULL; + +/* called via [p]error_msg() */ +static void warn_client(const char *msg) +{ + const char* peer = client_name; + if (peer) + { + send_dbus_sig_Warning(msg, peer); + } +} + +void init_daemon_logging(void) +{ + g_custom_logger = &warn_client; +} + +void set_client_name(const char *name) +{ + free(client_name); + client_name = xstrdup(name); +} + +void update_client(const char *fmt, ...) +{ + const char* peer = client_name; + if (!peer) + return; + + va_list p; + va_start(p, fmt); + char *msg = xvasprintf(fmt, p); + va_end(p); + + VERB1 log("Update('%s'): %s", peer, msg); + send_dbus_sig_Update(msg, peer); + + free(msg); +} diff --git a/src/daemon/comm_layer_inner.cpp b/src/daemon/comm_layer_inner.cpp deleted file mode 100644 index 7cba1c9e..00000000 --- a/src/daemon/comm_layer_inner.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - Copyright (C) 2010 ABRT team - Copyright (C) 2010 RedHat Inc - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ -#include "abrtlib.h" -#include "CommLayerServerDBus.h" -#include "comm_layer_inner.h" - -static char *client_name = NULL; - -/* called via [p]error_msg() */ -static void warn_client(const char *msg) -{ - const char* peer = client_name; - if (peer) - { - send_dbus_sig_Warning(msg, peer); - } -} - -void init_daemon_logging(void) -{ - g_custom_logger = &warn_client; -} - -void set_client_name(const char *name) -{ - free(client_name); - client_name = xstrdup(name); -} - -void update_client(const char *fmt, ...) -{ - const char* peer = client_name; - if (!peer) - return; - - va_list p; - va_start(p, fmt); - char *msg = xvasprintf(fmt, p); - va_end(p); - - VERB1 log("Update('%s'): %s", peer, msg); - send_dbus_sig_Update(msg, peer); - - free(msg); -} -- cgit