diff options
Diffstat (limited to 'libreport/src/lib')
39 files changed, 0 insertions, 6845 deletions
diff --git a/libreport/src/lib/Makefile.am b/libreport/src/lib/Makefile.am deleted file mode 100644 index f90f2f9f..00000000 --- a/libreport/src/lib/Makefile.am +++ /dev/null @@ -1,94 +0,0 @@ -# libreport - the stuff shared among most of abrt (like xmalloc, logging) -lib_LTLIBRARIES = \ - libreport.la \ - libabrt_dbus.la - -# Not used just yet: -# time.cpp -# xconnect.cpp - -libreport_la_SOURCES = \ - xfuncs.c \ - is_in_string_list.c \ - encbase64.c \ - binhex.c \ - stdio_helpers.c \ - hash_sha1.c \ - read_write.c \ - logging.c \ - copyfd.c \ - copy_file_recursive.c \ - concat_path_file.c \ - append_to_malloced_string.c \ - overlapping_strcpy.c \ - skip_whitespace.c \ - glib_support.c \ - iso_date_string.c \ - strbuf.c \ - xatonum.c \ - spawn.c \ - dirsize.c \ - dump_dir.c \ - get_cmdline.c \ - load_plugin_settings.c \ - make_descr.c \ - run_event.c \ - problem_data.c \ - create_dump_dir.c \ - abrt_types.c \ - parse_release.c \ - parse_options.c \ - steal_directory.c \ - event_xml_parser.c \ - event_config.c \ - kernel-tainted.c \ - report.c -libreport_la_CPPFLAGS = \ - -Wall -Wwrite-strings -Werror \ - -I$(srcdir)/../include \ - -DLOCALSTATEDIR='"$(localstatedir)"' \ - -DVAR_RUN=\"$(VAR_RUN)\" \ - -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \ - -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \ - -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \ - -DCONF_DIR=\"$(CONF_DIR)\" \ - -DEVENTS_DIR=\"$(EVENTS_DIR)\" \ - -DBIN_DIR=\"$(bindir)\" \ - $(GLIB_CFLAGS) \ - -D_GNU_SOURCE -libreport_la_LDFLAGS = \ - -version-info 0:1:0 -libreport_la_LIBADD = \ - $(GLIB_LIBS) - -libreportconfdir = $(CONF_DIR) -dist_libreportconf_DATA = \ - report_event.conf - -libabrt_dbus_la_SOURCES = \ - abrt_dbus.c -libabrt_dbus_la_CPPFLAGS = \ - -I$(srcdir)/../include/report -I$(srcdir)/../include \ - -DLOCALSTATEDIR='"$(localstatedir)"' \ - -DVAR_RUN=\"$(VAR_RUN)\" \ - -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \ - -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \ - -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \ - -DCONF_DIR=\"$(CONF_DIR)\" \ - -DEVENTS_DIR=\"$(EVENTS_DIR)\" \ - $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) \ - -Wall -Wwrite-strings -Werror \ - -D_GNU_SOURCE -libabrt_dbus_la_LDFLAGS = \ - -version-info 0:1:0 -libabrt_dbus_la_LIBADD = \ - libreport.la \ - $(GLIB_LIBS) \ - $(DBUS_LIBS) - -$(DESTDIR)/$(DEBUG_DUMPS_DIR): - $(mkdir_p) '$@' -# no need to chmod it here -#chmod 1777 '$@' -install-data-local: $(DESTDIR)/$(DEBUG_DUMPS_DIR) diff --git a/libreport/src/lib/abrt_dbus.c b/libreport/src/lib/abrt_dbus.c deleted file mode 100644 index d412ad5c..00000000 --- a/libreport/src/lib/abrt_dbus.c +++ /dev/null @@ -1,623 +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 <dbus/dbus.h> -//#include "abrtlib.h" -#include "abrt_dbus.h" - -DBusConnection* g_dbus_conn; - - -/* - * Helpers for building DBus messages - */ - -//void store_bool(DBusMessageIter* iter, bool val) -//{ -// dbus_bool_t db = val; -// if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &db)) -// die_out_of_memory(); -//} -void store_int32(DBusMessageIter* iter, int32_t val) -{ - if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &val)) - die_out_of_memory(); -} -void store_uint32(DBusMessageIter* iter, uint32_t val) -{ - if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &val)) - die_out_of_memory(); -} -void store_int64(DBusMessageIter* iter, int64_t val) -{ - if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_INT64, &val)) - die_out_of_memory(); -} -void store_uint64(DBusMessageIter* iter, uint64_t val) -{ - if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &val)) - die_out_of_memory(); -} - -/* dbus daemon will simply close our connection if we send broken utf8. - * Therefore we must never do that. - */ -static char *sanitize_utf8(const char *src) -{ - const char *initial_src = src; - char *sanitized = NULL; - unsigned sanitized_pos = 0; - - while (*src) - { - int bytes = 0; - - unsigned c = (unsigned char) *src; - if (c <= 0x7f) - { - bytes = 1; - goto good_byte; - } - - /* Unicode -> utf8: */ - /* 80-7FF -> 110yyyxx 10xxxxxx */ - /* 800-FFFF -> 1110yyyy 10yyyyxx 10xxxxxx */ - /* 10000-1FFFFF -> 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx */ - /* 200000-3FFFFFF -> 111110tt 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx */ - /* 4000000-FFFFFFFF -> 111111tt 10tttttt 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx */ - do { - c <<= 1; - bytes++; - } while ((c & 0x80) && bytes < 6); - if (bytes == 1) - { - /* A bare "continuation" byte. Say, 80 */ - goto bad_byte; - } - - c = (uint8_t)(c) >> bytes; - { - const char *pp = src; - int cnt = bytes; - while (--cnt) - { - unsigned ch = (unsigned char) *++pp; - if ((ch & 0xc0) != 0x80) /* Missing "continuation" byte. Example: e0 80 */ - { - goto bad_byte; - } - c = (c << 6) + (ch & 0x3f); - } - } - /* TODO */ - /* Need to check that c isn't produced by overlong encoding */ - /* Example: 11000000 10000000 converts to NUL */ - /* 11110000 10000000 10000100 10000000 converts to 0x100 */ - /* correct encoding: 11000100 10000000 */ - if (c <= 0x7f) /* crude check: only catches bad encodings which map to chars <= 7f */ - { - goto bad_byte; - } - - good_byte: - while (--bytes >= 0) - { - c = (unsigned char) *src++; - if (sanitized) - { - sanitized = (char*) xrealloc(sanitized, sanitized_pos + 2); - sanitized[sanitized_pos++] = c; - sanitized[sanitized_pos] = '\0'; - } - } - continue; - - bad_byte: - if (!sanitized) - { - sanitized_pos = src - initial_src; - sanitized = xstrndup(initial_src, sanitized_pos); - } - sanitized = (char*) xrealloc(sanitized, sanitized_pos + 5); - sanitized[sanitized_pos++] = '['; - c = (unsigned char) *src++; - sanitized[sanitized_pos++] = "0123456789ABCDEF"[c >> 4]; - sanitized[sanitized_pos++] = "0123456789ABCDEF"[c & 0xf]; - sanitized[sanitized_pos++] = ']'; - sanitized[sanitized_pos] = '\0'; - } - - if (sanitized) - VERB2 log("note: bad utf8, converted '%s' -> '%s'", initial_src, sanitized); - - return sanitized; /* usually NULL: the whole string is ok */ -} -void store_string(DBusMessageIter* iter, const char* val) -{ - const char *sanitized = sanitize_utf8(val); - if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, sanitized ? &sanitized : &val)) - die_out_of_memory(); - free((char*)sanitized); -} - - -/* - * Helpers for parsing DBus messages - */ - -//int load_bool(DBusMessageIter* iter, bool& val) -//{ -// int type = dbus_message_iter_get_arg_type(iter); -// if (type != DBUS_TYPE_BOOLEAN) -// error_msg_and_die("%s expected in dbus message, but not found ('%c')", "bool", type); -// dbus_bool_t db; -// dbus_message_iter_get_basic(iter, &db); -// val = db; -// return dbus_message_iter_next(iter); -//} -int load_int32(DBusMessageIter* iter, int32_t *val) -{ - int type = dbus_message_iter_get_arg_type(iter); - if (type != DBUS_TYPE_INT32) - { - error_msg("%s expected in dbus message, but not found ('%c')", "int32", type); - return -1; - } - dbus_message_iter_get_basic(iter, val); - return dbus_message_iter_next(iter); -} -int load_uint32(DBusMessageIter* iter, uint32_t *val) -{ - int type = dbus_message_iter_get_arg_type(iter); - if (type != DBUS_TYPE_UINT32) - { - error_msg("%s expected in dbus message, but not found ('%c')", "uint32", type); - return -1; - } - dbus_message_iter_get_basic(iter, val); - return dbus_message_iter_next(iter); -} -int load_int64(DBusMessageIter* iter, int64_t *val) -{ - int type = dbus_message_iter_get_arg_type(iter); - if (type != DBUS_TYPE_INT64) - { - error_msg("%s expected in dbus message, but not found ('%c')", "int64", type); - return -1; - } - dbus_message_iter_get_basic(iter, val); - return dbus_message_iter_next(iter); -} -int load_uint64(DBusMessageIter* iter, uint64_t *val) -{ - int type = dbus_message_iter_get_arg_type(iter); - if (type != DBUS_TYPE_UINT64) - { - error_msg("%s expected in dbus message, but not found ('%c')", "uint64", type); - return -1; - } - dbus_message_iter_get_basic(iter, val); - return dbus_message_iter_next(iter); -} -int load_charp(DBusMessageIter* iter, const char** val) -{ - *val = NULL; - - int type = dbus_message_iter_get_arg_type(iter); - if (type != DBUS_TYPE_STRING) - { - error_msg("%s expected in dbus message, but not found ('%c')", "string", type); - return -1; - } - dbus_message_iter_get_basic(iter, val); -//log("load_charp:'%s'", *val); - return dbus_message_iter_next(iter); -} - - -/* - * Glib integration machinery - */ - -/* Callback: "glib says dbus fd is active" */ -static gboolean handle_dbus_fd(GIOChannel *gio, GIOCondition condition, gpointer data) -{ - DBusWatch *watch = (DBusWatch*)data; - - VERB3 log("%s(gio, condition:%x [bits:IN/PRI/OUT/ERR/HUP...], data)", __func__, (int)condition); - - /* Notify the D-Bus library when a previously-added watch - * is ready for reading or writing, or has an exception such as a hangup. - */ - int glib_flags = (int)condition; - int dbus_flags = 0; - if (glib_flags & G_IO_IN) dbus_flags |= DBUS_WATCH_READABLE; - if (glib_flags & G_IO_OUT) dbus_flags |= DBUS_WATCH_WRITABLE; - if (glib_flags & G_IO_ERR) dbus_flags |= DBUS_WATCH_ERROR; - if (glib_flags & G_IO_HUP) dbus_flags |= DBUS_WATCH_HANGUP; - /* - * TODO: - * If dbus_watch_handle returns FALSE, then the file descriptor - * may still be ready for reading or writing, but more memory - * is needed in order to do the reading or writing. If you ignore - * the FALSE return, your application may spin in a busy loop - * on the file descriptor until memory becomes available, - * but nothing more catastrophic should happen. - */ - dbus_watch_handle(watch, dbus_flags); - - while (dbus_connection_dispatch(g_dbus_conn) == DBUS_DISPATCH_DATA_REMAINS) - VERB3 log("%s: more data to process, looping", __func__); - return TRUE; /* "glib, do not remove this event source!" */ -} - -typedef struct watch_app_info_t -{ - GIOChannel *channel; - guint event_source_id; - bool watch_enabled; -} watch_app_info_t; -/* Callback: "dbus_watch_get_enabled() may return a different value than it did before" */ -static void toggled_watch(DBusWatch *watch, void* data) -{ - VERB3 log("%s(watch:%p, data)", __func__, watch); - - watch_app_info_t* app_info = (watch_app_info_t*)dbus_watch_get_data(watch); - if (dbus_watch_get_enabled(watch)) - { - if (!app_info->watch_enabled) - { - app_info->watch_enabled = true; - int dbus_flags = dbus_watch_get_flags(watch); - int glib_flags = 0; - if (dbus_flags & DBUS_WATCH_READABLE) glib_flags |= G_IO_IN; - if (dbus_flags & DBUS_WATCH_WRITABLE) glib_flags |= G_IO_OUT; - VERB3 log(" adding watch to glib main loop. dbus_flags:%x glib_flags:%x", dbus_flags, glib_flags); - app_info->event_source_id = g_io_add_watch(app_info->channel, (GIOCondition)glib_flags, handle_dbus_fd, watch); - } - /* else: it was already enabled */ - } - else - { - if (app_info->watch_enabled) - { - app_info->watch_enabled = false; - /* does it free the hidden GSource too? */ - VERB3 log(" removing watch from glib main loop"); - g_source_remove(app_info->event_source_id); - } - /* else: it was already disabled */ - } -} -/* Callback: "libdbus needs a new watch to be monitored by the main loop" */ -static dbus_bool_t add_watch(DBusWatch *watch, void* data) -{ - VERB3 log("%s(watch:%p, data)", __func__, watch); - - watch_app_info_t* app_info = (watch_app_info_t*)xzalloc(sizeof(*app_info)); - dbus_watch_set_data(watch, app_info, free); - - int fd = dbus_watch_get_unix_fd(watch); - VERB3 log(" dbus_watch_get_unix_fd():%d", fd); - app_info->channel = g_io_channel_unix_new(fd); - /* _unconditionally_ adding it to event loop would be an error */ - toggled_watch(watch, data); - return TRUE; -} -/* Callback: "libdbus no longer needs a watch to be monitored by the main loop" */ -static void remove_watch(DBusWatch *watch, void* data) -{ - VERB3 log("%s()", __func__); - watch_app_info_t* app_info = (watch_app_info_t*)dbus_watch_get_data(watch); - if (app_info->watch_enabled) - { - app_info->watch_enabled = false; - g_source_remove(app_info->event_source_id); - } - g_io_channel_unref(app_info->channel); -} - -/* Callback: "libdbus needs a new timeout to be monitored by the main loop" */ -static dbus_bool_t add_timeout(DBusTimeout *timeout, void* data) -{ - VERB3 log("%s()", __func__); - return TRUE; -} -/* Callback: "libdbus no longer needs a timeout to be monitored by the main loop" */ -static void remove_timeout(DBusTimeout *timeout, void* data) -{ - VERB3 log("%s()", __func__); -} -/* Callback: "dbus_timeout_get_enabled() may return a different value than it did before" */ -static void timeout_toggled(DBusTimeout *timeout, void* data) -{ -//seems to be never called, let's make it noisy - error_msg_and_die("%s(): FIXME: some dbus machinery is missing here", __func__); -} - -/* Callback: "DBusObjectPathVTable is unregistered (or its connection is freed)" */ -static void unregister_vtable(DBusConnection *conn, void* data) -{ - VERB3 log("%s()", __func__); -} - - -/* - * Simple logging handler for dbus errors. - */ -int log_dbus_error(const char *msg, DBusError *err) -{ - int ret = 0; - if (dbus_error_is_set(err)) - { - error_msg("dbus error: %s", err->message); - ret = 1; - } - if (msg) - { - error_msg(msg); - ret = 1; - } - return ret; -} - - -/* - * Initialization. Works as follows: - * - * we have a DBusConnection* (say, obtained with dbus_bus_get) - * we call dbus_connection_set_watch_functions - * libdbus calls back add_watch(watch:0x2341090, data), this watch is for writing - * we call toggled_watch, but it finds that watch is not to be enabled yet - * libdbus calls back add_watch(watch:0x23410e0, data), this watch is for reading - * we call toggled_watch, it adds watch's fd to glib main loop with POLLIN - * (note: these watches are different objects, but they have the same fd) - * we call dbus_connection_set_timeout_functions - * we call dbus_connection_register_object_path - * - * Note: if user will later call dbus_bus_request_name(conn, ...): - * libdbus calls back add_timeout() - * libdbus calls back remove_timeout() - * note - no callback to timeout_toggled()! - * (therefore there is no code yet in timeout_toggled (see above), it's not used) - */ -void attach_dbus_conn_to_glib_main_loop(DBusConnection* conn, - const char* object_path, - DBusHandlerResult (*message_received_func)(DBusConnection *conn, DBusMessage *msg, void* data) -) { - if (g_dbus_conn) - error_msg_and_die("Internal bug: can't connect to more than one dbus"); - g_dbus_conn = conn; - -//do we need this? why? -//log("dbus_connection_set_dispatch_status_function"); -// dbus_connection_set_dispatch_status_function(conn, -// dispatch, /* void dispatch(DBusConnection *conn, DBusDispatchStatus new_status, void* data) */ -// NULL, /* data */ -// NULL /* free_data_function */ -// ) - VERB3 log("dbus_connection_set_watch_functions"); - if (!dbus_connection_set_watch_functions(conn, - add_watch, - remove_watch, - toggled_watch, - NULL, /* data */ - NULL /* free_data_function */ - ) - ) { - die_out_of_memory(); - } - VERB3 log("dbus_connection_set_timeout_functions"); - if (!dbus_connection_set_timeout_functions(conn, - add_timeout, - remove_timeout, - timeout_toggled, - NULL, /* data */ - NULL /* free_data_function */ - ) - ) { - die_out_of_memory(); - } - - if (object_path && message_received_func) - { - /* Table */ - const DBusObjectPathVTable vtable = { - /* .unregister_function = */ unregister_vtable, - /* .message_function = */ message_received_func, - }; - VERB3 log("dbus_connection_register_object_path"); - if (!dbus_connection_register_object_path(conn, - object_path, - &vtable, - NULL /* data */ - ) - ) { - die_out_of_memory(); - } - } -} - - -/* - * Support functions for clients - */ - -/* helpers */ -static DBusMessage* new_call_msg(const char* method) -{ - DBusMessage* msg = dbus_message_new_method_call(ABRTD_DBUS_NAME, ABRTD_DBUS_PATH, ABRTD_DBUS_IFACE, method); - if (!msg) - die_out_of_memory(); - return msg; -} - -static DBusMessage* send_get_reply_and_unref(DBusMessage* msg) -{ - dbus_uint32_t serial; - if (TRUE != dbus_connection_send(g_dbus_conn, msg, &serial)) - error_msg_and_die("Error sending DBus message"); - dbus_message_unref(msg); - - while (true) - { - DBusMessage *received = dbus_connection_pop_message(g_dbus_conn); - if (!received) - { - if (FALSE == dbus_connection_read_write(g_dbus_conn, -1)) - error_msg_and_die("dbus connection closed"); - continue; - } - - int tp = dbus_message_get_type(received); - const char *error_str = dbus_message_get_error_name(received); -#if 0 - /* Debugging */ - printf("type:%u (CALL:%u, RETURN:%u, ERROR:%u, SIGNAL:%u)\n", tp, - DBUS_MESSAGE_TYPE_METHOD_CALL, - DBUS_MESSAGE_TYPE_METHOD_RETURN, - DBUS_MESSAGE_TYPE_ERROR, - DBUS_MESSAGE_TYPE_SIGNAL - ); - const char *sender = dbus_message_get_sender(received); - if (sender) - printf("sender: %s\n", sender); - const char *path = dbus_message_get_path(received); - if (path) - printf("path: %s\n", path); - const char *member = dbus_message_get_member(received); - if (member) - printf("member: %s\n", member); - const char *interface = dbus_message_get_interface(received); - if (interface) - printf("interface: %s\n", interface); - const char *destination = dbus_message_get_destination(received); - if (destination) - printf("destination: %s\n", destination); - if (error_str) - printf("error: '%s'\n", error_str); -#endif - - DBusError err; - dbus_error_init(&err); - - if (dbus_message_is_signal(received, ABRTD_DBUS_IFACE, "Update")) - { - const char *update_msg; - if (!dbus_message_get_args(received, &err, - DBUS_TYPE_STRING, &update_msg, - DBUS_TYPE_INVALID)) - { - error_msg_and_die("dbus Update message: arguments mismatch"); - } - printf(">> %s\n", update_msg); - } - else if (dbus_message_is_signal(received, ABRTD_DBUS_IFACE, "Warning")) - { - const char *warning_msg; - if (!dbus_message_get_args(received, &err, - DBUS_TYPE_STRING, &warning_msg, - DBUS_TYPE_INVALID)) - { - error_msg_and_die("dbus Warning message: arguments mismatch"); - } - log(">! %s", warning_msg); - } - else - if (tp == DBUS_MESSAGE_TYPE_METHOD_RETURN - && dbus_message_get_reply_serial(received) == serial - ) { - return received; - } - else - if (tp == DBUS_MESSAGE_TYPE_ERROR - && dbus_message_get_reply_serial(received) == serial - ) { - error_msg_and_die("dbus call returned error: '%s'", error_str); - } - - dbus_message_unref(received); - } -} - -int32_t call_DeleteDebugDump(const char *dump_dir_name) -{ - DBusMessage* msg = new_call_msg(__func__ + 5); - dbus_message_append_args(msg, - DBUS_TYPE_STRING, &dump_dir_name, - DBUS_TYPE_INVALID); - - DBusMessage *reply = send_get_reply_and_unref(msg); - - DBusMessageIter in_iter; - dbus_message_iter_init(reply, &in_iter); - - int32_t result; - int r = load_int32(&in_iter, &result); - if (r != ABRT_DBUS_LAST_FIELD) /* more values present, or bad type */ - error_msg_and_die("dbus call %s: return type mismatch", __func__ + 5); - - dbus_message_unref(reply); - return result; -} - -static int connect_to_abrtd_and_call_DeleteDebugDump(const char *dump_dir_name) -{ - DBusError err; - dbus_error_init(&err); - g_dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); - if (log_dbus_error( - g_dbus_conn ? NULL : - "error requesting system DBus, possible reasons: " - "dbus config is incorrect; dbus-daemon is not running, " - "or dbus daemon needs to be restarted to reload dbus config", - &err - ) - ) { - if (g_dbus_conn) - dbus_connection_unref(g_dbus_conn); - g_dbus_conn = NULL; - return 1; - } - - int ret = call_DeleteDebugDump(dump_dir_name); - if (ret == ENOENT) - error_msg("Dump directory '%s' is not found", dump_dir_name); - else if (ret != 0) - error_msg("Can't delete dump directory '%s'", dump_dir_name); - - dbus_connection_unref(g_dbus_conn); - g_dbus_conn = NULL; - - return ret; -} - -int delete_dump_dir_possibly_using_abrtd(const char *dump_dir_name) -{ - /* Try to delete it ourselves */ - struct dump_dir *dd = dd_opendir(dump_dir_name, DD_OPEN_READONLY); - if (dd) - { - if (dd->locked) /* it is not readonly */ - return dd_delete(dd); - dd_close(dd); - } - - VERB1 log("Deleting '%s' via abrtd dbus call", dump_dir_name); - return connect_to_abrtd_and_call_DeleteDebugDump(dump_dir_name); -} diff --git a/libreport/src/lib/abrt_types.c b/libreport/src/lib/abrt_types.c deleted file mode 100644 index 0b51821d..00000000 --- a/libreport/src/lib/abrt_types.c +++ /dev/null @@ -1,37 +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 "libreport.h" - -map_string_h *new_map_string(void) -{ - return g_hash_table_new_full(g_str_hash, g_str_equal, free, free); -} - -void free_map_string(map_string_h *ms) -{ - if (ms) - g_hash_table_destroy(ms); -} - -const char *get_map_string_item_or_empty(map_string_h *ms, const char *key) -{ - const char *v = (const char*)g_hash_table_lookup(ms, key); - if (!v) v = ""; - return v; -} diff --git a/libreport/src/lib/append_to_malloced_string.c b/libreport/src/lib/append_to_malloced_string.c deleted file mode 100644 index c55a258f..00000000 --- a/libreport/src/lib/append_to_malloced_string.c +++ /dev/null @@ -1,27 +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 "libreport.h" - -char *append_to_malloced_string(char *mstr, const char *append) -{ - unsigned mlen = strlen(mstr); - mstr = (char*) xrealloc(mstr, mlen + strlen(append) + 1); - strcpy(mstr + mlen, append); - return mstr; -} diff --git a/libreport/src/lib/binhex.c b/libreport/src/lib/binhex.c deleted file mode 100644 index 238fda0c..00000000 --- a/libreport/src/lib/binhex.c +++ /dev/null @@ -1,74 +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 version 2 - as published by the Free Software Foundation. - - 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 "libreport.h" - -static const char hexdigits_locase[] = "0123456789abcdef"; - -/* Emit a string of hex representation of bytes */ -char *bin2hex(char *dst, const char *str, int count) -{ - while (count) { - unsigned char c = *str++; - /* put lowercase hex digits */ - *dst++ = hexdigits_locase[c >> 4]; - *dst++ = hexdigits_locase[c & 0xf]; - count--; - } - return dst; -} - -/* Convert "xxxxxxxx" hex string to binary, no more than COUNT bytes */ -char *hex2bin(char *dst, const char *str, int count) -{ - /* Parts commented out with // allow parsing - * of strings like "xx:x:x:xx:xx:xx:xxxxxx" - * (IPv6, ethernet addresses and the like). - */ - errno = EINVAL; - while (*str && count) { - uint8_t val; - uint8_t c; - - c = *str++; - if (isdigit(c)) - val = c - '0'; - else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') - val = (c|0x20) - ('a' - 10); - else - return NULL; - val <<= 4; - c = *str; - if (isdigit(c)) - val |= c - '0'; - else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') - val |= (c|0x20) - ('a' - 10); - //else if (c == ':' || c == '\0') - // val >>= 4; - else - return NULL; - - *dst++ = val; - //if (c != '\0') - str++; - //if (*str == ':') - // str++; - count--; - } - errno = (*str ? ERANGE : 0); - return dst; -} diff --git a/libreport/src/lib/concat_path_file.c b/libreport/src/lib/concat_path_file.c deleted file mode 100644 index a17739e3..00000000 --- a/libreport/src/lib/concat_path_file.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Utility routines. - * - * Copyright (C) 2001 Erik Andersen - * - * Licensed under GPLv2 or later. - */ - -/* Concatenate path and filename to new allocated buffer. - * Add '/' only as needed (no duplicate // are produced). - * If path is NULL, it is assumed to be "/". - * filename should not be NULL. - */ - -#include "libreport.h" - -char *concat_path_file(const char *path, const char *filename) -{ - if (!path) - path = ""; - const char *end = path + strlen(path); - while (*filename == '/') - filename++; - return xasprintf("%s%s%s", path, (end != path && end[-1] != '/' ? "/" : ""), filename); -} diff --git a/libreport/src/lib/copy_file_recursive.c b/libreport/src/lib/copy_file_recursive.c deleted file mode 100644 index ebfd8dae..00000000 --- a/libreport/src/lib/copy_file_recursive.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - Copyright (C) 2011 ABRT team - Copyright (C) 2011 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 "libreport.h" - -int copy_file_recursive(const char *source, const char *dest) -{ - /* This is a recursive function, try to minimize stack usage */ - /* NB: each struct stat is ~100 bytes */ - struct stat source_stat; - struct stat dest_stat; - int retval = 0; - int dest_exists = 0; - - if (strcmp(source, ".lock") == 0) - goto skip; - - if (stat(source, &source_stat) < 0) { - perror_msg("Can't stat '%s'", source); - return -1; - } - - if (lstat(dest, &dest_stat) < 0) { - if (errno != ENOENT) { - perror_msg("Can't stat '%s'", dest); - return -1; - } - } else { - if (source_stat.st_dev == dest_stat.st_dev - && source_stat.st_ino == dest_stat.st_ino - ) { - error_msg("'%s' and '%s' are the same file", source, dest); - return -1; - } - dest_exists = 1; - } - - if (S_ISDIR(source_stat.st_mode)) { - DIR *dp; - struct dirent *d; - - if (dest_exists) { - if (!S_ISDIR(dest_stat.st_mode)) { - error_msg("Target '%s' is not a directory", dest); - return -1; - } - /* race here: user can substitute a symlink between - * this check and actual creation of files inside dest */ - } else { - /* Create DEST */ - mode_t mode = source_stat.st_mode; - /* Allow owner to access new dir (at least for now) */ - mode |= S_IRWXU; - if (mkdir(dest, mode) < 0) { - perror_msg("Can't create directory '%s'", dest); - return -1; - } - } - /* Recursively copy files in SOURCE */ - dp = opendir(source); - if (dp == NULL) { - retval = -1; - goto ret; - } - - while (retval == 0 && (d = readdir(dp)) != NULL) { - char *new_source, *new_dest; - - if (dot_or_dotdot(d->d_name)) - continue; - new_source = concat_path_file(source, d->d_name); - new_dest = concat_path_file(dest, d->d_name); - if (copy_file_recursive(new_source, new_dest) < 0) - retval = -1; - free(new_source); - free(new_dest); - } - closedir(dp); - - goto ret; - } - - if (S_ISREG(source_stat.st_mode)) { - int src_fd; - int dst_fd; - mode_t new_mode; - - src_fd = open(source, O_RDONLY); - if (src_fd < 0) { - perror_msg("Can't open '%s'", source); - return -1; - } - - /* Do not try to open with weird mode fields */ - new_mode = source_stat.st_mode; - - // security problem versus (sym)link attacks - // dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode); - /* safe way: */ - dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode); - if (dst_fd < 0) { - close(src_fd); - return -1; - } - - if (copyfd_eof(src_fd, dst_fd, COPYFD_SPARSE) == -1) - retval = -1; - close(src_fd); - /* Careful: do check that buffered writes succeeded... */ - if (close(dst_fd) < 0) { - perror_msg("Error writing to '%s'", dest); - retval = -1; - } else { - /* (Try to) copy atime and mtime */ - struct timeval atime_mtime[2]; - atime_mtime[0].tv_sec = source_stat.st_atime; - // note: if "st_atim.tv_nsec" doesn't compile, try "st_atimensec": - atime_mtime[0].tv_usec = source_stat.st_atim.tv_nsec / 1000; - atime_mtime[1].tv_sec = source_stat.st_mtime; - atime_mtime[1].tv_usec = source_stat.st_mtim.tv_nsec / 1000; - // note: can use utimensat when it is more widely supported: - utimes(dest, atime_mtime); - } - goto ret; - } - - /* Neither dir not regular file: skip */ - - skip: - log("Skipping '%s'", source); - ret: - return retval; -} diff --git a/libreport/src/lib/copyfd.c b/libreport/src/lib/copyfd.c deleted file mode 100644 index 8d805069..00000000 --- a/libreport/src/lib/copyfd.c +++ /dev/null @@ -1,172 +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. -*/ - -/* - * Utility routines. - * - */ -#include "libreport.h" - -#define CONFIG_FEATURE_COPYBUF_KB 4 - -static const char msg_write_error[] = "write error"; -static const char msg_read_error[] = "read error"; - -static off_t full_fd_action(int src_fd, int dst_fd, off_t size, int flags) -{ - int status = -1; - off_t total = 0; - int last_was_seek = 0; -#if CONFIG_FEATURE_COPYBUF_KB <= 4 - char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024]; - enum { buffer_size = sizeof(buffer) }; -#else - char *buffer; - int buffer_size; - - /* We want page-aligned buffer, just in case kernel is clever - * and can do page-aligned io more efficiently */ - buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, - /* ignored: */ -1, 0); - buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024; - if (buffer == MAP_FAILED) { - buffer = alloca(4 * 1024); - buffer_size = 4 * 1024; - } -#endif - - if (src_fd < 0) - goto out; - - if (!size) { - size = buffer_size; - status = 1; /* copy until eof */ - } - - while (1) { - ssize_t rd; - - rd = safe_read(src_fd, buffer, size > buffer_size ? buffer_size : size); - - if (!rd) { /* eof - all done */ - if (last_was_seek) { - if (lseek(dst_fd, -1, SEEK_CUR) < 0 - || safe_write(dst_fd, "", 1) != 1 - ) { - perror_msg("%s", msg_write_error); - break; - } - } - status = 0; - break; - } - if (rd < 0) { - perror_msg("%s", msg_read_error); - break; - } - /* dst_fd == -1 is a fake, else... */ - if (dst_fd >= 0) { - if (flags & COPYFD_SPARSE) { - ssize_t cnt = rd; - while (--cnt >= 0) - if (buffer[cnt] != 0) - goto need2write; - if (lseek(dst_fd, rd, SEEK_CUR) < 0) { - flags &= ~COPYFD_SPARSE; - goto need2write; - } - last_was_seek = 1; - } else { - need2write: - { - ssize_t wr = full_write(dst_fd, buffer, rd); - if (wr < rd) { - perror_msg("%s", msg_write_error); - break; - } - last_was_seek = 0; - } - } - } - total += rd; - if (status < 0) { /* if we aren't copying till EOF... */ - size -= rd; - if (!size) { - /* 'size' bytes copied - all done */ - status = 0; - break; - } - } - } - out: - -#if CONFIG_FEATURE_COPYBUF_KB > 4 - if (buffer_size != 4 * 1024) - munmap(buffer, buffer_size); -#endif - return status ? -1 : total; -} - -off_t copyfd_size(int fd1, int fd2, off_t size, int flags) -{ - if (size) { - return full_fd_action(fd1, fd2, size, flags); - } - return 0; -} - -void copyfd_exact_size(int fd1, int fd2, off_t size) -{ - off_t sz = copyfd_size(fd1, fd2, size, /*flags:*/ 0); - if (sz == size) - return; - if (sz != -1) - error_msg_and_die("short read"); - /* if sz == -1, copyfd_XX already complained */ - xfunc_die(); -} - -off_t copyfd_eof(int fd1, int fd2, int flags) -{ - return full_fd_action(fd1, fd2, 0, flags); -} - -off_t copy_file(const char *src_name, const char *dst_name, int mode) -{ - off_t r; - int src = open(src_name, O_RDONLY); - if (src < 0) - { - perror_msg("Can't open '%s'", src_name); - return -1; - } - int dst = open(dst_name, O_WRONLY | O_TRUNC | O_CREAT, mode); - if (dst < 0) - { - close(src); - perror_msg("Can't open '%s'", dst_name); - return -1; - } - r = copyfd_eof(src, dst, /*flags:*/ 0); - close(src); - close(dst); - return r; -} diff --git a/libreport/src/lib/create_dump_dir.c b/libreport/src/lib/create_dump_dir.c deleted file mode 100644 index 33d9bd7c..00000000 --- a/libreport/src/lib/create_dump_dir.c +++ /dev/null @@ -1,85 +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 "libreport.h" - -static struct dump_dir *try_dd_create(const char *base_dir_name, const char *dir_name) -{ - char *path = concat_path_file(base_dir_name, dir_name); - struct dump_dir *dd = dd_create(path, (uid_t)-1L, 0640); - if (dd) - dd_create_basic_files(dd, (uid_t)-1L); - free(path); - return dd; -} - -struct dump_dir *create_dump_dir_from_problem_data(problem_data_t *problem_data, const char *base_dir_name) -{ - char dir_name[sizeof("abrt-tmp-YYYY-MM-DD-HH:MM:SS-%lu") + sizeof(long)*3]; - sprintf(dir_name, "abrt-tmp-%s-%lu", iso_date_string(NULL), (long)getpid()); - - struct dump_dir *dd; - if (base_dir_name) - dd = try_dd_create(base_dir_name, dir_name); - else - { - /* Try /var/run/abrt */ - dd = try_dd_create(LOCALSTATEDIR"/run/abrt", dir_name); - /* Try $HOME/tmp */ - if (!dd) - { - char *home = getenv("HOME"); - if (home && home[0]) - { - home = concat_path_file(home, "tmp"); - /*mkdir(home, 0777); - do we want this? */ - dd = try_dd_create(home, dir_name); - free(home); - } - } -//TODO: try user's home dir obtained by getpwuid(getuid())? - /* Try /tmp */ - if (!dd) - dd = try_dd_create("/tmp", dir_name); - } - if (!dd) - return NULL; - - GHashTableIter iter; - char *name; - struct problem_item *value; - g_hash_table_iter_init(&iter, problem_data); - while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value)) - { - if (name[0] == '.' || strchr(name, '/')) - { - error_msg("Problem data field name contains disallowed chars: '%s'", name); - goto next; - } - -//FIXME: what to do with CD_FLAG_BINs?? - if (value->flags & CD_FLAG_BIN) - goto next; - - dd_save_text(dd, name, value->content); - next: ; - } - - return dd; -} diff --git a/libreport/src/lib/daemon_is_ok.c b/libreport/src/lib/daemon_is_ok.c deleted file mode 100644 index b4856b14..00000000 --- a/libreport/src/lib/daemon_is_ok.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - 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 "libreport.h" - -int daemon_is_ok() -{ - int fd = open(VAR_RUN"/abrtd.pid", O_RDONLY); - if (fd < 0) - { - return 0; - } - - char pid[sizeof(pid_t)*3 + 2]; - int len = read(fd, pid, sizeof(pid)-1); - close(fd); - if (len <= 0) - return 0; - - pid[len] = '\0'; - *strchrnul(pid, '\n') = '\0'; - /* paranoia: we don't want to check /proc//stat or /proc///stat */ - if (pid[0] == '\0' || pid[0] == '/') - return 0; - - char path[sizeof("/proc/%s/stat") + sizeof(pid)]; - sprintf(path, "/proc/%s/stat", pid); - struct stat sb; - if (stat(path, &sb) == -1) - { - return 0; - } - - /* TODO: maybe readlink /proc/PID/exe and check that it is "xxx/abrt"? */ - - return 1; -} diff --git a/libreport/src/lib/dirsize.c b/libreport/src/lib/dirsize.c deleted file mode 100644 index 88733ae0..00000000 --- a/libreport/src/lib/dirsize.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - Copyright (C) 2009 Jiri Moskovcak (jmoskovc@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 "libreport.h" - -double get_dirsize(const char *pPath) -{ - DIR *dp = opendir(pPath); - if (dp == NULL) - return 0; - - struct dirent *ep; - struct stat statbuf; - double size = 0; - while ((ep = readdir(dp)) != NULL) - { - if (dot_or_dotdot(ep->d_name)) - continue; - char *dname = concat_path_file(pPath, ep->d_name); - if (lstat(dname, &statbuf) != 0) - { - free(dname); - continue; - } - if (S_ISDIR(statbuf.st_mode)) - { - size += get_dirsize(dname); - } - else if (S_ISREG(statbuf.st_mode)) - { - size += statbuf.st_size; - } - free(dname); - } - closedir(dp); - return size; -} - -double get_dirsize_find_largest_dir( - const char *pPath, - char **worst_dir, - const char *excluded) -{ - if (worst_dir) - *worst_dir = NULL; - - DIR *dp = opendir(pPath); - if (dp == NULL) - return 0; - - struct dirent *ep; - struct stat statbuf; - double size = 0; - double maxsz = 0; - while ((ep = readdir(dp)) != NULL) - { - if (dot_or_dotdot(ep->d_name)) - continue; - char *dname = concat_path_file(pPath, ep->d_name); - if (lstat(dname, &statbuf) != 0) - { - free(dname); - continue; - } - if (S_ISDIR(statbuf.st_mode)) - { - double sz = get_dirsize(dname); - size += sz; - - if (worst_dir && (!excluded || strcmp(excluded, ep->d_name) != 0)) - { - /* Calculate "weighted" size and age - * w = sz_kbytes * age_mins */ - sz /= 1024; - long age = (time(NULL) - statbuf.st_mtime) / 60; - if (age > 0) - sz *= age; - - if (sz > maxsz) - { - maxsz = sz; - free(*worst_dir); - *worst_dir = xstrdup(ep->d_name); - } - } - } - else if (S_ISREG(statbuf.st_mode)) - { - size += statbuf.st_size; - } - free(dname); - } - closedir(dp); - return size; -} diff --git a/libreport/src/lib/dump_dir.c b/libreport/src/lib/dump_dir.c deleted file mode 100644 index 8891f911..00000000 --- a/libreport/src/lib/dump_dir.c +++ /dev/null @@ -1,839 +0,0 @@ -/* - 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 <sys/utsname.h> -#include "libreport.h" -#include "strbuf.h" - -// Locking logic: -// -// The directory is locked by creating a symlink named .lock inside it, -// whose value (where it "points to") is the pid of locking process. -// We use symlink, not an ordinary file, because symlink creation -// is an atomic operation. -// -// There are two cases where after .lock creation, we might discover -// that directory is not really free: -// * another process just created new directory, but didn't manage -// to lock it before us. -// * another process is deleting the directory, and we managed to sneak in -// and create .lock after it deleted all files (including .lock) -// but before it rmdir'ed the empty directory. -// -// Both these cases are detected by the fact that file named "time" -// is not present (it must be present in any valid dump dir). -// If after locking the dir we don't see time file, we remove the lock -// at once and back off. What happens in concurrent processes -// we interfered with? -// * "create new dump dir" process just re-tries locking. -// * "delete dump dir" process just retries rmdir. -// -// There is another case when we don't find time file: -// when the directory is not really a *dump* dir - user gave us -// an ordinary directory name by mistake. -// We detect it by bailing out of "lock, check time file; sleep -// and retry if it doesn't exist" loop using a counter. -// -// To make locking work reliably, it's important to set timeouts -// correctly. For example, dd_create should retry locking -// its newly-created directory much faster than dd_opendir -// tries to lock the directory it tries to open. - - -// How long to sleep between "symlink fails with EEXIST, -// readlink fails with ENOENT" tries. Someone just unlocked the dir. -// We never bail out in this case, we retry forever. -// The value can be really small: -#define SYMLINK_RETRY_USLEEP (10*1000) - -// How long to sleep when lock file with valid pid is seen by dd_opendir -// (we are waiting for other process to unlock or die): -#define WAIT_FOR_OTHER_PROCESS_USLEEP (500*1000) - -// How long to sleep when lock file with valid pid is seen by dd_create -// (some idiot jumped the gun and locked the dir we just created). -// Must not be the same as WAIT_FOR_OTHER_PROCESS_USLEEP (we depend on this) -// and should be small (we have the priority in locking, this is OUR dir): -#define CREATE_LOCK_USLEEP (10*1000) - -// How long to sleep after we locked a dir, found no time file -// (either we are racing with someone, or it's not a dump dir) -// and unlocked it; -// and after how many tries to give up and declare it's not a dump dir: -#define NO_TIME_FILE_USLEEP (50*1000) -#define NO_TIME_FILE_COUNT 10 - -// How long to sleep after we unlocked an empty dir, but then rmdir failed -// (some idiot jumped the gun and locked the dir we are deleting); -// and after how many tries to give up: -#define RMDIR_FAIL_USLEEP (10*1000) -#define RMDIR_FAIL_COUNT 50 - - -static char *load_text_file(const char *path, unsigned flags); - -static bool isdigit_str(const char *str) -{ - do - { - if (*str < '0' || *str > '9') return false; - str++; - } while (*str); - return true; -} - -static bool exist_file_dir(const char *path) -{ - struct stat buf; - if (stat(path, &buf) == 0) - { - if (S_ISDIR(buf.st_mode) || S_ISREG(buf.st_mode)) - { - return true; - } - } - return false; -} - -/* Return values: - * -1: error (in this case, errno is 0 if error message is already logged) - * 0: failed to lock (someone else has it locked) - * 1: success - */ -static int get_and_set_lock(const char* lock_file, const char* pid) -{ - while (symlink(pid, lock_file) != 0) - { - if (errno != EEXIST) - { - if (errno != ENOENT && errno != ENOTDIR && errno != EACCES) - { - perror_msg("Can't create lock file '%s'", lock_file); - errno = 0; - } - return -1; - } - - char pid_buf[sizeof(pid_t)*3 + 4]; - ssize_t r = readlink(lock_file, pid_buf, sizeof(pid_buf) - 1); - if (r < 0) - { - if (errno == ENOENT) - { - /* Looks like lock_file was deleted */ - usleep(SYMLINK_RETRY_USLEEP); /* avoid CPU eating loop */ - continue; - } - perror_msg("Can't read lock file '%s'", lock_file); - errno = 0; - return -1; - } - pid_buf[r] = '\0'; - - if (strcmp(pid_buf, pid) == 0) - { - log("Lock file '%s' is already locked by us", lock_file); - return 0; - } - if (isdigit_str(pid_buf)) - { - char pid_str[sizeof("/proc/") + sizeof(pid_buf)]; - sprintf(pid_str, "/proc/%s", pid_buf); - if (access(pid_str, F_OK) == 0) - { - log("Lock file '%s' is locked by process %s", lock_file, pid_buf); - return 0; - } - log("Lock file '%s' was locked by process %s, but it crashed?", lock_file, pid_buf); - } - /* The file may be deleted by now by other process. Ignore ENOENT */ - if (unlink(lock_file) != 0 && errno != ENOENT) - { - perror_msg("Can't remove stale lock file '%s'", lock_file); - errno = 0; - return -1; - } - } - - VERB1 log("Locked '%s'", lock_file); - return 1; -} - -static int dd_lock(struct dump_dir *dd, unsigned sleep_usec, int flags) -{ - if (dd->locked) - error_msg_and_die("Locking bug on '%s'", dd->dd_dirname); - - char pid_buf[sizeof(long)*3 + 2]; - sprintf(pid_buf, "%lu", (long)getpid()); - - unsigned dirname_len = strlen(dd->dd_dirname); - char lock_buf[dirname_len + sizeof("/.lock")]; - strcpy(lock_buf, dd->dd_dirname); - strcpy(lock_buf + dirname_len, "/.lock"); - - unsigned count = NO_TIME_FILE_COUNT; - retry: - while (1) - { - int r = get_and_set_lock(lock_buf, pid_buf); - if (r < 0) - return r; /* error */ - if (r > 0) - break; /* locked successfully */ - /* Other process has the lock, wait for it to go away */ - usleep(sleep_usec); - } - - /* Are we called by dd_opendir (as opposed to dd_create)? */ - if (sleep_usec == WAIT_FOR_OTHER_PROCESS_USLEEP) /* yes */ - { - strcpy(lock_buf + dirname_len, "/time"); - if (access(lock_buf, F_OK) != 0) - { - /* time file doesn't exist. We managed to lock the directory - * which was just created by somebody else, or is almost deleted - * by delete_file_dir. - * Unlock and back off. - */ - strcpy(lock_buf + dirname_len, "/.lock"); - xunlink(lock_buf); - VERB1 log("Unlocked '%s' (no time file)", lock_buf); - if (--count == 0) - { - errno = EISDIR; /* "this is an ordinary dir, not dump dir" */ - return -1; - } - usleep(NO_TIME_FILE_USLEEP); - goto retry; - } - } - - dd->locked = true; - return 0; -} - -static void dd_unlock(struct dump_dir *dd) -{ - if (dd->locked) - { - dd->locked = 0; - - unsigned dirname_len = strlen(dd->dd_dirname); - char lock_buf[dirname_len + sizeof("/.lock")]; - strcpy(lock_buf, dd->dd_dirname); - strcpy(lock_buf + dirname_len, "/.lock"); - xunlink(lock_buf); - - VERB1 log("Unlocked '%s'", lock_buf); - } -} - -static inline struct dump_dir *dd_init(void) -{ - return (struct dump_dir*)xzalloc(sizeof(struct dump_dir)); -} - -int dd_exist(struct dump_dir *dd, const char *path) -{ - char *full_path = concat_path_file(dd->dd_dirname, path); - int ret = exist_file_dir(full_path); - free(full_path); - return ret; -} - -void dd_close(struct dump_dir *dd) -{ - if (!dd) - return; - - dd_unlock(dd); - if (dd->next_dir) - { - closedir(dd->next_dir); - /* free(dd->next_dir); - WRONG! */ - } - - free(dd->dd_dirname); - free(dd); -} - -static char* rm_trailing_slashes(const char *dir) -{ - unsigned len = strlen(dir); - while (len != 0 && dir[len-1] == '/') - len--; - return xstrndup(dir, len); -} - -struct dump_dir *dd_opendir(const char *dir, int flags) -{ - struct dump_dir *dd = dd_init(); - - dir = dd->dd_dirname = rm_trailing_slashes(dir); - - struct stat stat_buf; - stat(dir, &stat_buf); - /* & 0666 should remove the executable bit */ - dd->mode = (stat_buf.st_mode & 0666); - - errno = 0; - if (dd_lock(dd, WAIT_FOR_OTHER_PROCESS_USLEEP, flags) < 0) - { - if ((flags & DD_OPEN_READONLY) && errno == EACCES) - { - /* Directory is not writable. If it seems to be readable, - * return "read only" dd, not NULL */ - if (stat(dir, &stat_buf) == 0 - && S_ISDIR(stat_buf.st_mode) - && access(dir, R_OK) == 0 - ) { - return dd; - } - } - if (errno == EISDIR) - { - /* EISDIR: dd_lock can lock the dir, but it sees no time file there, - * even after it retried many times. It must be an ordinary directory! - * - * Without this check, e.g. abrt-action-print happily prints any current - * directory when run without arguments, because its option -d DIR - * defaults to "."! - */ - error_msg("'%s' is not a dump directory", dir); - } - else if (errno == ENOENT || errno == ENOTDIR) - { - if (!(flags & DD_FAIL_QUIETLY_ENOENT)) - error_msg("'%s' does not exist", dir); - } - else - { - if (!(flags & DD_FAIL_QUIETLY_EACCES)) - perror_msg("Can't access '%s'", dir); - } - dd_close(dd); - return NULL; - } - - dd->dd_uid = (uid_t)-1L; - dd->dd_gid = (gid_t)-1L; - if (geteuid() == 0) - { - /* In case caller would want to create more files, he'll need uid:gid */ - struct stat stat_buf; - if (stat(dir, &stat_buf) != 0 || !S_ISDIR(stat_buf.st_mode)) - { - error_msg("Can't stat '%s', or it is not a directory", dir); - dd_close(dd); - return NULL; - } - dd->dd_uid = stat_buf.st_uid; - dd->dd_gid = stat_buf.st_gid; - } - - return dd; -} - -/* Create a fresh empty debug dump dir. - * - * Security: we should not allow users to write new files or write - * into existing ones, but they should be able to read them. - * - * @param uid - * Crashed application's User Id - * - * We currently have only three callers: - * kernel oops hook: uid -> not saved, so everyone can steal and work with it - * this hook runs under 0:0 - * ccpp hook: uid=uid of crashed user's binary - * this hook runs under 0:0 - * python hook: uid=uid of crashed user's script - * this hook runs under abrt:gid - * - * Currently, we set dir's gid to passwd(uid)->pw_gid parameter, and we set uid to - * abrt's user id. We do not allow write access to group. - */ -struct dump_dir *dd_create(const char *dir, uid_t uid, mode_t mode) -{ - /* a little trick to copy read bits from file mode to exec bit of dir mode*/ - mode_t dir_mode = mode | ((mode & 0444) >> 2); - struct dump_dir *dd = dd_init(); - - dd->mode = mode; - - /* Unlike dd_opendir, can't use realpath: the directory doesn't exist yet, - * realpath will always return NULL. We don't really have to: - * dd_opendir(".") makes sense, dd_create(".") does not. - */ - dir = dd->dd_dirname = rm_trailing_slashes(dir); - - const char *last_component = strrchr(dir, '/'); - if (last_component) - last_component++; - else - last_component = dir; - if (dot_or_dotdot(last_component)) - { - /* dd_create("."), dd_create(".."), dd_create("dir/."), - * dd_create("dir/..") and similar are madness, refuse them. - */ - error_msg("Bad dir name '%s'", dir); - dd_close(dd); - return NULL; - } - - bool created_parents = false; - try_again: - /* Was creating it with mode 0700 and user as the owner, but this allows - * the user to replace any file in the directory, changing security-sensitive data - * (e.g. "uid", "analyzer", "executable") - */ - if (mkdir(dir, dir_mode) == -1) - { - int err = errno; - if (!created_parents && errno == ENOENT) - { - char *p = dd->dd_dirname + 1; - while ((p = strchr(p, '/')) != NULL) - { - *p = '\0'; - int r = (mkdir(dd->dd_dirname, 0755) == 0 || errno == EEXIST); - *p++ = '/'; - if (!r) - goto report_err; - } - created_parents = true; - goto try_again; - } - report_err: - errno = err; - perror_msg("Can't create directory '%s'", dir); - dd_close(dd); - return NULL; - } - - if (dd_lock(dd, CREATE_LOCK_USLEEP, /*flags:*/ 0) < 0) - { - dd_close(dd); - return NULL; - } - - /* mkdir's mode (above) can be affected by umask, fix it */ - if (chmod(dir, dir_mode) == -1) - { - perror_msg("can't change mode of '%s'", dir); - dd_close(dd); - return NULL; - } - - dd->dd_uid = (uid_t)-1L; - dd->dd_gid = (gid_t)-1L; - if (uid != (uid_t)-1L) - { - /* Get ABRT's user id */ - dd->dd_uid = 0; - struct passwd *pw = getpwnam("abrt"); - if (pw) - dd->dd_uid = pw->pw_uid; - else - error_msg("user 'abrt' does not exist, using uid 0"); - - /* Get crashed application's group id */ - /*dd->dd_gid = 0; - dd_init did this already */ - pw = getpwuid(uid); - if (pw) - dd->dd_gid = pw->pw_gid; - else - error_msg("User %lu does not exist, using gid 0", (long)uid); - - if (chown(dir, dd->dd_uid, dd->dd_gid) == -1) - { - perror_msg("can't change '%s' ownership to %lu:%lu", dir, - (long)dd->dd_uid, (long)dd->dd_gid); - } - } - - return dd; -} - -void dd_create_basic_files(struct dump_dir *dd, uid_t uid) -{ - char long_str[sizeof(long) * 3 + 2]; - - time_t t = time(NULL); - sprintf(long_str, "%lu", (long)t); - dd_save_text(dd, FILENAME_TIME, long_str); - - /* it doesn't make sense to create the uid file if uid == -1 */ - if (uid != (uid_t)-1L) - { - sprintf(long_str, "%li", (long)uid); - dd_save_text(dd, FILENAME_UID, long_str); - } - - struct utsname buf; - uname(&buf); /* never fails */ - dd_save_text(dd, FILENAME_KERNEL, buf.release); - dd_save_text(dd, FILENAME_ARCHITECTURE, buf.machine); - dd_save_text(dd, FILENAME_HOSTNAME, buf.nodename); - - char *release = load_text_file("/etc/system-release", - DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE); - if (!release) - release = load_text_file("/etc/redhat-release", /*flags:*/ 0); - dd_save_text(dd, FILENAME_OS_RELEASE, release); - free(release); -} - -void dd_sanitize_mode_and_owner(struct dump_dir *dd) -{ - /* Don't sanitize if we aren't run under root: - * we assume that during file creation (by whatever means, - * even by "hostname >file" in abrt_event.conf) - * normal umask-based mode setting takes care of correct mode, - * and uid:gid is, of course, set to user's uid and gid. - * - * For root operating on /var/spool/abrt/USERS_PROBLEM, this isn't true: - * "hostname >file", for example, would create file OWNED BY ROOT! - * This routine resets mode and uid:gid for all such files. - */ - if (dd->dd_uid == (uid_t)-1) - return; - - if (!dd->locked) - error_msg_and_die("dump_dir is not opened"); /* bug */ - - DIR *d = opendir(dd->dd_dirname); - if (!d) - return; - - struct dirent *dent; - while ((dent = readdir(d)) != NULL) - { - if (dent->d_name[0] == '.') /* ".lock", ".", ".."? skip */ - continue; - char *full_path = concat_path_file(dd->dd_dirname, dent->d_name); - struct stat statbuf; - if (lstat(full_path, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) - { - if ((statbuf.st_mode & 0777) != dd->mode) - chmod(full_path, dd->mode); - if (statbuf.st_uid != dd->dd_uid || statbuf.st_gid != dd->dd_gid) - { - if (chown(full_path, dd->dd_uid, dd->dd_gid) != 0) - { - perror_msg("can't change '%s' ownership to %lu:%lu", full_path, - (long)dd->dd_uid, (long)dd->dd_gid); - } - } - } - free(full_path); - } - closedir(d); -} - -static int delete_file_dir(const char *dir, bool skip_lock_file) -{ - DIR *d = opendir(dir); - if (!d) - { - /* The caller expects us to error out only if the directory - * still exists (not deleted). If directory - * *doesn't exist*, return 0 and clear errno. - */ - if (errno == ENOENT || errno == ENOTDIR) - { - errno = 0; - return 0; - } - return -1; - } - - bool unlink_lock_file = false; - struct dirent *dent; - while ((dent = readdir(d)) != NULL) - { - if (dot_or_dotdot(dent->d_name)) - continue; - if (skip_lock_file && strcmp(dent->d_name, ".lock") == 0) - { - unlink_lock_file = true; - continue; - } - char *full_path = concat_path_file(dir, dent->d_name); - if (unlink(full_path) == -1 && errno != ENOENT) - { - int err = 0; - if (errno == EISDIR) - { - errno = 0; - err = delete_file_dir(full_path, /*skip_lock_file:*/ false); - } - if (errno || err) - { - perror_msg("Can't remove '%s'", full_path); - free(full_path); - closedir(d); - return -1; - } - } - free(full_path); - } - closedir(d); - - /* Here we know for sure that all files/subdirs we found via readdir - * were deleted successfully. If rmdir below fails, we assume someone - * is racing with us and created a new file. - */ - - if (unlink_lock_file) - { - char *full_path = concat_path_file(dir, ".lock"); - xunlink(full_path); - free(full_path); - - unsigned cnt = RMDIR_FAIL_COUNT; - do { - if (rmdir(dir) == 0) - return 0; - /* Someone locked the dir after unlink, but before rmdir. - * This "someone" must be dd_lock(). - * It detects this (by seeing that there is no time file) - * and backs off at once. So we need to just retry rmdir, - * with minimal sleep. - */ - usleep(RMDIR_FAIL_USLEEP); - } while (--cnt != 0); - } - - int r = rmdir(dir); - if (r) - perror_msg("Can't remove directory '%s'", dir); - return r; -} - -int dd_delete(struct dump_dir *dd) -{ - int r = delete_file_dir(dd->dd_dirname, /*skip_lock_file:*/ true); - dd->locked = 0; /* delete_file_dir already removed .lock */ - dd_close(dd); - return r; -} - -static char *load_text_file(const char *path, unsigned flags) -{ - FILE *fp = fopen(path, "r"); - if (!fp) - { - if (!(flags & DD_FAIL_QUIETLY_ENOENT)) - perror_msg("Can't open file '%s'", path); - return (flags & DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE ? NULL : xstrdup("")); - } - - struct strbuf *buf_content = strbuf_new(); - int oneline = 0; - int ch; - while ((ch = fgetc(fp)) != EOF) - { -//TODO? \r -> \n? -//TODO? strip trailing spaces/tabs? - if (ch == '\n') - oneline = (oneline << 1) | 1; - if (ch == '\0') - ch = ' '; - if (isspace(ch) || ch >= ' ') /* used !iscntrl, but it failed on unicode */ - strbuf_append_char(buf_content, ch); - } - fclose(fp); - - char last = oneline != 0 ? buf_content->buf[buf_content->len - 1] : 0; - if (last == '\n') - { - /* If file contains exactly one '\n' and it is at the end, remove it. - * This enables users to use simple "echo blah >file" in order to create - * short string items in dump dirs. - */ - if (oneline == 1) - buf_content->buf[--buf_content->len] = '\0'; - } - else /* last != '\n' */ - { - /* Last line is unterminated, fix it */ - /* Cases: */ - /* oneline=0: "qwe" - DONT fix this! */ - /* oneline=1: "qwe\nrty" - two lines in fact */ - /* oneline>1: "qwe\nrty\uio" */ - if (oneline >= 1) - strbuf_append_char(buf_content, '\n'); - } - - return strbuf_free_nobuf(buf_content); -} - -static bool save_binary_file(const char *path, const char* data, unsigned size, uid_t uid, gid_t gid, mode_t mode) -{ - /* the mode is set by the caller, see dd_create() for security analysis */ - unlink(path); - int fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode); - if (fd < 0) - { - perror_msg("Can't open file '%s'", path); - return false; - } - - if (uid != (uid_t)-1L) - { - if (fchown(fd, uid, gid) == -1) - { - perror_msg("can't change '%s' ownership to %lu:%lu", path, (long)uid, (long)gid); - } - } - - unsigned r = full_write(fd, data, size); - close(fd); - if (r != size) - { - error_msg("Can't save file '%s'", path); - return false; - } - - return true; -} - -char* dd_load_text_ext(const struct dump_dir *dd, const char *name, unsigned flags) -{ -// if (!dd->locked) -// error_msg_and_die("dump_dir is not opened"); /* bug */ - - /* Compat with old abrt dumps. Remove in abrt-2.1 */ - if (strcmp(name, "release") == 0) - name = FILENAME_OS_RELEASE; - - char *full_path = concat_path_file(dd->dd_dirname, name); - char *ret = load_text_file(full_path, flags); - free(full_path); - - return ret; -} - -char* dd_load_text(const struct dump_dir *dd, const char *name) -{ - return dd_load_text_ext(dd, name, /*flags:*/ 0); -} - -void dd_save_text(struct dump_dir *dd, const char *name, const char *data) -{ - if (!dd->locked) - error_msg_and_die("dump_dir is not opened"); /* bug */ - - char *full_path = concat_path_file(dd->dd_dirname, name); - save_binary_file(full_path, data, strlen(data), dd->dd_uid, dd->dd_gid, dd->mode); - free(full_path); -} - -void dd_save_binary(struct dump_dir* dd, const char* name, const char* data, unsigned size) -{ - if (!dd->locked) - error_msg_and_die("dump_dir is not opened"); /* bug */ - - char *full_path = concat_path_file(dd->dd_dirname, name); - save_binary_file(full_path, data, size, dd->dd_uid, dd->dd_gid, dd->mode); - free(full_path); -} - -void add_reported_to(struct dump_dir *dd, const char *line) -{ - if (!dd->locked) - error_msg_and_die("dump_dir is not opened"); /* bug */ - - char *reported_to = dd_load_text_ext(dd, FILENAME_REPORTED_TO, DD_FAIL_QUIETLY_ENOENT | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE); - if (reported_to) - { - unsigned len_line = strlen(line); - char *p = reported_to; - while (*p) - { - if (strncmp(p, line, len_line) == 0 && (p[len_line] == '\n' || p[len_line] == '\0')) - goto ret; - p = strchrnul(p, '\n'); - if (!*p) - break; - p++; - } - if (p != reported_to && p[-1] != '\n') - reported_to = append_to_malloced_string(reported_to, "\n"); - reported_to = append_to_malloced_string(reported_to, line); - reported_to = append_to_malloced_string(reported_to, "\n"); - } - else - reported_to = xasprintf("%s\n", line); - dd_save_text(dd, FILENAME_REPORTED_TO, reported_to); - ret: - free(reported_to); -} - -DIR *dd_init_next_file(struct dump_dir *dd) -{ -// if (!dd->locked) -// error_msg_and_die("dump_dir is not opened"); /* bug */ - - if (dd->next_dir) - closedir(dd->next_dir); - - dd->next_dir = opendir(dd->dd_dirname); - if (!dd->next_dir) - { - error_msg("Can't open directory '%s'", dd->dd_dirname); - } - - return dd->next_dir; -} - -int dd_get_next_file(struct dump_dir *dd, char **short_name, char **full_name) -{ - if (dd->next_dir == NULL) - return 0; - - struct dirent *dent; - while ((dent = readdir(dd->next_dir)) != NULL) - { - if (is_regular_file(dent, dd->dd_dirname)) - { - if (short_name) - *short_name = xstrdup(dent->d_name); - if (full_name) - *full_name = concat_path_file(dd->dd_dirname, dent->d_name); - return 1; - } - } - - closedir(dd->next_dir); - dd->next_dir = NULL; - return 0; -} - -/* Utility function */ -void delete_dump_dir(const char *dirname) -{ - struct dump_dir *dd = dd_opendir(dirname, /*flags:*/ 0); - if (dd) - { - dd_delete(dd); - } -} diff --git a/libreport/src/lib/encbase64.c b/libreport/src/lib/encbase64.c deleted file mode 100644 index 52e02b7f..00000000 --- a/libreport/src/lib/encbase64.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2006 Rob Landley <rob@landley.net> - * - * Licensed under GPLv2 or later. - */ -#include "libreport.h" /* xmalloc */ - -/* Conversion table for base 64 */ -static const char tbl_base64[65 /*+ 2*/] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '+', '/', - '=' /* termination character */, - // '\n', '\0' /* needed for uudecode.c */ -}; - -/* Conversion table for uuencode -const char tbl_uuencode[65] ALIGN1 = { - '`', '!', '"', '#', '$', '%', '&', '\'', - '(', ')', '*', '+', ',', '-', '.', '/', - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', ':', ';', '<', '=', '>', '?', - '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', - '`' -}; -*/ - -/* - * Encode bytes at S of length LENGTH. - * Result will be 0-terminated, and must point to a writable - * buffer of at least 1+BASE64_LENGTH(length) bytes, - * where BASE64_LENGTH(len) = 4 * ((LENGTH + 2) / 3) - */ -static void encode_64bit(char *p, const void *src, int length, const char *tbl) -{ - const unsigned char *s = (const unsigned char *)src; - - /* Transform the 3x8 bits to 4x6 bits */ - while (length > 0) { - unsigned s1, s2; - - /* Are s[1], s[2] valid or should be assumed 0? */ - s1 = s2 = 0; - length -= 3; /* can be >=0, -1, -2 */ - if (length >= -1) { - s1 = s[1]; - if (length >= 0) - s2 = s[2]; - } - *p++ = tbl[s[0] >> 2]; - *p++ = tbl[((s[0] & 3) << 4) + (s1 >> 4)]; - *p++ = tbl[((s1 & 0xf) << 2) + (s2 >> 6)]; - *p++ = tbl[s2 & 0x3f]; - s += 3; - } - /* Zero-terminate */ - *p = '\0'; - /* If length is -2 or -1, pad last char or two */ - while (length) { - *--p = tbl[64]; - length++; - } -} - -char *encode_base64(const void *src, int length) -{ - char *dst = (char *)xmalloc(4 * ((length + 2) / 3) + 1); - encode_64bit(dst, src, length, tbl_base64); - return dst; -} diff --git a/libreport/src/lib/event_config.c b/libreport/src/lib/event_config.c deleted file mode 100644 index 35ed8d36..00000000 --- a/libreport/src/lib/event_config.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - Copyright (C) 2011 ABRT Team - Copyright (C) 2011 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 "libreport.h" - -GHashTable *g_event_config_list; -static GHashTable *g_event_config_symlinks; - -event_option_t *new_event_option(void) -{ - return xzalloc(sizeof(event_option_t)); -} - -event_config_t *new_event_config(void) -{ - return xzalloc(sizeof(event_config_t)); -} - -void free_event_option(event_option_t *p) -{ - if (!p) - return; - free(p->eo_name); - free(p->eo_value); - free(p->eo_label); - free(p->eo_note_html); - //free(p->eo_description); - //free(p->eo_allowed_value); - free(p); -} - -void free_event_config(event_config_t *p) -{ - if (!p) - return; - - free(p->screen_name); - free(p->description); - free(p->long_descr); - free(p->ec_creates_items); - free(p->ec_requires_items); - free(p->ec_exclude_items_by_default); - free(p->ec_include_items_by_default); - free(p->ec_exclude_items_always); - GList *opt; - for (opt = p->options; opt; opt = opt->next) - free_event_option(opt->data); - g_list_free(p->options); - - free(p); -} - - -static int cmp_event_option_name_with_string(gconstpointer a, gconstpointer b) -{ - const event_option_t *evopt = a; - return !evopt->eo_name || strcmp(evopt->eo_name, (char *)b) != 0; -} - -event_option_t *get_event_option_from_list(const char *name, GList *options) -{ - GList *elem = g_list_find_custom(options, name, &cmp_event_option_name_with_string); - if (elem) - return (event_option_t *)elem->data; - return NULL; -} - -static void load_config_files(const char *dir_path) -{ - DIR *dir; - struct dirent *dent; - - /* Load .conf files */ - dir = opendir(dir_path); - if (!dir) - return; - while ((dent = readdir(dir)) != NULL) - { - char *ext = strrchr(dent->d_name, '.'); - if (!ext) - continue; - if (strcmp(ext + 1, "conf") != 0) - continue; - - char *fullname = concat_path_file(dir_path, dent->d_name); - - *ext = '\0'; - event_config_t *event_config = get_event_config(dent->d_name); - bool new_config = (!event_config); - if (new_config) - event_config = new_event_config(); - - map_string_h *keys_and_values = new_map_string(); - - load_conf_file(fullname, keys_and_values, /*skipKeysWithoutValue:*/ false); - free(fullname); - - /* Insert or replace every key/value from keys_and_values to event_config->option */ - GHashTableIter iter; - char *name; - char *value; - g_hash_table_iter_init(&iter, keys_and_values); - while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value)) - { - event_option_t *opt; - GList *elem = g_list_find_custom(event_config->options, name, - cmp_event_option_name_with_string); - if (elem) - { - opt = elem->data; - // log("conf: replacing '%s' value:'%s'->'%s'", name, opt->value, value); - free(opt->eo_value); - } - else - { - // log("conf: new value %s='%s'", name, value); - opt = new_event_option(); - opt->eo_name = xstrdup(name); - } - opt->eo_value = xstrdup(value); - if (!elem) - event_config->options = g_list_append(event_config->options, opt); - } - - free_map_string(keys_and_values); - - if (new_config) - g_hash_table_replace(g_event_config_list, xstrdup(dent->d_name), event_config); - } - closedir(dir); -} - -/* (Re)loads data from /etc/abrt/events/foo.{xml,conf} and ~/.abrt/events/foo.conf */ -void load_event_config_data(void) -{ - free_event_config_data(); - - if (!g_event_config_list) - g_event_config_list = g_hash_table_new_full( - /*hash_func*/ g_str_hash, - /*key_equal_func:*/ g_str_equal, - /*key_destroy_func:*/ free, - /*value_destroy_func:*/ (GDestroyNotify) free_event_config - ); - if (!g_event_config_symlinks) - g_event_config_symlinks = g_hash_table_new_full( - /*hash_func*/ g_str_hash, - /*key_equal_func:*/ g_str_equal, - /*key_destroy_func:*/ free, - /*value_destroy_func:*/ free - ); - - DIR *dir; - struct dirent *dent; - - /* Load .xml files */ - dir = opendir(EVENTS_DIR); - if (!dir) - return; - while ((dent = readdir(dir)) != NULL) - { - char *ext = strrchr(dent->d_name, '.'); - if (!ext) - continue; - if (strcmp(ext + 1, "xml") != 0) - continue; - - char *fullname = concat_path_file(EVENTS_DIR, dent->d_name); - *ext = '\0'; - - struct stat buf; - if (0 != lstat(fullname, &buf)) - continue; - if (S_ISLNK(buf.st_mode)) - { - GError *error = NULL; - gchar *link = g_file_read_link(fullname, &error); - if (error != NULL) - error_msg_and_die("Error reading symlink '%s': %s", fullname, error->message); - - gchar *target = g_path_get_basename(link); - char *ext = strrchr(target, '.'); - if (!ext || 0 != strcmp(ext + 1, "xml")) - error_msg_and_die("Invalid event symlink '%s': expected it to" - " point to another xml file", fullname); - *ext = '\0'; - g_hash_table_replace(g_event_config_symlinks, xstrdup(dent->d_name), target); - g_free(link); - /* don't free target, it is owned by the hash table now */ - continue; - } - - event_config_t *event_config = get_event_config(dent->d_name); - bool new_config = (!event_config); - if (new_config) - event_config = new_event_config(); - - load_event_description_from_file(event_config, fullname); - free(fullname); - - if (new_config) - g_hash_table_replace(g_event_config_list, xstrdup(dent->d_name), event_config); - } - closedir(dir); - - load_config_files(EVENTS_DIR); - - char *HOME = getenv("HOME"); - if (!HOME || !HOME[0]) - return; - HOME = concat_path_file(HOME, ".abrt/events"); - load_config_files(HOME); - free(HOME); -} - -/* Frees all loaded data */ -void free_event_config_data(void) -{ - if (g_event_config_list) - { - g_hash_table_destroy(g_event_config_list); - g_event_config_list = NULL; - } - if (g_event_config_symlinks) - { - g_hash_table_destroy(g_event_config_symlinks); - g_event_config_symlinks = NULL; - } -} - -event_config_t *get_event_config(const char *name) -{ - if (!g_event_config_list) - return NULL; - if (g_event_config_symlinks) - { - char *link = g_hash_table_lookup(g_event_config_symlinks, name); - if (link) - name = link; - } - return g_hash_table_lookup(g_event_config_list, name); -} - -GList *export_event_config(const char *event_name) -{ - GList *env_list = NULL; - - event_config_t *config = get_event_config(event_name); - if (config) - { - GList *lopt; - for (lopt = config->options; lopt; lopt = lopt->next) - { - event_option_t *opt = lopt->data; - if (!opt->eo_value) - continue; - char *var_val = xasprintf("%s=%s", opt->eo_name, opt->eo_value); - VERB3 log("Exporting '%s'", var_val); - env_list = g_list_prepend(env_list, var_val); - putenv(var_val); - } - } - - return env_list; -} - -void unexport_event_config(GList *env_list) -{ - while (env_list) - { - char *var_val = env_list->data; - VERB3 log("Unexporting '%s'", var_val); - safe_unsetenv(var_val); - env_list = g_list_remove(env_list, var_val); - free(var_val); - } -} - -/* return NULL if successful otherwise appropriate error message */ -static char *validate_event_option(event_option_t *opt) -{ - if (!opt->eo_allow_empty && (!opt->eo_value || !opt->eo_value[0])) - return xstrdup(_("Missing mandatory value")); - - /* if value is NULL and allow-empty yes than it doesn't make sence to check it */ - if (!opt->eo_value) - return NULL; - - const gchar *s = NULL; - if (!g_utf8_validate(opt->eo_value, -1, &s)) - return xasprintf(_("Invalid utf8 character '%c'"), *s); - - switch (opt->eo_type) { - case OPTION_TYPE_TEXT: - case OPTION_TYPE_PASSWORD: - break; - case OPTION_TYPE_NUMBER: - { - char *endptr; - errno = 0; - long r = strtol(opt->eo_value, &endptr, 10); - (void) r; - if (errno != 0 || endptr == opt->eo_value || *endptr != '\0') - return xasprintf(_("Invalid number '%s'"), opt->eo_value); - - break; - } - case OPTION_TYPE_BOOL: - if (strcmp(opt->eo_value, "yes") != 0 - && strcmp(opt->eo_value, "no") != 0 - && strcmp(opt->eo_value, "on") != 0 - && strcmp(opt->eo_value, "off") != 0 - && strcmp(opt->eo_value, "1") != 0 - && strcmp(opt->eo_value, "0") != 0) - { - return xasprintf(_("Invalid boolean value '%s'"), opt->eo_value); - } - break; - case OPTION_TYPE_HINT_HTML: - return NULL; - default: - return xstrdup(_("Unsupported option type")); - }; - - return NULL; -} - -GHashTable *validate_event(const char *event_name) -{ - event_config_t *config = get_event_config(event_name); - if (!config) - return NULL; - - GHashTable *errors = g_hash_table_new_full(g_str_hash, g_str_equal, free, free); - GList *li; - - for (li = config->options; li; li = li->next) - { - event_option_t *opt = (event_option_t *)li->data; - char *err = validate_event_option(opt); - if (err) - g_hash_table_insert(errors, xstrdup(opt->eo_name), err); - } - - if (g_hash_table_size(errors)) - return errors; - - g_hash_table_destroy(errors); - - return NULL; -} diff --git a/libreport/src/lib/event_xml_parser.c b/libreport/src/lib/event_xml_parser.c deleted file mode 100644 index 4a2e4493..00000000 --- a/libreport/src/lib/event_xml_parser.c +++ /dev/null @@ -1,469 +0,0 @@ -/* - Copyright (C) 2011 ABRT Team - Copyright (C) 2011 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 "libreport.h" -#include "event_config.h" - -#define EVENT_ELEMENT "event" -#define LABEL_ELEMENT "label" -#define DESCRIPTION_ELEMENT "description" -#define LONG_DESCR_ELEMENT "long-description" -#define ALLOW_EMPTY_ELEMENT "allow-empty" -#define NOTE_HTML_ELEMENT "note-html" -#define CREATES_ELEMENT "creates-items" -#define OPTION_ELEMENT "option" -//#define ACTION_ELEMENT "action" -#define NAME_ELEMENT "name" -#define DEFAULT_VALUE_ELEMENT "default-value" - -#define REQUIRES_ELEMENT "requires-items" -#define EXCL_BY_DEFAULT_ELEMENT "exclude-items-by-default" -#define INCL_BY_DEFAULT_ELEMENT "include-items-by-default" -#define EXCL_ALWAYS_ELEMENT "exclude-items-always" -#define EXCL_BINARY_ELEMENT "exclude-binary-items" - - -struct my_parse_data -{ - event_config_t *event_config; - event_option_t *cur_option; - const char *cur_locale; - char *attribute_lang; -}; - -static const char *const option_types[] = -{ - [OPTION_TYPE_TEXT ] = "text", - [OPTION_TYPE_BOOL ] = "bool", - [OPTION_TYPE_PASSWORD ] = "password", - [OPTION_TYPE_NUMBER ] = "number", - [OPTION_TYPE_HINT_HTML] = "hint-html", - [OPTION_TYPE_INVALID ] = NULL -}; - -// Return xml:lang value for <foo xml:lang="value"> if value matches current locale, -// "" if foo has no xml:lang attribute at all, -// else (if xml:lang is for some other locale) return NULL -// -static char *get_element_lang(struct my_parse_data *parse_data, const gchar **att_names, const gchar **att_values) -{ - char *short_locale_end = strchr(parse_data->cur_locale, '_'); - VERB3 log("locale: %s", parse_data->cur_locale); - int i; - for (i = 0; att_names[i] != NULL; ++i) - { - VERB3 log("attr: %s:%s", att_names[i], att_values[i]); - if (strcmp(att_names[i], "xml:lang") == 0) - { - if (strcmp(att_values[i], parse_data->cur_locale) == 0) - { - VERB3 log("found translation for: %s", parse_data->cur_locale); - return xstrdup(att_values[i]); - } - - /* try to match shorter locale - * e.g: "cs" with cs_CZ - */ - if (short_locale_end - && strncmp(att_values[i], parse_data->cur_locale, short_locale_end - parse_data->cur_locale) == 0 - ) { - VERB3 log("found translation for shortlocale: %s", parse_data->cur_locale); - return xstrndup(att_values[i], short_locale_end - parse_data->cur_locale); - } - } - } - /* if the element has no attribute then it's a default non-localized value */ - if (i == 0) - return xstrdup(""); - /* if the element is in different language than the current locale */ - return NULL; -} - -static int cmp_event_option_name_with_string(gconstpointer a, gconstpointer b) -{ - const event_option_t *evopt = a; - /* "When it is not a match?" */ - return !evopt->eo_name || strcmp(evopt->eo_name, (char *)b) != 0; -} - -static void consume_cur_option(struct my_parse_data *parse_data) -{ - event_option_t *opt = parse_data->cur_option; - if (!opt) - return; - parse_data->cur_option = NULL; - - event_config_t *event_config = parse_data->event_config; - - /* Example of "nameless" option: <option type="hint-html"> - * The remaining code does not like "nameless" options - * (strcmp would segfault, etc), so provide invented name: - */ - if (!opt->eo_name) - opt->eo_name = xasprintf("%u", (unsigned)g_list_length(event_config->options)); - - GList *elem = g_list_find_custom(event_config->options, opt->eo_name, cmp_event_option_name_with_string); - if (elem) - { - /* we already have option with such name */ - event_option_t *old_opt = elem->data; - if (old_opt->eo_value) - { - /* ...and it already has a value, which - * overrides xml-defined default one: - */ - free(opt->eo_value); - opt->eo_value = old_opt->eo_value; - old_opt->eo_value = NULL; - } - //log("xml: replacing '%s' value:'%s'->'%s'", opt->eo_name, old_opt->eo_value, opt->eo_value); - free_event_option(old_opt); - elem->data = opt; - } - else - { - //log("xml: new value %s='%s'", opt->eo_name, opt->eo_value); - event_config->options = g_list_append(event_config->options, opt); - } -} - -// Called for opening tags <foo bar="baz"> -static void start_element(GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - gpointer user_data, - GError **error) -{ - //log("start: %s", element_name); - - struct my_parse_data *parse_data = user_data; - - if (strcmp(element_name, OPTION_ELEMENT) == 0) - { - if (parse_data->cur_option) - { - error_msg("error, option nested in option"); - return; - } - - event_option_t *opt = parse_data->cur_option = new_event_option(); - int i; - - for (i = 0; attribute_names[i] != NULL; ++i) - { - VERB2 log("attr: %s:%s", attribute_names[i], attribute_values[i]); - if (strcmp(attribute_names[i], "name") == 0) - { - free(opt->eo_name); - opt->eo_name = xstrdup(attribute_values[i]); - } - else if (strcmp(attribute_names[i], "type") == 0) - { - option_type_t type; - for (type = OPTION_TYPE_TEXT; type < OPTION_TYPE_INVALID; ++type) - { - if (strcmp(option_types[type], attribute_values[i]) == 0) - opt->eo_type = type; - } - } - } - } - else - if (strcmp(element_name, LABEL_ELEMENT) == 0 - || strcmp(element_name, DESCRIPTION_ELEMENT) == 0 - || strcmp(element_name, LONG_DESCR_ELEMENT) == 0 - || strcmp(element_name, NAME_ELEMENT) == 0 - || strcmp(element_name, NOTE_HTML_ELEMENT) == 0 - ) { - free(parse_data->attribute_lang); - parse_data->attribute_lang = get_element_lang(parse_data, attribute_names, attribute_values); - } -} - -// Called for close tags </foo> -static void end_element(GMarkupParseContext *context, - const gchar *element_name, - gpointer user_data, - GError **error) -{ - struct my_parse_data *parse_data = user_data; - - free(parse_data->attribute_lang); - parse_data->attribute_lang = NULL; - - if (strcmp(element_name, OPTION_ELEMENT) == 0) - { - consume_cur_option(parse_data); - } - if (strcmp(element_name, EVENT_ELEMENT) == 0) - { - consume_cur_option(parse_data); - } -} - -// Called for character data -// text is not nul-terminated -static void text(GMarkupParseContext *context, - const gchar *text, - gsize text_len, - gpointer user_data, - GError **error) -{ - struct my_parse_data *parse_data = user_data; - event_config_t *ui = parse_data->event_config; - - const gchar *inner_element = g_markup_parse_context_get_element(context); - char *text_copy = xstrndup(text, text_len); - event_option_t *opt = parse_data->cur_option; - if (opt) - { - if (strcmp(inner_element, LABEL_ELEMENT) == 0) - { - if (parse_data->attribute_lang != NULL) /* if it isn't for other locale */ - { - /* set the value only if we found a value for the current locale - * OR the label is still not set and we found the default value - */ - if (parse_data->attribute_lang[0] != '\0' - || !opt->eo_label /* && parse_data->attribute_lang is "" - always true */ - ) { - VERB2 log("new label:'%s'", text_copy); - free(opt->eo_label); - opt->eo_label = text_copy; - } - } - return; - } - /* - * we can add a separate field for the default value - * in that case we can implement features like "reset to default value" - * but for now using "value" should be enough and clients doesn't - * have to know about the "defaul-value" - */ - if (strcmp(inner_element, DEFAULT_VALUE_ELEMENT) == 0) - { - VERB2 log("default value:'%s'", text_copy); - free(opt->eo_value); - opt->eo_value = text_copy; - return; - } - - if (strcmp(inner_element, NOTE_HTML_ELEMENT) == 0) - { - if (parse_data->attribute_lang != NULL) /* if it isn't for other locale */ - { - /* set the value only if we found a value for the current locale - * OR the label is still not set and we found the default value - */ - if (parse_data->attribute_lang[0] != '\0' - || !opt->eo_note_html /* && parse_data->attribute_lang is "" - always true */ - ) { - VERB2 log("html note:'%s'", text_copy); - free(opt->eo_note_html); - opt->eo_note_html = text_copy; - } - } - return; - } - - if (strcmp(inner_element, ALLOW_EMPTY_ELEMENT) == 0) - { - VERB2 log("allow-empty:'%s'", text_copy); - opt->eo_allow_empty = string_to_bool(text_copy); - return; - } - /* - if (strcmp(inner_element, DESCRIPTION_ELEMENT) == 0) - { - VERB2 log("tooltip:'%s'", text_copy); - free(opt->eo_description); - opt->eo_description = text_copy; - return; - } - */ - } - else - { - /* we're not in option, so the description is for the event */ - /* - if (strcmp(inner_element, ACTION_ELEMENT) == 0) - { - VERB2 log("action description:'%s'", text_copy); - free(ui->action); - ui->action = text_copy; - return; - } - */ - if (strcmp(inner_element, CREATES_ELEMENT) == 0) - { - VERB2 log("ec_creates_items:'%s'", text_copy); - free(ui->ec_creates_items); - ui->ec_creates_items = text_copy; - return; - } - if (strcmp(inner_element, NAME_ELEMENT) == 0) - { - if (parse_data->attribute_lang != NULL) /* if it isn't for other locale */ - { - /* set the value only if we found a value for the current locale - * OR the label is still not set and we found the default value - */ - if (parse_data->attribute_lang[0] != '\0' - || !ui->screen_name /* && parse_data->attribute_lang is "" - always true */ - ) { - VERB2 log("event name:'%s'", text_copy); - free(ui->screen_name); - ui->screen_name = text_copy; - } - } - return; - } - if (strcmp(inner_element, DESCRIPTION_ELEMENT) == 0) - { - VERB3 log("event description:'%s'", text_copy); - - if (parse_data->attribute_lang != NULL) /* if it isn't for other locale */ - { - /* set the value only if we found a value for the current locale - * OR the description is still not set and we found the default value - */ - if (parse_data->attribute_lang[0] != '\0' - || !ui->description /* && parse_data->attribute_lang is "" - always true */ - ) { - free(ui->description); - ui->description = text_copy; - } - } - return; - } - if (strcmp(inner_element, LONG_DESCR_ELEMENT) == 0) - { - VERB3 log("event long description:'%s'", text_copy); - - if (parse_data->attribute_lang != NULL) /* if it isn't for other locale */ - { - /* set the value only if we found a value for the current locale - * OR the description is still not set and we found the default value - */ - if (parse_data->attribute_lang[0] != '\0' - || !ui->long_descr /* && parse_data->attribute_lang is "" - always true */ - ) { - free(ui->long_descr); - ui->long_descr = text_copy; - } - } - return; - } - if (strcmp(inner_element, REQUIRES_ELEMENT) == 0) - { - free(ui->ec_requires_items); - ui->ec_requires_items = text_copy; - return; - } - if (strcmp(inner_element, EXCL_BY_DEFAULT_ELEMENT) == 0) - { - free(ui->ec_exclude_items_by_default); - ui->ec_exclude_items_by_default = text_copy; - return; - } - if (strcmp(inner_element, INCL_BY_DEFAULT_ELEMENT) == 0) - { - free(ui->ec_include_items_by_default); - ui->ec_include_items_by_default = text_copy; - return; - } - if (strcmp(inner_element, EXCL_ALWAYS_ELEMENT) == 0) - { - free(ui->ec_exclude_items_always); - ui->ec_exclude_items_always = text_copy; - return; - } - if (strcmp(inner_element, EXCL_BINARY_ELEMENT) == 0) - { - ui->ec_exclude_binary_items = string_to_bool(text_copy); - free(text_copy); - return; - } - } - free(text_copy); -} - - // Called for strings that should be re-saved verbatim in this same - // position, but are not otherwise interpretable. At the moment - // this includes comments and processing instructions. - // text is not nul-terminated -static void passthrough(GMarkupParseContext *context, - const gchar *passthrough_text, - gsize text_len, - gpointer user_data, - GError **error) -{ - VERB3 log("passthrough"); -} - -// Called on error, including one set by other -// methods in the vtable. The GError should not be freed. -static void error(GMarkupParseContext *context, - GError *error, - gpointer user_data) -{ - error_msg("error in XML parsing"); -} - -/* this function takes 2 parameters - * ui -> pointer to event_config_t - * filename -> filename to read - * event_config_t contains list of options, which is malloced by hits function - * and must be freed by the caller - */ - -void load_event_description_from_file(event_config_t *event_config, const char* filename) -{ - struct my_parse_data parse_data = { event_config, NULL, NULL , NULL }; - parse_data.cur_locale = setlocale(LC_ALL, NULL); - - GMarkupParser parser; - memset(&parser, 0, sizeof(parser)); /* just in case */ - parser.start_element = &start_element; - parser.end_element = &end_element; - parser.text = &text; - parser.passthrough = &passthrough; - parser.error = &error; - - GMarkupParseContext *context = g_markup_parse_context_new( - &parser, G_MARKUP_TREAT_CDATA_AS_TEXT, - &parse_data, /*GDestroyNotify:*/ NULL); - - FILE* fin = fopen(filename, "r"); - if (fin != NULL) - { - size_t read_bytes = 0; - char buff[1024]; - while ((read_bytes = fread(buff, 1, 1024, fin)) != 0) - { - g_markup_parse_context_parse(context, buff, read_bytes, NULL); - } - fclose(fin); - } - - g_markup_parse_context_free(context); - - consume_cur_option(&parse_data); /* just in case */ - free(parse_data.attribute_lang); /* just in case */ -} diff --git a/libreport/src/lib/get_cmdline.c b/libreport/src/lib/get_cmdline.c deleted file mode 100644 index 04254660..00000000 --- a/libreport/src/lib/get_cmdline.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - 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 "libreport.h" - -/* If s is a string with only printable ASCII chars - * and has no spaces, ", ', and \, copy it verbatim. - * Else, encapsulate it in single quotes, and - * encode ', " and \ with \c escapes. - * Control chars are encoded as \r, \n, \t, or \xNN. - * In all cases, terminating NUL is added - * and the pointer to it is returned. - */ -static char *append_escaped(char *start, const char *s) -{ - char *dst = start; - const unsigned char *p = (unsigned char *)s; - - while (1) - { - const unsigned char *old_p = p; - while (*p > ' ' && *p <= 0x7e && *p != '\"' && *p != '\'' && *p != '\\') - p++; - if (dst == start) - { - if (p != (unsigned char *)s && *p == '\0') - { - /* entire word does not need escaping and quoting */ - strcpy(dst, s); - dst += strlen(s); - return dst; - } - *dst++ = '\''; - } - - strncpy(dst, (char *)old_p, (p - old_p)); - dst += (p - old_p); - - if (*p == '\0') - { - *dst++ = '\''; - *dst = '\0'; - return dst; - } - - char hex_char_buf[5]; - const char *a; - switch (*p) - { - case '\r': a = "\\r"; break; - case '\n': a = "\\n"; break; - case '\t': a = "\\t"; break; - case '\'': a = "\\\'"; break; - case '\"': a = "\\\""; break; - case '\\': a = "\\\\"; break; - case ' ': a = " "; break; - default: - /* Build \xNN string */ - hex_char_buf[0] = '\\'; - hex_char_buf[1] = 'x'; - hex_char_buf[2] = "0123456789abcdef"[*p >> 4]; - hex_char_buf[3] = "0123456789abcdef"[*p & 0xf]; - hex_char_buf[4] = '\0'; - a = hex_char_buf; - } - strcpy(dst, a); - dst += strlen(a); - p++; - } -} - -static char* get_escaped(const char *path, char separator) -{ - char *escaped = NULL; - - int fd = open(path, O_RDONLY); - if (fd >= 0) - { - char *dst = NULL; - unsigned total_esc_len = 0; - while (total_esc_len < 1024 * 1024) /* paranoia check */ - { - /* read and escape one block */ - char buffer[4 * 1024 + 1]; - int len = read(fd, buffer, sizeof(buffer) - 1); - if (len <= 0) - break; - buffer[len] = '\0'; - - /* string CC can expand into '\xNN\xNN' and thus needs len*4 + 3 bytes, - * including terminating NUL. - * We add +1 for possible \n added at the very end. - */ - escaped = xrealloc(escaped, total_esc_len + len*4 + 4); - char *src = buffer; - dst = escaped + total_esc_len; - while (1) - { - /* escape till next NUL char */ - char *d = append_escaped(dst, src); - total_esc_len += (d - dst); - dst = d; - src += strlen(src) + 1; - if ((src - buffer) >= len) - break; - *dst++ = separator; - } - - } - - if (dst) - { - if (separator == '\n') - *dst++ = separator; - *dst = '\0'; - } - - close(fd); - } - - return escaped; -} - -char* get_cmdline(pid_t pid) -{ - char path[sizeof("/proc/%lu/cmdline") + sizeof(long)*3]; - sprintf(path, "/proc/%lu/cmdline", (long)pid); - return get_escaped(path, ' '); -} - -char* get_environ(pid_t pid) -{ - char path[sizeof("/proc/%lu/environ") + sizeof(long)*3]; - sprintf(path, "/proc/%lu/environ", (long)pid); - return get_escaped(path, '\n'); -} diff --git a/libreport/src/lib/glib_support.c b/libreport/src/lib/glib_support.c deleted file mode 100644 index b59b37c0..00000000 --- a/libreport/src/lib/glib_support.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - Copyright (C) 2011 ABRT team - Copyright (C) 2011 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 "libreport.h" - -void list_free_with_free(GList *list) -{ - GList *li; - for (li = list; li; li = g_list_next(li)) - free(li->data); - g_list_free(list); -} diff --git a/libreport/src/lib/hash_sha1.c b/libreport/src/lib/hash_sha1.c deleted file mode 100644 index fafdae56..00000000 --- a/libreport/src/lib/hash_sha1.c +++ /dev/null @@ -1,211 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Based on shasum from http://www.netsw.org/crypto/hash/ - * Majorly hacked up to use Dr Brian Gladman's sha1 code - * - * Copyright (C) 2002 Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK. - * Copyright (C) 2003 Glenn L. McGrath - * Copyright (C) 2003 Erik Andersen - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - * - * --------------------------------------------------------------------------- - * Issue Date: 10/11/2002 - * - * This is a byte oriented version of SHA1 that operates on arrays of bytes - * stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor - * - * --------------------------------------------------------------------------- - */ -#include "libreport.h" -#include <byteswap.h> - -#if defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ -# define SHA1_BIG_ENDIAN 1 -# define SHA1_LITTLE_ENDIAN 0 -#elif __BYTE_ORDER == __BIG_ENDIAN -# define SHA1_BIG_ENDIAN 1 -# define SHA1_LITTLE_ENDIAN 0 -#elif __BYTE_ORDER == __LITTLE_ENDIAN -# define SHA1_BIG_ENDIAN 0 -# define SHA1_LITTLE_ENDIAN 1 -#else -# error "Can't determine endianness" -#endif - -#define rotl32(x,n) (((x) << (n)) | ((x) >> (32 - (n)))) -/* for sha256: */ -#define rotr32(x,n) (((x) >> (n)) | ((x) << (32 - (n)))) -/* for sha512: */ -#define rotr64(x,n) (((x) >> (n)) | ((x) << (64 - (n)))) - - -/* Generic 64-byte helpers for 64-byte block hashes */ -static void common64_hash(sha1_ctx_t *ctx, const void *buffer, size_t len); -static void common64_end(sha1_ctx_t *ctx, int swap_needed); - - -/* sha1 specific code */ - -static void sha1_process_block64(sha1_ctx_t *ctx) -{ - static const uint32_t rconsts[] = { - 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 - }; - int i, j; - int cnt; - uint32_t W[16+16]; - uint32_t a, b, c, d, e; - - /* On-stack work buffer frees up one register in the main loop - * which otherwise will be needed to hold ctx pointer */ - for (i = 0; i < 16; i++) - if (SHA1_BIG_ENDIAN) - W[i] = W[i+16] = ((uint32_t*)ctx->wbuffer)[i]; - else - W[i] = W[i+16] = bswap_32(((uint32_t*)ctx->wbuffer)[i]); - - a = ctx->hash[0]; - b = ctx->hash[1]; - c = ctx->hash[2]; - d = ctx->hash[3]; - e = ctx->hash[4]; - - /* 4 rounds of 20 operations each */ - cnt = 0; - for (i = 0; i < 4; i++) { - j = 19; - do { - uint32_t work; - - work = c ^ d; - if (i == 0) { - work = (work & b) ^ d; - if (j <= 3) - goto ge16; - /* Used to do bswap_32 here, but this - * requires ctx (see comment above) */ - work += W[cnt]; - } else { - if (i == 2) - work = ((b | c) & d) | (b & c); - else /* i = 1 or 3 */ - work ^= b; - ge16: - W[cnt] = W[cnt+16] = rotl32(W[cnt+13] ^ W[cnt+8] ^ W[cnt+2] ^ W[cnt], 1); - work += W[cnt]; - } - work += e + rotl32(a, 5) + rconsts[i]; - - /* Rotate by one for next time */ - e = d; - d = c; - c = /* b = */ rotl32(b, 30); - b = a; - a = work; - cnt = (cnt + 1) & 15; - } while (--j >= 0); - } - - ctx->hash[0] += a; - ctx->hash[1] += b; - ctx->hash[2] += c; - ctx->hash[3] += d; - ctx->hash[4] += e; -} - -void sha1_begin(sha1_ctx_t *ctx) -{ - ctx->hash[0] = 0x67452301; - ctx->hash[1] = 0xefcdab89; - ctx->hash[2] = 0x98badcfe; - ctx->hash[3] = 0x10325476; - ctx->hash[4] = 0xc3d2e1f0; - ctx->total64 = 0; - /* for sha256: ctx->process_block = sha1_process_block64; */ -} - -void sha1_hash(sha1_ctx_t *ctx, const void *buffer, size_t len) -{ - common64_hash(ctx, buffer, len); -} - -/* May be used also for sha256 */ -void sha1_end(sha1_ctx_t *ctx, void *resbuf) -{ - unsigned hash_size; - - /* SHA stores total in BE, need to swap on LE arches: */ - common64_end(ctx, /*swap_needed:*/ SHA1_LITTLE_ENDIAN); - - hash_size = 5; /* (ctx->process_block == sha1_process_block64) ? 5 : 8; */ - /* This way we do not impose alignment constraints on resbuf: */ - if (SHA1_LITTLE_ENDIAN) { - unsigned i; - for (i = 0; i < hash_size; ++i) - ctx->hash[i] = bswap_32(ctx->hash[i]); - } - memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * hash_size); -} - - -/* Generic 64-byte helpers for 64-byte block hashes */ - -/*#define PROCESS_BLOCK(ctx) ctx->process_block(ctx)*/ -#define PROCESS_BLOCK(ctx) sha1_process_block64(ctx) - -/* Feed data through a temporary buffer. - * The internal buffer remembers previous data until it has 64 - * bytes worth to pass on. - */ -static void common64_hash(sha1_ctx_t *ctx, const void *buffer, size_t len) -{ - unsigned bufpos = ctx->total64 & 63; - - ctx->total64 += len; - - while (1) { - unsigned remaining = 64 - bufpos; - if (remaining > len) - remaining = len; - /* Copy data into aligned buffer */ - memcpy(ctx->wbuffer + bufpos, buffer, remaining); - len -= remaining; - buffer = (const char *)buffer + remaining; - bufpos += remaining; - /* clever way to do "if (bufpos != 64) break; ... ; bufpos = 0;" */ - bufpos -= 64; - if (bufpos != 0) - break; - /* Buffer is filled up, process it */ - PROCESS_BLOCK(ctx); - /*bufpos = 0; - already is */ - } -} - -/* Process the remaining bytes in the buffer */ -static void common64_end(sha1_ctx_t *ctx, int swap_needed) -{ - unsigned bufpos = ctx->total64 & 63; - /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */ - ctx->wbuffer[bufpos++] = 0x80; - - /* This loop iterates either once or twice, no more, no less */ - while (1) { - unsigned remaining = 64 - bufpos; - memset(ctx->wbuffer + bufpos, 0, remaining); - /* Do we have enough space for the length count? */ - if (remaining >= 8) { - /* Store the 64-bit counter of bits in the buffer */ - uint64_t t = ctx->total64 << 3; - if (swap_needed) - t = bswap_64(t); - /* wbuffer is suitably aligned for this */ - *(uint64_t *) (&ctx->wbuffer[64 - 8]) = t; - } - PROCESS_BLOCK(ctx); - if (remaining >= 8) - break; - bufpos = 0; - } -} diff --git a/libreport/src/lib/is_in_string_list.c b/libreport/src/lib/is_in_string_list.c deleted file mode 100644 index 2d7bb61b..00000000 --- a/libreport/src/lib/is_in_string_list.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - Copyright (C) 2011 ABRT team - Copyright (C) 2011 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 "libreport.h" - -bool is_in_string_list(const char *name, char **v) -{ - while (*v) - { - if (strcmp(*v, name) == 0) - return true; - v++; - } - return false; -} diff --git a/libreport/src/lib/iso_date_string.c b/libreport/src/lib/iso_date_string.c deleted file mode 100644 index 475f7863..00000000 --- a/libreport/src/lib/iso_date_string.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - Copyright (C) 2011 ABRT team - Copyright (C) 2011 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 "libreport.h" - -char *iso_date_string(time_t *pt) -{ - static char buf[sizeof("YYYY-MM-DD-HH:MM:SS") + 4]; - - time_t t; - struct tm *ptm = localtime(pt ? pt : (time(&t), &t)); - strftime(buf, sizeof(buf), "%Y-%m-%d-%H:%M:%S", ptm); - - return buf; -} diff --git a/libreport/src/lib/kernel-tainted.c b/libreport/src/lib/kernel-tainted.c deleted file mode 100644 index ace7c29e..00000000 --- a/libreport/src/lib/kernel-tainted.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - Copyright (C) 2011 ABRT team - Copyright (C) 2011 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 "libreport.h" - -/* From RHEL6 kernel/panic.c: */ -static const int tnts_short[] = { - 'P' , - 'F' , - 'S' , - 'R' , - 'M' , - 'B' , - 'U' , - 'D' , - 'A' , - 'W' , - 'C' , - 'I' , - '-' , - '-' , - '-' , - '-' , - '-' , - '-' , - '-' , - '-' , - '-' , - '-' , - '-' , - '-' , - '-' , - '-' , - '-' , - '-' , - 'H' , - 'T' , -}; - -/** - * print_tainted - return a string to represent the kernel taint state. - * - * 'P' - Proprietary module has been loaded. - * 'F' - Module has been forcibly loaded. - * 'S' - SMP with CPUs not designed for SMP. - * 'R' - User forced a module unload. - * 'M' - System experienced a machine check exception. - * 'B' - System has hit bad_page. - * 'U' - Userspace-defined naughtiness. - * 'D' - Kernel has oopsed before - * 'A' - ACPI table overridden. - * 'W' - Taint on warning. - * 'C' - modules from drivers/staging are loaded. - * 'I' - Working around severe firmware bug. - * 'H' - Hardware is unsupported. - * T - Tech_preview - */ - - -static const char *const tnts_long[] = { - "Proprietary module has been loaded.", - "Module has been forcibly loaded.", - "SMP with CPUs not designed for SMP.", - "User forced a module unload.", - "System experienced a machine check exception.", - "System has hit bad_page.", - "Userspace-defined naughtiness.", - "Kernel has oopsed before.", - "ACPI table overridden.", - "Taint on warning.", - "Modules from drivers/staging are loaded.", - "Working around severe firmware bug.", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "Hardware is unsupported.", - "Tech_preview", -}; - -char *kernel_tainted_short(unsigned tainted) -{ - char *tnt = xzalloc(ARRAY_SIZE(tnts_short) + 1); - int i = 0; - while (tainted) - { - if (0x1 & tainted) - tnt[i] = tnts_short[i]; - else - tnt[i] = '-'; - - ++i; - tainted >>= 1; - } - - return tnt; -} - -GList *kernel_tainted_long(unsigned tainted) -{ - int i = 0; - GList *tnt = NULL; - - while (tainted) - { - if (0x1 & tainted && tnts_long[i]) - tnt = g_list_append(tnt, xstrdup(tnts_long[i])); - - ++i; - tainted >>= 1; - } - - return tnt; -} diff --git a/libreport/src/lib/load_plugin_settings.c b/libreport/src/lib/load_plugin_settings.c deleted file mode 100644 index e07ea7d4..00000000 --- a/libreport/src/lib/load_plugin_settings.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - 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 "libreport.h" - -/* Returns false if open failed. - * Returns empty hash if conf file is empty. - * TODO: better error detection? - */ -bool load_conf_file(const char *pPath, map_string_h *settings, bool skipKeysWithoutValue) -{ - FILE *fp = stdin; - if (strcmp(pPath, "-") != 0) - { - fp = fopen(pPath, "r"); - if (!fp) - return false; - } - - char *line; - while ((line = xmalloc_fgetline(fp)) != NULL) - { - bool in_quote = false; - /* We are reusing line buffer to form temporary - * "key\0value\0..." in its beginning - */ - char *value = NULL; - char *src; - char *dst; - for (src = dst = line; *src; src++) - { - char c = *src; - if (c == '"') - { - in_quote = !in_quote; - } - if (!in_quote) - { - if (isspace(c)) - { - continue; - } - if (c == '#' && dst == line) - { - break; - } - if (c == '=') - { - *dst++ = '\0'; /* terminate key */ - value = dst; /* remember where value starts */ - continue; - } - } - *dst++ = c; /* store next key or value char */ - } - *dst = '\0'; /* terminate value */ - - /* Skip broken or empty lines. */ - if (!value) - goto free_line; - - /* Skip lines with empty key. */ - if (line[0] == '\0') - goto free_line; - - if (skipKeysWithoutValue && value[0] == '\0') - goto free_line; - - /* Skip lines with unclosed quotes. */ - if (in_quote) - goto free_line; - - g_hash_table_replace(settings, xstrdup(line), xstrdup(value)); - free_line: - free(line); - } - - if (fp != stdin) - fclose(fp); - - return true; -} diff --git a/libreport/src/lib/logging.c b/libreport/src/lib/logging.c deleted file mode 100644 index 72aa2423..00000000 --- a/libreport/src/lib/logging.c +++ /dev/null @@ -1,148 +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. -*/ - -/* - * Utility routines. - * - */ -#include "libreport.h" - -void (*g_custom_logger)(const char*); -const char *msg_prefix = ""; -const char *msg_eol = "\n"; -int logmode = LOGMODE_STDIO; -int xfunc_error_retval = EXIT_FAILURE; -int g_verbose; - -void xfunc_die(void) -{ - exit(xfunc_error_retval); -} - -static void verror_msg_helper(const char *s, - va_list p, - const char* strerr, - int flags) -{ - char *msg; - int prefix_len, strerr_len, msgeol_len, used; - - if (!logmode) - return; - - used = vasprintf(&msg, s, p); - if (used < 0) - return; - - /* This is ugly and costs +60 bytes compared to multiple - * fprintf's, but is guaranteed to do a single write. - * This is needed for e.g. when multiple children - * can produce log messages simultaneously. */ - - prefix_len = msg_prefix[0] ? strlen(msg_prefix) + 2 : 0; - strerr_len = strerr ? strlen(strerr) : 0; - msgeol_len = strlen(msg_eol); - /* +3 is for ": " before strerr and for terminating NUL */ - msg = (char*) xrealloc(msg, prefix_len + used + strerr_len + msgeol_len + 3); - /* TODO: maybe use writev instead of memmoving? Need full_writev? */ - if (prefix_len) { - char *p; - memmove(msg + prefix_len, msg, used); - used += prefix_len; - p = stpcpy(msg, msg_prefix); - p[0] = ':'; - p[1] = ' '; - } - if (strerr) { - if (s[0]) { - msg[used++] = ':'; - msg[used++] = ' '; - } - strcpy(&msg[used], strerr); - used += strerr_len; - } - strcpy(&msg[used], msg_eol); - - if (flags & LOGMODE_STDIO) { - fflush(stdout); - full_write(STDERR_FILENO, msg, used + msgeol_len); - } - msg[used] = '\0'; /* remove msg_eol (usually "\n") */ - if (flags & LOGMODE_SYSLOG) { - syslog(LOG_ERR, "%s", msg + prefix_len); - } - if ((flags & LOGMODE_CUSTOM) && g_custom_logger) { - g_custom_logger(msg + prefix_len); - } - free(msg); -} - -void log_msg(const char *s, ...) -{ - va_list p; - - va_start(p, s); - verror_msg_helper(s, p, NULL, logmode); - va_end(p); -} - -void error_msg(const char *s, ...) -{ - va_list p; - - va_start(p, s); - verror_msg_helper(s, p, NULL, (logmode | LOGMODE_CUSTOM)); - va_end(p); -} - -void error_msg_and_die(const char *s, ...) -{ - va_list p; - - va_start(p, s); - verror_msg_helper(s, p, NULL, (logmode | LOGMODE_CUSTOM)); - va_end(p); - xfunc_die(); -} - -void perror_msg(const char *s, ...) -{ - va_list p; - - va_start(p, s); - /* Guard against "<error message>: Success" */ - verror_msg_helper(s, p, errno ? strerror(errno) : NULL, (logmode | LOGMODE_CUSTOM)); - va_end(p); -} - -void perror_msg_and_die(const char *s, ...) -{ - va_list p; - - va_start(p, s); - /* Guard against "<error message>: Success" */ - verror_msg_helper(s, p, errno ? strerror(errno) : NULL, (logmode | LOGMODE_CUSTOM)); - va_end(p); - xfunc_die(); -} - -void die_out_of_memory(void) -{ - error_msg_and_die("Out of memory, exiting"); -} diff --git a/libreport/src/lib/make_descr.c b/libreport/src/lib/make_descr.c deleted file mode 100644 index adee54af..00000000 --- a/libreport/src/lib/make_descr.c +++ /dev/null @@ -1,262 +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 "libreport.h" - - -char *make_description(problem_data_t *problem_data, char **names_to_skip, unsigned max_text_size, unsigned desc_flags) -{ - struct strbuf *buf_dsc = strbuf_new(); - - GList *list = g_hash_table_get_keys(problem_data); - list = g_list_sort(list, (GCompareFunc)strcmp); - GList *l; - - /* Print one-liners. Format: - * NAME1: <maybe more spaces>VALUE1 - * NAME2: <maybe more spaces>VALUE2 - */ - bool empty = true; - l = list; - while (l) - { - const char *key = l->data; - l = l->next; - - /* Skip items we are not interested in */ -//TODO: optimize by doing this once, not 3 times: - if (names_to_skip && is_in_string_list(key, names_to_skip)) - continue; - - struct problem_item *item = g_hash_table_lookup(problem_data, key); - if (!item) - continue; - - if ((desc_flags & MAKEDESC_SHOW_ONLY_LIST) && !(item->flags & CD_FLAG_LIST)) - continue; - - if ((item->flags & CD_FLAG_TXT) - && strlen(item->content) <= max_text_size - ) { - char *formatted = format_problem_item(item); - char *output = formatted ? formatted : item->content; - char *eol = strchr(output, '\n'); - if (!eol) - { - int pad = 16 - (strlen(key) + 2); - if (pad < 0) pad = 0; - strbuf_append_strf(buf_dsc, "%s: %*s%s\n", key, pad, "", output); - empty = false; - } - free(formatted); - } - } - - bool append_empty_line = !empty; - if (desc_flags & MAKEDESC_SHOW_FILES) - { - /* Print file info. Format: - * <empty line if needed> - * NAME1: <maybe more spaces>Binary file, NNN bytes - * NAME2: <maybe more spaces>Text file, NNN bytes - * - * In many cases, it is useful to know how big binary files are - * (for example, helps with diagnosing bug upload problems) - */ - l = list; - while (l) - { - const char *key = l->data; - l = l->next; - - /* Skip items we are not interested in */ - if (names_to_skip && is_in_string_list(key, names_to_skip)) - continue; - - struct problem_item *item = g_hash_table_lookup(problem_data, key); - if (!item) - continue; - - if ((desc_flags & MAKEDESC_SHOW_ONLY_LIST) && !(item->flags & CD_FLAG_LIST)) - continue; - - if ((item->flags & CD_FLAG_BIN) - || ((item->flags & CD_FLAG_TXT) && strlen(item->content) > max_text_size) - ) { - if (append_empty_line) - strbuf_append_char(buf_dsc, '\n'); - append_empty_line = false; - - struct stat statbuf; - int stat_err = 0; - if (item->flags & CD_FLAG_BIN) - stat_err = stat(item->content, &statbuf); - else - statbuf.st_size = strlen(item->content); - - /* We don't print item->content for CD_FLAG_BIN, as it is - * always "/path/to/dump/dir/KEY" - not informative. - */ - int pad = 16 - (strlen(key) + 2); - if (pad < 0) pad = 0; - strbuf_append_strf(buf_dsc, - (!stat_err ? "%s: %*s%s file, %llu bytes\n" : "%s: %*s%s file\n"), - key, - pad, "", - ((item->flags & CD_FLAG_BIN) ? "Binary" : "Text"), - (long long)statbuf.st_size - ); - empty = false; - } - } - } - - if (desc_flags & MAKEDESC_SHOW_MULTILINE) - { - /* Print multi-liners. Format: - * <empty line if needed> - * NAME: - * :LINE1 - * :LINE2 - * :LINE3 - */ - l = list; - while (l) - { - const char *key = l->data; - l = l->next; - - /* Skip items we are not interested in */ - if (names_to_skip && is_in_string_list(key, names_to_skip)) - continue; - - struct problem_item *item = g_hash_table_lookup(problem_data, key); - if (!item) - continue; - - if ((desc_flags & MAKEDESC_SHOW_ONLY_LIST) && !(item->flags & CD_FLAG_LIST)) - continue; - - if ((item->flags & CD_FLAG_TXT) - && strlen(item->content) <= max_text_size - ) { - char *formatted = format_problem_item(item); - char *output = formatted ? formatted : item->content; - char *eol = strchr(output, '\n'); - if (eol) - { - if (!empty) - strbuf_append_char(buf_dsc, '\n'); - strbuf_append_str(buf_dsc, key); - strbuf_append_str(buf_dsc, ":\n"); - for (;;) - { - eol = strchrnul(output, '\n'); - strbuf_append_strf(buf_dsc, ":%.*s\n", (int)(eol - output), output); - if (*eol == '\0' || eol[1] == '\0') - break; - output = eol + 1; - } - empty = false; - } - free(formatted); - } - } - } - - g_list_free(list); - - return strbuf_free_nobuf(buf_dsc); -} - -char* make_description_mailx(problem_data_t *problem_data) -{ - struct strbuf *buf_dsc = strbuf_new(); - struct strbuf *buf_additional_files = strbuf_new(); - struct strbuf *buf_duphash_file = strbuf_new(); - struct strbuf *buf_common_files = strbuf_new(); - - GHashTableIter iter; - char *name; - struct problem_item *value; - g_hash_table_iter_init(&iter, problem_data); - while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value)) - { - if (value->flags & CD_FLAG_TXT) - { - if ((strcmp(name, FILENAME_DUPHASH) != 0) - && (strcmp(name, FILENAME_ARCHITECTURE) != 0) - && (strcmp(name, FILENAME_KERNEL) != 0) - && (strcmp(name, FILENAME_PACKAGE) != 0) - ) { - strbuf_append_strf(buf_additional_files, "%s\n-----\n%s\n\n", name, value->content); - } - else if (strcmp(name, FILENAME_DUPHASH) == 0) - strbuf_append_strf(buf_duphash_file, "%s\n-----\n%s\n\n", name, value->content); - else - strbuf_append_strf(buf_common_files, "%s\n-----\n%s\n\n", name, value->content); - } - } - - char *common_files = strbuf_free_nobuf(buf_common_files); - char *duphash_file = strbuf_free_nobuf(buf_duphash_file); - char *additional_files = strbuf_free_nobuf(buf_additional_files); - - strbuf_append_strf(buf_dsc, "Duplicate check\n=====\n%s\n\n", duphash_file); - strbuf_append_strf(buf_dsc, "Common information\n=====\n%s\n\n", common_files); - strbuf_append_strf(buf_dsc, "Additional information\n=====\n%s\n", additional_files); - - free(common_files); - free(duphash_file); - free(additional_files); - - return strbuf_free_nobuf(buf_dsc); -} - -/* Items we don't want to include to bz / logger */ -static const char *const blacklisted_items[] = { - CD_DUMPDIR , - FILENAME_ANALYZER , - FILENAME_COREDUMP , - FILENAME_HOSTNAME , - FILENAME_DUPHASH , - FILENAME_UUID , - FILENAME_COUNT , - FILENAME_TAINTED_SHORT, - NULL -}; - -char* make_description_bz(problem_data_t *problem_data) -{ - return make_description( - problem_data, - (char**)blacklisted_items, - /*max_text_size:*/ CD_TEXT_ATT_SIZE, - MAKEDESC_SHOW_FILES | MAKEDESC_SHOW_MULTILINE - ); -} - -char* make_description_logger(problem_data_t *problem_data) -{ - return make_description( - problem_data, - (char**)blacklisted_items, - /*max_text_size:*/ CD_TEXT_ATT_SIZE, - MAKEDESC_SHOW_FILES | MAKEDESC_SHOW_MULTILINE - ); -} diff --git a/libreport/src/lib/overlapping_strcpy.c b/libreport/src/lib/overlapping_strcpy.c deleted file mode 100644 index 3301024f..00000000 --- a/libreport/src/lib/overlapping_strcpy.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ -#include "libreport.h" - -/* Like strcpy but can copy overlapping strings. */ -void overlapping_strcpy(char *dst, const char *src) -{ - /* Cheap optimization for dst == src case - - * better to have it here than in many callers. - */ - if (dst != src) - { - while ((*dst = *src) != '\0') - { - dst++; - src++; - } - } -} diff --git a/libreport/src/lib/parse_options.c b/libreport/src/lib/parse_options.c deleted file mode 100644 index f2f876b3..00000000 --- a/libreport/src/lib/parse_options.c +++ /dev/null @@ -1,251 +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 <getopt.h> -#include "libreport.h" -#include "parse_options.h" - -#define USAGE_OPTS_WIDTH 30 -#define USAGE_GAP 2 - -const char *g_progname; - -const char *abrt_init(char **argv) -{ - char *env_verbose = getenv("ABRT_VERBOSE"); - if (env_verbose) - g_verbose = atoi(env_verbose); - - g_progname = strrchr(argv[0], '/'); - if (g_progname) - g_progname++; - else - g_progname = argv[0]; - - char *pfx = getenv("ABRT_PROG_PREFIX"); - if (pfx && string_to_bool(pfx)) - msg_prefix = g_progname; - - return g_progname; -} - -void export_abrt_envvars(int pfx) -{ - putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); - if (pfx) - { - putenv((char*)"ABRT_PROG_PREFIX=1"); - msg_prefix = g_progname; - } -} - -void show_usage_and_die(const char *usage, const struct options *opt) -{ - fputs(_("Usage: "), stderr); - while (*usage) - { - int len = strchrnul(usage, '\b') - usage; - if (len > 0) - { - fprintf(stderr, "%.*s", len, usage); - usage += len; - } - if (*usage == '\b') - { - fputs(g_progname, stderr); - usage++; - } - } - fputs("\n\n", stderr); - - for (; opt->type != OPTION_END; opt++) - { - size_t pos; - int pad; - - if (opt->type == OPTION_GROUP) - { - fputc('\n', stderr); - if (*opt->help) - fprintf(stderr, "%s\n", opt->help); - continue; - } - - pos = fprintf(stderr, " "); - if (opt->short_name) - pos += fprintf(stderr, "-%c", opt->short_name); - - if (opt->short_name && opt->long_name) - pos += fprintf(stderr, ", "); - - if (opt->long_name) - pos += fprintf(stderr, "--%s", opt->long_name); - - if (opt->argh) - { - const char *fmt = " %s"; - if (opt->type == OPTION_OPTSTRING) - fmt = "[%s]"; - pos += fprintf(stderr, fmt, opt->argh); - } - - if (pos <= USAGE_OPTS_WIDTH) - pad = USAGE_OPTS_WIDTH - pos; - else - { - fputc('\n', stderr); - pad = USAGE_OPTS_WIDTH; - } - fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opt->help); - } - fputc('\n', stderr); - exit(1); -} - -static int parse_opt_size(const struct options *opt) -{ - unsigned size = 0; - for (; opt->type != OPTION_END; opt++) - size++; - - return size; -} - -unsigned parse_opts(int argc, char **argv, const struct options *opt, - const char *usage) -{ - int help = 0; - int size = parse_opt_size(opt); - const int LONGOPT_OFFSET = 256; - - struct strbuf *shortopts = strbuf_new(); - - struct option *longopts = xzalloc(sizeof(longopts[0]) * (size+2)); - struct option *curopt = longopts; - int ii; - for (ii = 0; ii < size; ++ii) - { - curopt->name = opt[ii].long_name; - /*curopt->flag = 0; - xzalloc did it */ - if (opt[ii].short_name) - curopt->val = opt[ii].short_name; - else - curopt->val = LONGOPT_OFFSET + ii; - - switch (opt[ii].type) - { - case OPTION_BOOL: - curopt->has_arg = no_argument; - if (opt[ii].short_name) - strbuf_append_char(shortopts, opt[ii].short_name); - break; - case OPTION_INTEGER: - case OPTION_STRING: - case OPTION_LIST: - curopt->has_arg = required_argument; - if (opt[ii].short_name) - strbuf_append_strf(shortopts, "%c:", opt[ii].short_name); - break; - case OPTION_OPTSTRING: - curopt->has_arg = optional_argument; - if (opt[ii].short_name) - strbuf_append_strf(shortopts, "%c::", opt[ii].short_name); - break; - case OPTION_GROUP: - case OPTION_END: - break; - } - //log("curopt[%d].name:'%s' .has_arg:%d .flag:%p .val:%d", (int)(curopt-longopts), - // curopt->name, curopt->has_arg, curopt->flag, curopt->val); - /* - * getopt_long() thinks that NULL name marks the end of longopts. - * Example: - * [0] name:'verbose' val:'v' - * [1] name:NULL val:'c' - * [2] name:'force' val:'f' - * ... ... ... - * In this case, --force won't be accepted! - * Therefore we can only advance if name is not NULL. - */ - if (curopt->name) - curopt++; - } - curopt->name = "help"; - curopt->has_arg = no_argument; - curopt->flag = &help; - curopt->val = 1; - /* xzalloc did it already: - curopt++; - curopt->name = NULL; - curopt->has_arg = 0; - curopt->flag = NULL; - curopt->val = 0; - */ - - unsigned retval = 0; - while (1) - { - int c = getopt_long(argc, argv, shortopts->buf, longopts, NULL); - - if (c == -1) - break; - - if (c == '?' || help) - { - free(longopts); - strbuf_free(shortopts); - show_usage_and_die(usage, opt); - } - - for (ii = 0; ii < size; ++ii) - { - if (opt[ii].short_name == c || LONGOPT_OFFSET + ii == c) - { - if (ii < sizeof(retval)*8) - retval |= (1 << ii); - - if (opt[ii].value != NULL) switch (opt[ii].type) - { - case OPTION_BOOL: - *(int*)(opt[ii].value) += 1; - break; - case OPTION_INTEGER: - *(int*)(opt[ii].value) = xatoi(optarg); - break; - case OPTION_STRING: - case OPTION_OPTSTRING: - if (optarg) - *(char**)(opt[ii].value) = (char*)optarg; - break; - case OPTION_LIST: - *(GList**)(opt[ii].value) = g_list_append(*(GList**)(opt[ii].value), optarg); - break; - case OPTION_GROUP: - case OPTION_END: - break; - } - } - } - } - - free(longopts); - strbuf_free(shortopts); - - return retval; -} diff --git a/libreport/src/lib/parse_release.c b/libreport/src/lib/parse_release.c deleted file mode 100644 index 0071cfe3..00000000 --- a/libreport/src/lib/parse_release.c +++ /dev/null @@ -1,81 +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 "libreport.h" - -// caller is reposible for freeing *product* and *version* -static void parse_release(const char *release, char** product, char** version, bool append_rhel_version) -{ - if (strstr(release, "Rawhide")) - { - *product = xstrdup("Fedora"); - *version = xstrdup("rawhide"); - VERB3 log("%s: version:'%s' product:'%s'", __func__, *version, *product); - return; - } - - struct strbuf *buf_product = strbuf_new(); - if (strstr(release, "Fedora")) - strbuf_append_str(buf_product, "Fedora"); - else if (strstr(release, "Red Hat Enterprise Linux")) - strbuf_append_str(buf_product, "Red Hat Enterprise Linux"); - else - { - /* TODO: add logic for parsing other distros' names here */ - strbuf_append_str(buf_product, release); - } - - const char *r = strstr(release, "release"); - const char *space = r ? strchr(r, ' ') : NULL; - - struct strbuf *buf_version = strbuf_new(); - if (space) - { - space++; - while (*space != '\0' && *space != ' ') - { - /* Eat string like "5.2" */ - strbuf_append_char(buf_version, *space); - if (append_rhel_version - && strcmp(buf_product->buf, "Red Hat Enterprise Linux") == 0 - ) { - strbuf_append_char(buf_product, ' '); - strbuf_append_char(buf_product, *space); - } - append_rhel_version = false; - space++; - } - } - - *version = strbuf_free_nobuf(buf_version); - *product = strbuf_free_nobuf(buf_product); - - VERB3 log("%s: version:'%s' product:'%s'", __func__, *version, *product); -} - -void parse_release_for_bz(const char *release, char** product, char** version) -{ - /* Fedora/RH bugzilla uses "Red Hat Enterprise Linux N" product RHEL */ - parse_release(release, product, version, /*append_rhel_version:*/ true); -} - -void parse_release_for_rhts(const char *release, char** product, char** version) -{ - /* RHTS uses "Red Hat Enterprise Linux" product for RHEL */ - parse_release(release, product, version, /*append_rhel_version:*/ false); -} diff --git a/libreport/src/lib/problem_data.c b/libreport/src/lib/problem_data.c deleted file mode 100644 index ed88f9d8..00000000 --- a/libreport/src/lib/problem_data.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - Copyright (C) 2010 Denys Vlasenko (dvlasenk@redhat.com) - 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 "libreport.h" - -static void free_problem_item(void *ptr) -{ - if (ptr) - { - struct problem_item *item = (struct problem_item *)ptr; - free(item->content); - free(item); - } -} - -char *format_problem_item(struct problem_item *item) -{ - if (!item) - return xstrdup("(nullitem)"); - - if (item->flags & CD_FLAG_UNIXTIME) - { - errno = 0; - char *end; - time_t time = strtol(item->content, &end, 10); - if (!errno && !*end && end != item->content) - { - char timeloc[256]; - int success = strftime(timeloc, sizeof(timeloc), "%c", localtime(&time)); - if (success) - return xstrdup(timeloc); - } - } - return NULL; -} - -/* problem_data["name"] = { "content", CD_FLAG_foo_bits } */ - -problem_data_t *new_problem_data(void) -{ - return g_hash_table_new_full(g_str_hash, g_str_equal, - free, free_problem_item); -} - -void add_basics_to_problem_data(problem_data_t *pd) -{ - const char *analyzer = get_problem_item_content_or_NULL(pd, FILENAME_ANALYZER); - if (analyzer == NULL) - add_to_problem_data(pd, "analyzer", "libreport"); - - /* If application didn't provide dupe hash, we generate it - * from all components, so we at least eliminate the exact same - * reports - */ - if (get_problem_item_content_or_NULL(pd, FILENAME_DUPHASH) == NULL) - { - /* start hash */ - sha1_ctx_t sha1ctx; - sha1_begin(&sha1ctx); - - /* - * To avoid spurious hash differences, sort keys so that elements are - * always processed in the same order: - */ - GList *list = g_hash_table_get_keys(pd); - list = g_list_sort(list, (GCompareFunc)strcmp); - GList *l = list; - while (l) - { - const char *key = l->data; - l = l->next; - struct problem_item *item = g_hash_table_lookup(pd, key); - /* do not hash items which are binary (item->flags & CD_FLAG_BIN). - * Their ->content is full file name, with path. Path is always - * different and will make hash differ even if files are the same. - */ - if (item->flags & CD_FLAG_BIN) - continue; - sha1_hash(&sha1ctx, item->content, strlen(item->content)); - } - g_list_free(list); - - /* end hash */ - char hash_bytes[SHA1_RESULT_LEN]; - sha1_end(&sha1ctx, hash_bytes); - char hash_str[SHA1_RESULT_LEN*2 + 1]; - bin2hex(hash_str, hash_bytes, SHA1_RESULT_LEN)[0] = '\0'; - - add_to_problem_data(pd, FILENAME_DUPHASH, hash_str); - } - - pid_t pid = getpid(); - if (pid > 0) - { - char buf[PATH_MAX+1]; - char *exe = xasprintf("/proc/%u/exe", pid); - ssize_t read = readlink(exe, buf, PATH_MAX); - if (read > 0) - { - buf[read] = 0; - VERB2 log("reporting initiated from: %s", buf); - add_to_problem_data(pd, FILENAME_EXECUTABLE, buf); - } - free(exe); - -//#ifdef WITH_RPM - /* FIXME: component should be taken from rpm using librpm - * which means we need to link against it :( - * or run rpm -qf executable ?? - */ - /* Fedora/RHEL rpm specific piece of code */ - const char *component = get_problem_item_content_or_NULL(pd, FILENAME_COMPONENT); - //FIXME: this REALLY needs to go away, or every report will be assigned to abrt - if (component == NULL) // application didn't specify component - add_to_problem_data(pd, FILENAME_COMPONENT, "abrt"); -//#endif - } -} - -void add_to_problem_data_ext(problem_data_t *problem_data, - const char *name, - const char *content, - unsigned flags) -{ - if (!(flags & CD_FLAG_BIN)) - flags |= CD_FLAG_TXT; - if (!(flags & CD_FLAG_ISEDITABLE)) - flags |= CD_FLAG_ISNOTEDITABLE; - - struct problem_item *item = (struct problem_item *)xzalloc(sizeof(*item)); - item->content = xstrdup(content); - item->flags = flags; - g_hash_table_replace(problem_data, xstrdup(name), item); -} - -void add_to_problem_data(problem_data_t *problem_data, - const char *name, - const char *content) -{ - add_to_problem_data_ext(problem_data, name, content, CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE); -} - -const char *get_problem_item_content_or_die(problem_data_t *problem_data, const char *key) -{ - struct problem_item *item = get_problem_data_item_or_NULL(problem_data, key); - if (!item) - error_msg_and_die("Error accessing problem data: no ['%s']", key); - return item->content; -} - -const char *get_problem_item_content_or_NULL(problem_data_t *problem_data, const char *key) -{ - struct problem_item *item = get_problem_data_item_or_NULL(problem_data, key); - if (!item) - return NULL; - return item->content; -} - - -/* Miscellaneous helpers */ - -static const char *const editable_files[] = { - FILENAME_COMMENT , - FILENAME_BACKTRACE, - NULL -}; -static bool is_editable_file(const char *file_name) -{ - return is_in_string_list(file_name, (char**)editable_files); -} - -static const char *const always_text_files[] = { - FILENAME_CMDLINE , - FILENAME_BACKTRACE, - NULL -}; -static char* is_text_file(const char *name, ssize_t *sz) -{ - /* We were using magic.h API to check for file being text, but it thinks - * that file containing just "0" is not text (!!) - * So, we do it ourself. - */ - - int fd = open(name, O_RDONLY); - if (fd < 0) - return NULL; /* it's not text (because it does not exist! :) */ - - /* Maybe 64k limit is small. But _some_ limit is necessary: - * fields declared "text" may end up in editing fields and such. - * We don't want to accidentally end up with 100meg text in a textbox! - * So, don't remove this. If you really need to, raise the limit. - * - * Bumped up to 200k: saw 124740 byte /proc/PID/smaps file - */ - off_t size = lseek(fd, 0, SEEK_END); - if (size < 0 || size > 200*1024) - { - close(fd); - return NULL; /* it's not a SMALL text */ - } - lseek(fd, 0, SEEK_SET); - - char *buf = (char*)xmalloc(*sz); - ssize_t r = full_read(fd, buf, *sz); - close(fd); - if (r < 0) - { - free(buf); - return NULL; /* it's not text (because we can't read it) */ - } - if (r < *sz) - buf[r] = '\0'; - *sz = r; - - /* Some files in our dump directories are known to always be textual */ - const char *base = strrchr(name, '/'); - if (base) - { - base++; - if (is_in_string_list(base, (char**)always_text_files)) - return buf; - } - - /* Every once in a while, even a text file contains a few garbled - * or unexpected non-ASCII chars. We should not declare it "binary". - */ - const unsigned RATIO = 50; - unsigned total_chars = r + RATIO; - unsigned bad_chars = 1; /* 1 prevents division by 0 later */ - while (--r >= 0) - { - if (buf[r] >= 0x7f - /* among control chars, only '\t','\n' etc are allowed */ - || (buf[r] < ' ' && !isspace(buf[r])) - ) { - if (buf[r] == '\0') - { - /* We don't like NULs very much. Not text for sure! */ - free(buf); - return NULL; - } - bad_chars++; - } - } - - if ((total_chars / bad_chars) >= RATIO) - return buf; /* looks like text to me */ - - free(buf); - return NULL; /* it's binary */ -} - -void load_problem_data_from_dump_dir(problem_data_t *problem_data, struct dump_dir *dd, char **excluding) -{ - char *short_name; - char *full_name; - - dd_init_next_file(dd); - while (dd_get_next_file(dd, &short_name, &full_name)) - { - if (excluding && is_in_string_list(short_name, excluding)) - { - //log("Excluded:'%s'", short_name); - goto next; - } - - ssize_t sz = 4*1024; - char *text = NULL; - bool editable = is_editable_file(short_name); - - if (!editable) - { - text = is_text_file(full_name, &sz); - if (!text) - { - add_to_problem_data_ext(problem_data, - short_name, - full_name, - CD_FLAG_BIN + CD_FLAG_ISNOTEDITABLE - ); - goto next; - } - } - - char *content; - if (sz < 4*1024) /* did is_text_file read entire file? */ - { - /* yes */ - content = text; - } - else - { - /* no, need to read it all */ - free(text); - content = dd_load_text(dd, short_name); - } - /* Strip '\n' from one-line elements: */ - char *nl = strchr(content, '\n'); - if (nl && nl[1] == '\0') - *nl = '\0'; - - int flags = 0; - - if (editable) - flags |= CD_FLAG_TXT | CD_FLAG_ISEDITABLE; - else - flags |= CD_FLAG_TXT | CD_FLAG_ISNOTEDITABLE; - - static const char *const list_files[] = { - FILENAME_UID , - FILENAME_PACKAGE , - FILENAME_EXECUTABLE, - FILENAME_TIME , - FILENAME_COUNT , - NULL - }; - if (is_in_string_list(short_name, (char**)list_files)) - flags |= CD_FLAG_LIST; - - if (strcmp(short_name, FILENAME_TIME) == 0) - flags |= CD_FLAG_UNIXTIME; - - add_to_problem_data_ext(problem_data, - short_name, - content, - flags - ); - free(content); - next: - free(short_name); - free(full_name); - } -} - -problem_data_t *create_problem_data_from_dump_dir(struct dump_dir *dd) -{ - problem_data_t *problem_data = new_problem_data(); - load_problem_data_from_dump_dir(problem_data, dd, NULL); - return problem_data; -} - -/* - * Returns NULL-terminated char *vector[]. Result itself must be freed, - * but do no free list elements. IOW: do free(result), but never free(result[i])! - * If comma_separated_list is NULL or "", returns NULL. - */ -static char **build_exclude_vector(const char *comma_separated_list) -{ - char **exclude_items = NULL; - if (comma_separated_list && comma_separated_list[0]) - { - /* even w/o commas, we'll need two elements: - * exclude_items[0] = "name" - * exclude_items[1] = NULL - */ - unsigned cnt = 2; - - const char *cp = comma_separated_list; - while (*cp) - if (*cp++ == ',') - cnt++; - - /* We place the string directly after the char *vector[cnt]: */ - exclude_items = xzalloc(cnt * sizeof(exclude_items[0]) + (cp - comma_separated_list) + 1); - char *p = strcpy((char*)&exclude_items[cnt], comma_separated_list); - - char **pp = exclude_items; - *pp++ = p; - while (*p) - { - if (*p++ == ',') - { - p[-1] = '\0'; - *pp++ = p; - } - } - } - - return exclude_items; -} - -problem_data_t *create_problem_data_for_reporting(const char *dump_dir_name) -{ - char **exclude_items = build_exclude_vector(getenv("EXCLUDE_FROM_REPORT")); - struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); - if (!dd) - return NULL; /* dd_opendir already emitted error msg */ - problem_data_t *problem_data = new_problem_data(); - load_problem_data_from_dump_dir(problem_data, dd, exclude_items); - dd_close(dd); - free(exclude_items); - return problem_data; -} - -void log_problem_data(problem_data_t *problem_data, const char *pfx) -{ - GHashTableIter iter; - char *name; - struct problem_item *value; - g_hash_table_iter_init(&iter, problem_data); - while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value)) - { - log("%s[%s]:'%s' 0x%x", - pfx, name, - value->content, - value->flags - ); - } -} diff --git a/libreport/src/lib/read_write.c b/libreport/src/lib/read_write.c deleted file mode 100644 index a3bbb58f..00000000 --- a/libreport/src/lib/read_write.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Utility routines. - * - * Licensed under GPLv2 or later, see file COPYING in this tarball for details. - */ -#include "libreport.h" - -/* Die with an error message if we can't read the entire buffer. */ -void xread(int fd, void *buf, size_t count) -{ - if (count) - { - ssize_t size = full_read(fd, buf, count); - if ((size_t)size != count) - error_msg_and_die("short read"); - } -} - -ssize_t safe_read(int fd, void *buf, size_t count) -{ - ssize_t n; - - do { - n = read(fd, buf, count); - } while (n < 0 && errno == EINTR); - - return n; -} - -ssize_t safe_write(int fd, const void *buf, size_t count) -{ - ssize_t n; - - do { - n = write(fd, buf, count); - } while (n < 0 && errno == EINTR); - - return n; -} - -ssize_t full_read(int fd, void *buf, size_t len) -{ - ssize_t cc; - ssize_t total; - - total = 0; - - while (len) - { - cc = safe_read(fd, buf, len); - - if (cc < 0) - { - if (total) - { - /* we already have some! */ - /* user can do another read to know the error code */ - return total; - } - return cc; /* read() returns -1 on failure. */ - } - if (cc == 0) - break; - buf = ((char *)buf) + cc; - total += cc; - len -= cc; - } - - return total; -} - -ssize_t full_write(int fd, const void *buf, size_t len) -{ - ssize_t cc; - ssize_t total; - - total = 0; - - while (len) - { - cc = safe_write(fd, buf, len); - - if (cc < 0) - { - if (total) - { - /* we already wrote some! */ - /* user can do another write to know the error code */ - return total; - } - return cc; /* write() returns -1 on failure. */ - } - - total += cc; - buf = ((const char *)buf) + cc; - len -= cc; - } - - return total; -} - -ssize_t full_write_str(int fd, const char *buf) -{ - return full_write(fd, buf, strlen(buf)); -} diff --git a/libreport/src/lib/report.c b/libreport/src/lib/report.c deleted file mode 100644 index 9b5df02d..00000000 --- a/libreport/src/lib/report.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - Copyright (C) 2011 ABRT Team - Copyright (C) 2011 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 "libreport.h" -#include "report.h" - -int report_problem_in_dir(const char *dirname, int flags) -{ - const char *path; - /* - if is isatty - -> run cli reporter - path = "cli" - */ - - char *args[5], **pp; - pp = args; - *pp++ = (char *)"bug-reporting-wizard"; - if (!(flags & LIBREPORT_ANALYZE)) - *pp++ = (char *)"--report-only"; - *pp++ = (char *)"--"; - *pp++ = (char *)dirname; - *pp++ = NULL; - - pid_t pid = vfork(); - if (pid < 0) /* error */ - { - perror_msg("vfork"); - return -1; - } - - if (pid == 0) /* child */ - { - /* Some callers set SIGCHLD to SIG_IGN. - * However, reporting spawns child processes. - * Suppressing child death notification terribly confuses some of them. - * Just in case, undo it. - * Note that we do it in the child, so the parent is never affected. - */ - signal(SIGCHLD, SIG_DFL); - path = BIN_DIR"/bug-reporting-wizard"; - VERB1 log("Executing: %s", path); - execv(path, args); - /* Did not find the desired executable in the installation directory. - * Trying to find it in PATH - */ - path = "bug-reporting-wizard"; - execvp(path, args); - perror_msg_and_die("Can't execute %s", path); - } - - /* parent */ - if (flags & LIBREPORT_WAIT) - { - int status; - pid_t p = waitpid(pid, &status, 0); - if (p <= 0) - { - perror_msg("can't waitpid"); - return -1; - } - if (WIFEXITED(status)) - { - VERB2 log("reporting finished with exitcode %d", WEXITSTATUS(status)); - return WEXITSTATUS(status); - } - /* child died from a signal: WIFSIGNALED(status) should be true */ - VERB2 log("reporting killed by signal %d", WTERMSIG(status)); - return WTERMSIG(status) + 128; - } - - return 0; -} - -int report_problem_in_memory(problem_data_t *pd, int flags) -{ - int result = 0; - struct dump_dir *dd = create_dump_dir_from_problem_data(pd, "/tmp"/* /var/tmp ?? */); - if (!dd) - return -1; - char *dir_name = xstrdup(dd->dd_dirname); - dd_close(dd); - VERB2 log("Temp problem dir: '%s'", dir_name); - -// TODO: if !LIBREPORT_WAIT pass LIBREPORT_DEL_DIR, and teach bug-reporting-wizard -// an option to delete directory after reporting? -// It will make !LIBREPORT_WAIT reporting possible - result = report_problem_in_dir(dir_name, flags); - - /* If we wait for reporter to finish, we should clean the tmp dir. - * We can also reload the problem data if requested. - */ - if (flags & LIBREPORT_WAIT) - { - if (flags & LIBREPORT_RELOAD_DATA) - g_hash_table_remove_all(pd); - dd = dd_opendir(dir_name, 0); - if (dd) - { - if (flags & LIBREPORT_RELOAD_DATA) - load_problem_data_from_dump_dir(pd, dd, NULL); - dd_delete(dd); - } - } - - free(dir_name); - return result; -} - -int report_problem(problem_data_t *pd) -{ - return report_problem_in_memory(pd, LIBREPORT_WAIT); -} diff --git a/libreport/src/lib/report_event.conf b/libreport/src/lib/report_event.conf deleted file mode 100644 index a99ce8ab..00000000 --- a/libreport/src/lib/report_event.conf +++ /dev/null @@ -1,47 +0,0 @@ -# This configuration file specifies which programs should be run -# when the specified event occurs in dump directory lifetime. -# -# It consists of directives and rules. -# -# Directives start with a reserved word. Currently, there is only one -# directive, "include". Its format is "include FILE". -# It causes files which match FILE to be read and -# parsed as if they are inserted textually where this directive -# occurs. FILE can use shell pattern metacharacters (*,?,etc) to -# specify multiple files. Relative paths are interpreted relative -# to current file. -# -# Rule starts with a line with non-space leading character. -# All subsequent lines which start with space or tab form one rule. -# Note that separating newline is *retained*. Example: -# EVENT=post-create date >/tmp/dt # semicolon is not needed here! -# echo $HOSTNAME `uname -r` -# -# Rules may be commented out with #. One # is sufficient to comment out -# even a multi-line rule (no need to comment out every line). -# -# Rules specify which programs to run on the dump directory. -# Each rule may have conditions to be checked before the program is run. -# -# Conditions have form VAR=VAL or VAL~=REGEX, where VAR is either -# word "EVENT" or a name of dump directory element to be checked -# (for example, "executable", "package", hostname" etc). -# -# If all conditions match, the remaining part of the rule -# (the "program" part) is run in the shell. -# All shell language constructs are valid. -# All stdout and stderr output is captured and passed to abrt -# and possibly to abrt's frontends and shown to the user. -# -# If the program terminates with nonzero exit code, -# the event processing is considered unsuccessful and is stopped. -# Last captured output line, if any, is considered to be -# the error message indicating the reason of the failure, -# and may be used by abrt as such. -# -# If the program terminates successfully, next rule is read -# and processed. This process is repeated until the end of this file. - -include events.d/*.conf - -EVENT=report_Dummy analyzer=libreport echo "Hello world" >> /tmp/libreport.log diff --git a/libreport/src/lib/run_event.c b/libreport/src/lib/run_event.c deleted file mode 100644 index 0457364a..00000000 --- a/libreport/src/lib/run_event.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - 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 <glob.h> -#include <regex.h> -#include "libreport.h" - -struct run_event_state *new_run_event_state() -{ - return xzalloc(sizeof(struct run_event_state)); -} - -void free_run_event_state(struct run_event_state *state) -{ - if (state) - { - free_commands(state); - free(state); - } -} - - -/* Asynchronous command execution */ - -/* It is not yet clear whether we need to re-parse event config file - * and re-check the elements in dump dir after each command. - * - * Consider this config file: - * - * EVENT=e cmd1 - * EVENT=e foo=bar cmd2 - * EVENT=e foo=baz cmd3 - * - * Imagine that element foo existed and was equal to bar at the beginning. - * After cmd1, should we execute cmd2 if element foo disappeared? - * After cmd1/2, should we execute cmd3 if element foo changed value to baz? - * - * We used to read entire config file and select a list of commands to execute, - * checking all conditions in the beginning. It is a bit more simple to code up. - * - * This proved to be bad for use cases where, for example, post-create rule - * for a specified package needs to run: - * - * EVENT=post-create - * abrt-action-save-package-data - * EVENT=post-create component=mypkg - * my_handling - * - * Problem here is that "component" element is created by - * abrt-action-save-package-data! Pre-selecting rules excludes second rule. - * - * Now we read entire config but do NOT select commands to execute, - * we check conditions of every next rule *directly before its execution*. - * - * It's possible we'd want to switch to an algorightm which makes in unnecessary - * to properly order rules in config files(s). Now these two rules must not - * be reordered, or else second one won't work: - * EVENT=post-create echo foo >bar - * EVENT=post-create foo=bar do_something - * but this might be not so easy to ensure when include files are involved... - * - * Anyway, list of commands machinery is encapsulated in struct run_event_state, - * and public async API: - * prepare_commands(state, dir, event); - * spawn_next_command(state, dir, event); - * free_commands(state); - * does not expose the way we select rules to execute. - */ -struct rule { - GList *conditions; - char *command; /* never NULL */ -}; - -static void free_rule_list(GList *rule_list) -{ - while (rule_list) - { - struct rule *cur_rule = rule_list->data; - list_free_with_free(cur_rule->conditions); - free(cur_rule->command); - free(cur_rule); - - GList *next = rule_list->next; - g_list_free_1(rule_list); - rule_list = next; - } -} - -/* Stop-gap measure against infinite recursion */ -#define MAX_recursion_depth 32 - -static GList *load_rule_list(GList *rule_list, - const char *conf_file_name, - unsigned recursion_depth -) { - FILE *conffile = fopen(conf_file_name, "r"); - if (!conffile) - { - error_msg("Can't open '%s'", conf_file_name); - return rule_list; - } - - /* Read and remember rules */ - char *next_line = xmalloc_fgetline(conffile); - while (next_line) - { - /* Read and concatenate all lines in a rule */ - char *line = next_line; - while (1) - { - next_line = xmalloc_fgetline(conffile); - if (!next_line || !isblank(next_line[0])) - break; - char *old_line = line; - line = xasprintf("%s\n%s", line, next_line); - free(old_line); - free(next_line); - } - - char *p = skip_whitespace(line); - if (*p == '\0' || *p == '#') - goto next_line; /* empty or comment line, skip */ - - //VERB3 log("%s: line '%s'", __func__, p); - - /* Handle "include" directive */ - if (recursion_depth < MAX_recursion_depth - && strncmp(p, "include", strlen("include")) == 0 - && isblank(p[strlen("include")]) - ) { - /* "include GLOB_PATTERN" */ - p = skip_whitespace(p + strlen("include")); - - const char *last_slash; - char *name_to_glob; - if (*p != '/' - && (last_slash = strrchr(conf_file_name, '/')) != NULL - ) - /* GLOB_PATTERN is relative, and this include is in path/to/file.conf - * Construct path/to/GLOB_PATTERN: - */ - name_to_glob = xasprintf("%.*s%s", (int)(last_slash - conf_file_name + 1), conf_file_name, p); - else - /* Either GLOB_PATTERN is absolute, or this include is in file.conf - * (no slashes in its name). Use unchanged GLOB_PATTERN: - */ - name_to_glob = xstrdup(p); - - glob_t globbuf; - memset(&globbuf, 0, sizeof(globbuf)); - //VERB3 log("%s: globbing '%s'", __func__, name_to_glob); - glob(name_to_glob, 0, NULL, &globbuf); - free(name_to_glob); - char **name = globbuf.gl_pathv; - if (name) while (*name) - { - //VERB3 log("%s: recursing into '%s'", __func__, *name); - rule_list = load_rule_list(rule_list, *name, recursion_depth + 1); - //VERB3 log("%s: returned from '%s'", __func__, *name); - name++; - } - globfree(&globbuf); - goto next_line; - } - - /* Rule has form: [VAR=VAL]... PROG [ARGS] */ - struct rule *cur_rule = xzalloc(sizeof(*cur_rule)); - - while (1) /* word loop */ - { - char *end_word = skip_non_whitespace(p); - - /* If there is no '=' in this word... */ - char *line_val = strchr(p, '='); - if (!line_val || line_val >= end_word) - break; /* ...we found the start of a command */ - - cur_rule->conditions = g_list_append(cur_rule->conditions, xstrndup(p, end_word - p)); - - /* Go to next word */ - p = skip_whitespace(end_word); - } /* end of word loop */ - - VERB1 log("Adding '%s'", p); - cur_rule->command = xstrdup(p); - - rule_list = g_list_append(rule_list, cur_rule); - - next_line: - free(line); - } /* end of line loop */ - - fclose(conffile); - - return rule_list; -} - -static int regcmp_lines(char *val, const char *regex) -{ - regex_t rx; - int r = regcomp(&rx, regex, REG_NOSUB); //TODO: and REG_EXTENDED? - //log("REGEX:'%s':%d", regex, r); - if (r) - { - //char errbuf[256]; - //size_t needsz = regerror(r, &rx, errbuf, sizeof(errbuf)); - error_msg("Bad regexp '%s'", regex); // TODO: use errbuf? - return r; - } - - /* Check every line */ - while (1) - { - char *eol = strchr(val, '\n'); - if (eol) - *eol = '\0'; - r = regexec(&rx, val, 0, NULL, /*eflags:*/ 0); - //log("REGCMP:'%s':%d", val, r); - if (eol) - *eol = '\n'; - if (r == 0 || !eol) - break; - val = eol + 1; - } - /* Here, r == 0 if match was found */ - regfree(&rx); - return r; -} - -/* Deletes rules in *pp_rule_list, starting from first (remaining) rule, - * until it finds a rule with all conditions satisfied. - * In this case, it deletes this rule and returns this rule's cmd. - * Else (if it didn't find such rule), it deletes all rules and returns NULL. - * In case of error (dump_dir can't be opened), deletes all rules and returns NULL. - * - * Intended usage: - * list = load_rule_list(...); - * while ((cmd = pop_next_command(&list, ...)) != NULL) - * run(cmd); - */ -static char* pop_next_command(GList **pp_rule_list, - char **pp_event_name, /* reports EVENT value thru this, if not NULL on entry */ - struct dump_dir **pp_dd, /* use *pp_dd for access to dump dir, if non-NULL */ - const char *dump_dir_name, - const char *pfx, - unsigned pfx_len -) -{ - char *command = NULL; - struct dump_dir *dd = pp_dd ? *pp_dd : NULL; - - GList *rule_list = *pp_rule_list; - while (rule_list) - { - struct rule *cur_rule = rule_list->data; - - GList *condition = cur_rule->conditions; - while (condition) - { - const char *cond_str = condition->data; - const char *eq_sign = strchr(cond_str, '='); - - /* Is it "EVENT=foo"? */ - if (strncmp(cond_str, "EVENT=", 6) == 0) - { - if (strncmp(eq_sign + 1, pfx, pfx_len) != 0) - goto next_rule; /* prefix doesn't match */ - if (pp_event_name) - { - free(*pp_event_name); - *pp_event_name = xstrdup(eq_sign + 1); - } - } - else - { - /* Read from dump dir and compare */ - if (!dd) - { - /* Without dir to match, we assume match for all conditions */ - if (!dump_dir_name) - goto next_cond; - dd = dd_opendir(dump_dir_name, /*flags:*/ 0); - if (!dd) - { - free_rule_list(rule_list); - *pp_rule_list = NULL; - goto ret; /* error (note: dd_opendir logged error msg) */ - } - } - /* Is it "VAR~=REGEX"? */ - int regex = (eq_sign > cond_str && eq_sign[-1] == '~'); - char *var_name = xstrndup(cond_str, eq_sign - cond_str - regex); - char *real_val = dd_load_text_ext(dd, var_name, DD_FAIL_QUIETLY_ENOENT); - free(var_name); - int vals_differ = regex ? regcmp_lines(real_val, eq_sign + 1) : strcmp(real_val, eq_sign + 1); - free(real_val); - - /* Do values match? */ - if (vals_differ) /* no */ - { - //VERB3 log("var '%s': '%.*s'!='%s', skipping line", - // p, - // (int)(strchrnul(real_val, '\n') - real_val), real_val, - // eq_sign); - goto next_rule; - } - } - next_cond: - /* We are here if current condition is satisfied */ - - condition = condition->next; - } - /* We are here if all conditions are satisfied */ - - command = cur_rule->command; - - next_rule: - *pp_rule_list = rule_list->next; - g_list_free_1(rule_list); - - list_free_with_free(cur_rule->conditions); - /*free(cur_rule->command); - WRONG! we might be returning it! */ - if (command) - { - /* We found rule to run, return it */ - free(cur_rule); - break; - } - free(cur_rule->command); /* _now_ it is ok */ - free(cur_rule); - - rule_list = *pp_rule_list; - } /* while (rule_list) */ - - ret: - if (pp_dd) - *pp_dd = dd; - else - dd_close(dd); - return command; -} - -void free_commands(struct run_event_state *state) -{ - free_rule_list(state->rule_list); - state->rule_list = NULL; - state->command_out_fd = -1; - state->command_pid = 0; -} - -int prepare_commands(struct run_event_state *state, - const char *dump_dir_name, - const char *event -) { - free_commands(state); - - state->children_count = 0; - - GList *rule_list = load_rule_list(NULL, CONF_DIR"/report_event.conf", /*recursion_depth:*/ 0); - state->rule_list = rule_list; - return rule_list != NULL; -} - -int spawn_next_command(struct run_event_state *state, - const char *dump_dir_name, - const char *event -) { - char *cmd = pop_next_command(&state->rule_list, - NULL, /* don't return event_name */ - NULL, /* NULL &dd: we match by... */ - dump_dir_name, /* ...dirname */ - event, strlen(event)+1 /* for this event name exactly (not prefix) */ - ); - if (!cmd) - return -1; - - /* We count it even if fork fails. The counter isn't meant - * to count *successful* forks, it is meant to let caller know - * whether the event we run has *any* handlers configured, or not. - */ - state->children_count++; - - VERB1 log("Executing '%s'", cmd); - - /* Export some useful environment variables for children */ - char *env_vec[3]; - /* Just exporting dump_dir_name isn't always ok: it can be "." - * and some children want to cd to other directory but still - * be able to find dump directory by using $DUMP_DIR... - */ - char *full_name = realpath(dump_dir_name, NULL); - env_vec[0] = xasprintf("DUMP_DIR=%s", (full_name ? full_name : dump_dir_name)); - free(full_name); - env_vec[1] = xasprintf("EVENT=%s", event); - env_vec[2] = NULL; - - char *argv[4]; - argv[0] = (char*)"/bin/sh"; // TODO: honor $SHELL? - argv[1] = (char*)"-c"; - argv[2] = cmd; - argv[3] = NULL; - - int pipefds[2]; - state->command_pid = fork_execv_on_steroids( - EXECFLG_INPUT_NUL + EXECFLG_OUTPUT + EXECFLG_ERR2OUT, - argv, - pipefds, - /* env_vec: */ env_vec, - /* dir: */ dump_dir_name, - /* uid(unused): */ 0 - ); - state->command_out_fd = pipefds[0]; - - free(env_vec[0]); - free(env_vec[1]); - free(cmd); - - return 0; -} - - -/* Synchronous command execution: - */ -int run_event_on_dir_name(struct run_event_state *state, - const char *dump_dir_name, - const char *event -) { - prepare_commands(state, dump_dir_name, event); - - /* Execute every command in shell */ - - int retval = 0; - while (spawn_next_command(state, dump_dir_name, event) >= 0) - { - /* Consume log from stdout */ - FILE *fp = fdopen(state->command_out_fd, "r"); - if (!fp) - die_out_of_memory(); - char *buf; - while ((buf = xmalloc_fgetline(fp)) != NULL) - { - if (state->logging_callback) - buf = state->logging_callback(buf, state->logging_param); - free(buf); - } - fclose(fp); /* Got EOF, close. This also closes state->command_out_fd */ - - /* Wait for child to actually exit, collect status */ - int status; - waitpid(state->command_pid, &status, 0); - - retval = WEXITSTATUS(status); - if (WIFSIGNALED(status)) - retval = WTERMSIG(status) + 128; - if (retval != 0) - break; - - if (state->post_run_callback) - { - retval = state->post_run_callback(dump_dir_name, state->post_run_param); - if (retval != 0) - break; - } - } - - free_commands(state); - - return retval; -} - -int run_event_on_problem_data(struct run_event_state *state, problem_data_t *data, const char *event) -{ - state->children_count = 0; - - struct dump_dir *dd = create_dump_dir_from_problem_data(data, NULL); - if (!dd) - return -1; - char *dir_name = xstrdup(dd->dd_dirname); - dd_close(dd); - - int r = run_event_on_dir_name(state, dir_name, event); - - g_hash_table_remove_all(data); - dd = dd_opendir(dir_name, /*flags:*/ 0); - free(dir_name); - if (dd) - { - load_problem_data_from_dump_dir(data, dd, NULL); - dd_delete(dd); - } - - return r; -} - -char *list_possible_events(struct dump_dir *dd, const char *dump_dir_name, const char *pfx) -{ - struct strbuf *result = strbuf_new(); - - GList *rule_list = load_rule_list(NULL, CONF_DIR"/report_event.conf", /*recursion_depth:*/ 0); - - unsigned pfx_len = strlen(pfx); - for (;;) - { - /* Retrieve each cmd, and fetch its EVENT=foo value */ - char *event_name = NULL; - char *cmd = pop_next_command(&rule_list, - &event_name, /* return event_name */ - (dd ? &dd : NULL), /* match this dd... */ - dump_dir_name, /* ...or if NULL, this dirname */ - pfx, pfx_len /* for events with this prefix */ - ); - if (!cmd) - break; - free(cmd); - - if (event_name) - { - /* Append "EVENT\n" - only if it is not there yet */ - unsigned e_len = strlen(event_name); - char *p = result->buf; - while (p && *p) - { - if (strncmp(p, event_name, e_len) == 0 && p[e_len] == '\n') - goto skip; /* This event is already in the result */ - p = strchr(p, '\n'); - if (p) - p++; - } - strbuf_append_strf(result, "%s\n", event_name); - skip: - free(event_name); - } - } - - return strbuf_free_nobuf(result); -} diff --git a/libreport/src/lib/skip_whitespace.c b/libreport/src/lib/skip_whitespace.c deleted file mode 100644 index b2864e6f..00000000 --- a/libreport/src/lib/skip_whitespace.c +++ /dev/null @@ -1,22 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ -#include "libreport.h" - -char* skip_whitespace(const char *s) -{ - /* NB: isspace('\0') returns 0 */ - while (isspace(*s)) ++s; - - return (char *) s; -} - -char* skip_non_whitespace(const char *s) -{ - while (*s && !isspace(*s)) ++s; - - return (char *) s; -} diff --git a/libreport/src/lib/spawn.c b/libreport/src/lib/spawn.c deleted file mode 100644 index 2e09da27..00000000 --- a/libreport/src/lib/spawn.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Utility routines. - * - * Licensed under GPLv2, see file COPYING in this tarball for details. - */ -#include "libreport.h" - -static char *concat_str_vector(char **strings) -{ - if (!strings[0]) - return xzalloc(1); // returns "" - - unsigned len = 0; - char **spp = strings; - while (*spp) - len += strlen(*spp++) + 1; - - char *result = xmalloc(len); - - char *r = result; - spp = strings; - while (*spp) { - r = stpcpy(r, *spp++); - *r++ = ' '; - } - *--r = '\0'; - - return result; -} - -/* Returns pid */ -pid_t fork_execv_on_steroids(int flags, - char **argv, - int *pipefds, - char **env_vec, - const char *dir, - uid_t uid) -{ - pid_t child; - /* Reminder: [0] is read end, [1] is write end */ - int pipe_to_child[2]; - int pipe_fm_child[2]; - - /* Sanitize flags */ - if (!pipefds) - flags &= ~(EXECFLG_INPUT | EXECFLG_OUTPUT); - - if (flags & EXECFLG_INPUT) - xpipe(pipe_to_child); - if (flags & EXECFLG_OUTPUT) - xpipe(pipe_fm_child); - - fflush(NULL); - child = fork(); - if (child == -1) { - perror_msg_and_die("fork"); - } - if (child == 0) { - /* Child */ - - if (dir) - xchdir(dir); - - if (flags & EXECFLG_SETGUID) { - struct passwd* pw = getpwuid(uid); - gid_t gid = pw ? pw->pw_gid : uid; - setgroups(1, &gid); - xsetregid(gid, gid); - xsetreuid(uid, uid); - } - - if (env_vec) { - /* Note: we use the glibc extension that putenv("var") - * *unsets* $var if "var" string has no '=' */ - while (*env_vec) - putenv(*env_vec++); - } - - /* Play with stdio descriptors */ - if (flags & EXECFLG_INPUT) { - xmove_fd(pipe_to_child[0], STDIN_FILENO); - close(pipe_to_child[1]); - } else if (flags & EXECFLG_INPUT_NUL) { - xmove_fd(xopen("/dev/null", O_RDWR), STDIN_FILENO); - } - if (flags & EXECFLG_OUTPUT) { - xmove_fd(pipe_fm_child[1], STDOUT_FILENO); - close(pipe_fm_child[0]); - } else if (flags & EXECFLG_OUTPUT_NUL) { - xmove_fd(xopen("/dev/null", O_RDWR), STDOUT_FILENO); - } - - /* This should be done BEFORE stderr redirect */ - VERB1 { - char *r = concat_str_vector(argv); - log("Executing: %s", r); - free(r); - } - - if (flags & EXECFLG_ERR2OUT) { - /* Want parent to see errors in the same stream */ - xdup2(STDOUT_FILENO, STDERR_FILENO); - } else if (flags & EXECFLG_ERR_NUL) { - xmove_fd(xopen("/dev/null", O_RDWR), STDERR_FILENO); - } - - if (flags & EXECFLG_SETSID) - setsid(); - - execvp(argv[0], argv); - if (!(flags & EXECFLG_QUIET)) - perror_msg("Can't execute '%s'", argv[0]); - exit(127); /* shell uses this exit code in this case */ - } - - if (flags & EXECFLG_INPUT) { - close(pipe_to_child[0]); - pipefds[1] = pipe_to_child[1]; - } - if (flags & EXECFLG_OUTPUT) { - close(pipe_fm_child[1]); - pipefds[0] = pipe_fm_child[0]; - } - - return child; -} - -char *run_in_shell_and_save_output(int flags, - const char *cmd, - const char *dir, - size_t *size_p) -{ - flags |= EXECFLG_OUTPUT; - flags &= ~EXECFLG_INPUT; - - const char *argv[] = { "/bin/sh", "-c", cmd, NULL }; - int pipeout[2]; - pid_t child = fork_execv_on_steroids(flags, (char **)argv, pipeout, - /*env_vec:*/ NULL, dir, /*uid (unused):*/ 0); - - size_t pos = 0; - char *result = NULL; - while (1) { - result = (char*) xrealloc(result, pos + 4*1024 + 1); - size_t sz = safe_read(pipeout[0], result + pos, 4*1024); - if (sz <= 0) { - break; - } - pos += sz; - } - result[pos] = '\0'; - if (size_p) - *size_p = pos; - close(pipeout[0]); - waitpid(child, NULL, 0); - - return result; -} diff --git a/libreport/src/lib/stdio_helpers.c b/libreport/src/lib/stdio_helpers.c deleted file mode 100644 index 2ce20777..00000000 --- a/libreport/src/lib/stdio_helpers.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Utility routines. - * - * Copyright (C) 2001 Matt Krai - * Copyright (C) 2004 Erik Andersen <andersen@codepoet.org> - * Copyright (C) 2005, 2006 Rob Landley <rob@landley.net> - * Copyright (C) 2010 ABRT Team - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ -#include "libreport.h" - -//TODO: add sanitizing upper limit (e.g 64K, 1M, or configurable). -//This is why we don't use GNU's getline: it doesn't have -//any upper sanity bound on line size. - -static char *xmalloc_fgets_internal(FILE *file, int *sizep) -{ - unsigned idx = 0; - char *linebuf = NULL; - - while (1) { - char *r; - - linebuf = xrealloc(linebuf, idx + 0x100); - r = fgets(&linebuf[idx], 0x100, file); - if (!r) { - /* need to terminate the line */ - linebuf[idx] = '\0'; - break; - } - - /* stupid. fgets knows the len, it should report it somehow */ - unsigned len = strlen(&linebuf[idx]); - - idx += len; - if (len < 0xff || linebuf[idx - 1] == '\n') - break; /* we found \n or EOF */ - } - - *sizep = idx; - - if (!idx) { - /* The very first fgets returned NULL. It's EOF (or error) */ - free(linebuf); - linebuf = NULL; - } - return linebuf; -} - -char *xmalloc_fgets(FILE *file) -{ - int sz; - char *r = xmalloc_fgets_internal(file, &sz); - if (!r) - return r; - return xrealloc(r, sz + 1); -} - -char *xmalloc_fgetline(FILE *file) -{ - int sz; - char *r = xmalloc_fgets_internal(file, &sz); - if (!r) - return r; - if (r[sz - 1] == '\n') - r[--sz] = '\0'; - return xrealloc(r, sz + 1); -} diff --git a/libreport/src/lib/steal_directory.c b/libreport/src/lib/steal_directory.c deleted file mode 100644 index 4bcd192e..00000000 --- a/libreport/src/lib/steal_directory.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - Copyright (C) 2011 ABRT Team - Copyright (C) 2011 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 "libreport.h" - -struct dump_dir *steal_directory(const char *base_dir, const char *dump_dir_name) -{ - const char *base_name = strrchr(dump_dir_name, '/'); - if (base_name) - base_name++; - else - base_name = dump_dir_name; - - struct dump_dir *dd_dst; - unsigned count = 100; - char *dst_dir_name = concat_path_file(base_dir, base_name); - while (1) - { - dd_dst = dd_create(dst_dir_name, (uid_t)-1, 0640); - free(dst_dir_name); - if (dd_dst) - break; - if (--count == 0) - { - error_msg("Can't create new dump dir in '%s'", base_dir); - return NULL; - } - struct timeval tv; - gettimeofday(&tv, NULL); - dst_dir_name = xasprintf("%s/%s.%u", base_dir, base_name, (int)tv.tv_usec); - } - - VERB1 log("Creating copy in '%s'", dd_dst->dd_dirname); - if (copy_file_recursive(dump_dir_name, dd_dst->dd_dirname) < 0) - { - /* error. copy_file_recursive already emitted error message */ - /* Don't leave half-copied dir lying around */ - dd_delete(dd_dst); - return NULL; - } - - return dd_dst; -} diff --git a/libreport/src/lib/strbuf.c b/libreport/src/lib/strbuf.c deleted file mode 100644 index f2adeda7..00000000 --- a/libreport/src/lib/strbuf.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - String buffer implementation - - 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 "libreport.h" - -int prefixcmp(const char *str, const char *prefix) -{ - for (; ; str++, prefix++) - if (!*prefix) - return 0; - else if (*str != *prefix) - return (unsigned char)*prefix - (unsigned char)*str; -} - -int suffixcmp(const char *str, const char *suffix) -{ - int len_minus_suflen = strlen(str) - strlen(suffix); - if (len_minus_suflen < 0) - return len_minus_suflen; - else - return strcmp(str + len_minus_suflen, suffix); -} - -/* - * Trims whitespace characters both from left and right side of a string. - * Modifies the string in-place. Returns the trimmed string. - */ -char *strtrim(char *str) -{ - if (!str) - return NULL; - - // Remove leading spaces. - overlapping_strcpy(str, skip_whitespace(str)); - - // Remove trailing spaces. - int i = strlen(str); - while (--i >= 0) - { - if (!isspace(str[i])) - break; - } - str[++i] = '\0'; - return str; -} - -struct strbuf *strbuf_new(void) -{ - struct strbuf *buf = xzalloc(sizeof(*buf)); - /*buf->len = 0; - done by xzalloc */ - buf->alloc = 8; - buf->buf = xzalloc(8); - return buf; -} - -void strbuf_free(struct strbuf *strbuf) -{ - if (!strbuf) - return; - free(strbuf->buf); - free(strbuf); -} - -char *strbuf_free_nobuf(struct strbuf *strbuf) -{ - char *ret = strbuf->buf; - free(strbuf); - return ret; -} - - -void strbuf_clear(struct strbuf *strbuf) -{ - assert(strbuf->alloc > 0); - strbuf->len = 0; - strbuf->buf[0] = '\0'; -} - -/* Ensures that the buffer can be extended by N+1 characters - * without touching malloc/realloc. - * Returns pointer where appended chars can be stored by the caller; - * increments ->len by N (therefore callers don't need to do it). - */ -static char *strbuf_grow(struct strbuf *strbuf, unsigned increment) -{ - unsigned len = strbuf->len; - unsigned need = strbuf->len = len + increment; - unsigned cur_size = strbuf->alloc; - if (cur_size <= need) - { - while (cur_size <= need) - cur_size += 64 + cur_size / 8; - strbuf->alloc = cur_size; - strbuf->buf = xrealloc(strbuf->buf, cur_size); - } - char *p = strbuf->buf + len; - return p; -} - -struct strbuf *strbuf_append_char(struct strbuf *strbuf, char c) -{ - char *p = strbuf_grow(strbuf, 1); - *p++ = c; - *p = '\0'; - return strbuf; -} - -struct strbuf *strbuf_append_str(struct strbuf *strbuf, const char *str) -{ - unsigned len = strlen(str); - char *p = strbuf_grow(strbuf, len); - assert(strbuf->len < strbuf->alloc); - strcpy(p, str); - return strbuf; -} - -struct strbuf *strbuf_prepend_str(struct strbuf *strbuf, const char *str) -{ - unsigned cur_len = strbuf->len; - unsigned inc_len = strlen(str); - strbuf_grow(strbuf, inc_len); - assert(strbuf->len < strbuf->alloc); - memmove(strbuf->buf + inc_len, strbuf->buf, cur_len); - memcpy(strbuf->buf, str, inc_len); - return strbuf; -} - -struct strbuf *strbuf_append_strf(struct strbuf *strbuf, const char *format, ...) -{ - va_list p; - char *string_ptr; - - va_start(p, format); - string_ptr = xvasprintf(format, p); - va_end(p); - - strbuf_append_str(strbuf, string_ptr); - free(string_ptr); - return strbuf; -} - -struct strbuf *strbuf_prepend_strf(struct strbuf *strbuf, const char *format, ...) -{ - va_list p; - char *string_ptr; - - va_start(p, format); - string_ptr = xvasprintf(format, p); - va_end(p); - - strbuf_prepend_str(strbuf, string_ptr); - free(string_ptr); - return strbuf; -} diff --git a/libreport/src/lib/xatonum.c b/libreport/src/lib/xatonum.c deleted file mode 100644 index b6b90a98..00000000 --- a/libreport/src/lib/xatonum.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Utility routines. - * - * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> - * - * Licensed under GPLv2, see file LICENSE in this tarball for details. - */ -#include "libreport.h" - -unsigned xatou(const char *numstr) -{ - unsigned long r; - int old_errno; - char *e; - - if (*numstr < '0' || *numstr > '9') - goto inval; - - old_errno = errno; - errno = 0; - r = strtoul(numstr, &e, 10); - if (errno || numstr == e || *e != '\0' || r > UINT_MAX) - goto inval; /* error / no digits / illegal trailing chars */ - errno = old_errno; /* Ok. So restore errno. */ - return r; - -inval: - error_msg_and_die("invalid number '%s'", numstr); -} - -int xatoi_positive(const char *numstr) -{ - unsigned r = xatou(numstr); - if (r > (unsigned)INT_MAX) - error_msg_and_die("invalid number '%s'", numstr); - return r; -} - -int xatoi(const char *numstr) -{ - unsigned r; - - if (*numstr != '-') - return xatoi_positive(numstr); - - r = xatou(numstr + 1); - if (r > (unsigned)INT_MAX + 1) - error_msg_and_die("invalid number '%s'", numstr); - return - (int)r; -} diff --git a/libreport/src/lib/xfuncs.c b/libreport/src/lib/xfuncs.c deleted file mode 100644 index 67b61d40..00000000 --- a/libreport/src/lib/xfuncs.c +++ /dev/null @@ -1,410 +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. -*/ - -/* - * Utility routines. - * - */ -#include "libreport.h" - -/* Turn on nonblocking I/O on a fd */ -int ndelay_on(int fd) -{ - int flags = fcntl(fd, F_GETFL); - if (flags & O_NONBLOCK) - return 0; - return fcntl(fd, F_SETFL, flags | O_NONBLOCK); -} - -int ndelay_off(int fd) -{ - int flags = fcntl(fd, F_GETFL); - if (!(flags & O_NONBLOCK)) - return 0; - return fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); -} - -int close_on_exec_on(int fd) -{ - return fcntl(fd, F_SETFD, FD_CLOEXEC); -} - -// Die if we can't allocate size bytes of memory. -void* xmalloc(size_t size) -{ - void *ptr = malloc(size); - if (ptr == NULL && size != 0) - die_out_of_memory(); - return ptr; -} - -// Die if we can't resize previously allocated memory. (This returns a pointer -// to the new memory, which may or may not be the same as the old memory. -// It'll copy the contents to a new chunk and free the old one if necessary.) -void* xrealloc(void *ptr, size_t size) -{ - ptr = realloc(ptr, size); - if (ptr == NULL && size != 0) - die_out_of_memory(); - return ptr; -} - -// Die if we can't allocate and zero size bytes of memory. -void* xzalloc(size_t size) -{ - void *ptr = xmalloc(size); - memset(ptr, 0, size); - return ptr; -} - -// Die if we can't copy a string to freshly allocated memory. -char* xstrdup(const char *s) -{ - char *t; - if (s == NULL) - return NULL; - - t = strdup(s); - - if (t == NULL) - die_out_of_memory(); - - return t; -} - -// Die if we can't allocate n+1 bytes (space for the null terminator) and copy -// the (possibly truncated to length n) string into it. -char* xstrndup(const char *s, int n) -{ - int m; - char *t; - - /* We can just xmalloc(n+1) and strncpy into it, */ - /* but think about xstrndup("abc", 10000) wastage! */ - m = n; - t = (char*) s; - while (m) - { - if (!*t) break; - m--; - t++; - } - n -= m; - t = (char*) xmalloc(n + 1); - t[n] = '\0'; - - return (char*) memcpy(t, s, n); -} - -void xpipe(int filedes[2]) -{ - if (pipe(filedes)) - perror_msg_and_die("can't create pipe"); -} - -void xdup(int from) -{ - if (dup(from) < 0) - perror_msg_and_die("can't duplicate file descriptor"); -} - -void xdup2(int from, int to) -{ - if (dup2(from, to) != to) - perror_msg_and_die("can't duplicate file descriptor"); -} - -// "Renumber" opened fd -void xmove_fd(int from, int to) -{ - if (from == to) - return; - xdup2(from, to); - close(from); -} - -// Die with an error message if we can't write the entire buffer. -void xwrite(int fd, const void *buf, size_t count) -{ - if (count == 0) - return; - ssize_t size = full_write(fd, buf, count); - if ((size_t)size != count) - error_msg_and_die("short write"); -} - -void xwrite_str(int fd, const char *str) -{ - xwrite(fd, str, strlen(str)); -} - -// Die with an error message if we can't lseek to the right spot. -off_t xlseek(int fd, off_t offset, int whence) -{ - off_t off = lseek(fd, offset, whence); - if (off == (off_t)-1) { - if (whence == SEEK_SET) - perror_msg_and_die("lseek(%llu)", (long long)offset); - perror_msg_and_die("lseek"); - } - return off; -} - -void xchdir(const char *path) -{ - if (chdir(path)) - perror_msg_and_die("chdir(%s)", path); -} - -char* xvasprintf(const char *format, va_list p) -{ - int r; - char *string_ptr; - -#if 1 - // GNU extension - r = vasprintf(&string_ptr, format, p); -#else - // Bloat for systems that haven't got the GNU extension. - va_list p2; - va_copy(p2, p); - r = vsnprintf(NULL, 0, format, p); - string_ptr = xmalloc(r+1); - r = vsnprintf(string_ptr, r+1, format, p2); - va_end(p2); -#endif - - if (r < 0) - die_out_of_memory(); - return string_ptr; -} - -// Die with an error message if we can't malloc() enough space and do an -// sprintf() into that space. -char* xasprintf(const char *format, ...) -{ - va_list p; - char *string_ptr; - - va_start(p, format); - string_ptr = xvasprintf(format, p); - va_end(p); - - return string_ptr; -} - -void xsetenv(const char *key, const char *value) -{ - if (setenv(key, value, 1)) - die_out_of_memory(); -} - -void safe_unsetenv(const char *var_val) -{ - //char *name = xstrndup(var_val, strchrnul(var_val, '=') - var_val); - //unsetenv(name); - //free(name); - - /* Avoid malloc/free (name is usually very short) */ - unsigned len = strchrnul(var_val, '=') - var_val; - char name[len + 1]; - memcpy(name, var_val, len); - name[len] = '\0'; - unsetenv(name); -} - -// Die with an error message if we can't open a new socket. -int xsocket(int domain, int type, int protocol) -{ - int r = socket(domain, type, protocol); - if (r < 0) - { - const char *s = "INET"; - if (domain == AF_PACKET) s = "PACKET"; - if (domain == AF_NETLINK) s = "NETLINK"; - if (domain == AF_INET6) s = "INET6"; - perror_msg_and_die("socket(AF_%s)", s); - } - - return r; -} - -// Die with an error message if we can't bind a socket to an address. -void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) -{ - if (bind(sockfd, my_addr, addrlen)) - perror_msg_and_die("bind"); -} - -// Die with an error message if we can't listen for connections on a socket. -void xlisten(int s, int backlog) -{ - if (listen(s, backlog)) - perror_msg_and_die("listen"); -} - -// Die with an error message if sendto failed. -// Return bytes sent otherwise -ssize_t xsendto(int s, const void *buf, size_t len, - const struct sockaddr *to, - socklen_t tolen) -{ - ssize_t ret = sendto(s, buf, len, 0, to, tolen); - if (ret < 0) - { - close(s); - perror_msg_and_die("sendto"); - } - return ret; -} - -// xstat() - a stat() which dies on failure with meaningful error message -void xstat(const char *name, struct stat *stat_buf) -{ - if (stat(name, stat_buf)) - perror_msg_and_die("can't stat '%s'", name); -} - -// Die if we can't open a file and return a fd -int xopen3(const char *pathname, int flags, int mode) -{ - int ret; - ret = open(pathname, flags, mode); - if (ret < 0) - perror_msg_and_die("can't open '%s'", pathname); - return ret; -} - -// Die if we can't open an existing file and return a fd -int xopen(const char *pathname, int flags) -{ - return xopen3(pathname, flags, 0666); -} - -void xunlink(const char *pathname) -{ - if (unlink(pathname)) - perror_msg_and_die("Can't remove file '%s'", pathname); -} - -#if 0 //UNUSED -// Warn if we can't open a file and return a fd. -int open3_or_warn(const char *pathname, int flags, int mode) -{ - int ret; - ret = open(pathname, flags, mode); - if (ret < 0) - perror_msg("can't open '%s'", pathname); - return ret; -} - -// Warn if we can't open a file and return a fd. -int open_or_warn(const char *pathname, int flags) -{ - return open3_or_warn(pathname, flags, 0666); -} -#endif - -/* Just testing dent->d_type == DT_REG is wrong: some filesystems - * do not report the type, they report DT_UNKNOWN for every dirent - * (and this is not a bug in filesystem, this is allowed by standards). - */ -int is_regular_file(struct dirent *dent, const char *dirname) -{ - if (dent->d_type == DT_REG) - return 1; - if (dent->d_type != DT_UNKNOWN) - return 0; - - char *fullname = xasprintf("%s/%s", dirname, dent->d_name); - struct stat statbuf; - int r = lstat(fullname, &statbuf); - free(fullname); - - return r == 0 && S_ISREG(statbuf.st_mode); -} - -/* Is it "." or ".."? */ -/* abrtlib candidate */ -bool dot_or_dotdot(const char *filename) -{ - if (filename[0] != '.') return false; - if (filename[1] == '\0') return true; - if (filename[1] != '.') return false; - if (filename[2] == '\0') return true; - return false; -} - -/* Find out if the last character of a string matches the one given. - * Don't underrun the buffer if the string length is 0. - */ -char *last_char_is(const char *s, int c) -{ - if (s && *s) - { - s += strlen(s) - 1; - if ((unsigned char)*s == c) - return (char*)s; - } - return NULL; -} - -bool string_to_bool(const char *s) -{ - if (s[0] == '1' && s[1] == '\0') - return true; - if (strcasecmp(s, "on") == 0) - return true; - if (strcasecmp(s, "yes") == 0) - return true; - if (strcasecmp(s, "true") == 0) - return true; - return false; -} - -void xseteuid(uid_t euid) -{ - if (seteuid(euid) != 0) - perror_msg_and_die("can't set %cid %lu", 'u', (long)euid); -} - -void xsetegid(gid_t egid) -{ - if (setegid(egid) != 0) - perror_msg_and_die("can't set %cid %lu", 'g', (long)egid); -} - -void xsetreuid(uid_t ruid, uid_t euid) -{ - if (setreuid(ruid, euid) != 0) - perror_msg_and_die("can't set %cid %lu", 'u', (long)ruid); -} - -void xsetregid(gid_t rgid, gid_t egid) -{ - if (setregid(rgid, egid) != 0) - perror_msg_and_die("can't set %cid %lu", 'g', (long)rgid); -} - -const char *get_home_dir(uid_t uid) -{ - struct passwd* pw = getpwuid(uid); - // TODO: handle errno - return pw ? pw->pw_dir : NULL; -} |