Blame src/lib/abrt_sock.c

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