/* Copyright (C) 2010 ABRT team Copyright (C) 2010 RedHat Inc This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "internal_libreport.h" #define SOCKET_FILE VAR_RUN"/abrt/abrt.socket" /* connects to abrtd * returns: socketfd * -1 on error */ static int connect_to_abrtd_socket() { int socketfd = xsocket(AF_UNIX, SOCK_STREAM, 0); if (socketfd == -1) return -1; /*close_on_exec_on(socketfd); - not needed, we are closing it soon */ struct sockaddr_un local; memset(&local, 0, sizeof(local)); local.sun_family = AF_UNIX; strcpy(local.sun_path, SOCKET_FILE); int r = connect(socketfd, (struct sockaddr*)&local, sizeof(local)); if (r != 0) { VERB1 pwarn_msg("Can't connect to '%s'", SOCKET_FILE); close(socketfd); return -1; } return socketfd; } static int connect_to_abrtd_and_call_DeleteDebugDump(const char *dump_dir_name) { int result = -1; /* error so far */ int socketfd = connect_to_abrtd_socket(); if (socketfd != -1) { full_write(socketfd, "DELETE ", strlen("DELETE ")); full_write(socketfd, dump_dir_name, strlen(dump_dir_name)); full_write(socketfd, " HTTP/1.1\r\n\r\n", strlen(" HTTP/1.1\r\n\r\n")); shutdown(socketfd, SHUT_WR); char response[64]; int r = full_read(socketfd, response, sizeof(response) - 1); if (r >= 0) { log_notice("Response via socket:'%.*s'", r, response); /* 0123456789... */ /* "HTTP/1.1 200 " */ response[5] = '1'; response[7] = '1'; if (strncmp(response, "HTTP/1.1 ", strlen("HTTP/1.1 ")) == 0 && isdigit(response[9]) && isdigit(response[10]) && isdigit(response[11]) && response[12] == ' ') { result = (response[9] - '0') * 100 + (response[10] - '0') * 10 + (response[11] - '0'); } } close(socketfd); } return result; } int problem_data_send_to_abrt(problem_data_t* problem_data) { int result = 1; /* error so far */ int socketfd = connect_to_abrtd_socket(); if (socketfd != -1) { GHashTableIter iter; char *name; struct problem_item *value; g_hash_table_iter_init(&iter, problem_data); full_write(socketfd, "PUT / HTTP/1.1\r\n\r\n", strlen("PUT / HTTP/1.1\r\n\r\n")); while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value)) { if (value->flags & CD_FLAG_BIN) { /* sending files over the socket is not implemented yet */ log_warning("Skipping binary file %s", name); continue; } /* only files should contain '/' and those are handled earlier */ if (name[0] == '.' || strchr(name, '/')) { error_msg("Problem data field name contains disallowed chars: '%s'", name); continue; } char* msg = xasprintf("%s=%s", name, value->content); full_write(socketfd, msg, strlen(msg)+1 /* yes, +1 coz we want to send the trailing 0 */); free(msg); } shutdown(socketfd, SHUT_WR); char response[64]; int r = full_read(socketfd, response, sizeof(response) - 1); if (r >= 0) { log_notice("Response via socket:'%.*s'", r, response); /* 0123456789... */ /* "HTTP/1.1 200 " */ response[5] = '1'; response[7] = '1'; result = strncmp(response, "HTTP/1.1 201 ", strlen("HTTP/1.1 201 ")); } close(socketfd); } return result; } int delete_dump_dir_possibly_using_abrtd(const char *dump_dir_name) { INITIALIZE_LIBREPORT(); #if DUMP_DIR_OWNED_BY_USER == 0 /* 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); } else { if (errno == ENOENT || errno == ENOTDIR) /* No such dir, no point in trying to talk over socket */ return 1; } log_notice("Deleting '%s' via abrtd", dump_dir_name); const int res = connect_to_abrtd_and_call_DeleteDebugDump(dump_dir_name); if (res != 0) error_msg(_("Can't delete: '%s'"), dump_dir_name); return res; #else log_notice("Deleting '%s' via abrtd", dump_dir_name); const int res = connect_to_abrtd_and_call_DeleteDebugDump(dump_dir_name); if (res == 200) { /* * Deleted */ return 0; } /* * An error occurred but we can still try to delete it directly */ /* Using NULL in order to easily detect a buggy error message */ const char *error_reason = NULL; /* Used only for error messages */ char num_buf[sizeof(int)*3 + 1]; if (res < 0 || res == 400) { /* -1 : an error in communication * 400 : bad request or abrtd refused to delete the directory outside of the dump location * * 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); error_reason = _("locked by another process"); dd_close(dd); } } else { switch (res) { case 403: error_reason = _("permission denied"); break; case 404: error_reason = _("not a problem directory"); break; default: snprintf(num_buf, sizeof(num_buf), "%d", res); error_reason = num_buf; break; } } error_msg(_("Can't delete '%s': %s"), dump_dir_name, error_reason); return 1; #endif }