Blame src/lib/steal_directory.c

Packit Service 779887
/*
Packit Service 779887
    Copyright (C) 2011  ABRT Team
Packit Service 779887
    Copyright (C) 2011  RedHat inc.
Packit Service 779887
Packit Service 779887
    This program is free software; you can redistribute it and/or modify
Packit Service 779887
    it under the terms of the GNU General Public License as published by
Packit Service 779887
    the Free Software Foundation; either version 2 of the License, or
Packit Service 779887
    (at your option) any later version.
Packit Service 779887
Packit Service 779887
    This program is distributed in the hope that it will be useful,
Packit Service 779887
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 779887
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 779887
    GNU General Public License for more details.
Packit Service 779887
Packit Service 779887
    You should have received a copy of the GNU General Public License along
Packit Service 779887
    with this program; if not, write to the Free Software Foundation, Inc.,
Packit Service 779887
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit Service 779887
*/
Packit Service 779887
#include "internal_libreport.h"
Packit Service 779887
Packit Service 779887
struct dump_dir *steal_directory(const char *base_dir, const char *dump_dir_name)
Packit Service 779887
{
Packit Service 779887
    const char *base_name = strrchr(dump_dir_name, '/');
Packit Service 779887
    if (base_name)
Packit Service 779887
    {
Packit Service 779887
        if (base_name[1] == '\0')
Packit Service 779887
        {
Packit Service 779887
            /* Drats. It has trailing slash(es) */
Packit Service 779887
            /* Skip all trailing slashes */
Packit Service 779887
            while (base_name > dump_dir_name && *--base_name == '/')
Packit Service 779887
                continue;
Packit Service 779887
            /* Find previous one */
Packit Service 779887
            for (;;)
Packit Service 779887
            {
Packit Service 779887
                if (*base_name == '/')
Packit Service 779887
                    break;
Packit Service 779887
                base_name--;
Packit Service 779887
                if (base_name < dump_dir_name)
Packit Service 779887
                    /* It has ONLY trailing slash(es) */
Packit Service 779887
                    break;
Packit Service 779887
            }
Packit Service 779887
        }
Packit Service 779887
        base_name++;
Packit Service 779887
    }
Packit Service 779887
    else
Packit Service 779887
        base_name = dump_dir_name;
Packit Service 779887
Packit Service 779887
    struct dump_dir *dd_dst;
Packit Service 779887
    unsigned count = 100;
Packit Service 779887
    char *dst_dir_name = concat_path_file(base_dir, base_name);
Packit Service 779887
    while (1)
Packit Service 779887
    {
Packit Service 779887
        dd_dst = dd_create(dst_dir_name, (uid_t)-1, DEFAULT_DUMP_DIR_MODE);
Packit Service 779887
        free(dst_dir_name);
Packit Service 779887
        if (dd_dst)
Packit Service 779887
            break;
Packit Service 779887
        if (--count == 0)
Packit Service 779887
        {
Packit Service 779887
            error_msg("Can't create new dump dir in '%s'", base_dir);
Packit Service 779887
            return NULL;
Packit Service 779887
        }
Packit Service 779887
        struct timeval tv;
Packit Service 779887
        gettimeofday(&tv, NULL);
Packit Service 779887
        dst_dir_name = xasprintf("%s/%s.%u", base_dir, base_name, (int)tv.tv_usec);
Packit Service 779887
    }
Packit Service 779887
Packit Service 779887
    log_notice("Creating copy in '%s'", dd_dst->dd_dirname);
Packit Service 779887
    if (copy_file_recursive(dump_dir_name, dd_dst->dd_dirname) < 0)
Packit Service 779887
    {
Packit Service 779887
        /* error. copy_file_recursive already emitted error message */
Packit Service 779887
        /* Don't leave half-copied dir lying around */
Packit Service 779887
        dd_delete(dd_dst);
Packit Service 779887
        return NULL;
Packit Service 779887
    }
Packit Service 779887
Packit Service 779887
    return dd_dst;
Packit Service 779887
}
Packit Service 779887
Packit Service 779887
struct dump_dir *open_directory_for_writing(
Packit Service 779887
                            const char *dump_dir_name,
Packit Service 779887
                            bool (*ask)(const char *, const char *))
Packit Service 779887
{
Packit Service 779887
    struct dump_dir *dd = dd_opendir(dump_dir_name, DD_OPEN_READONLY);
Packit Service 779887
Packit Service 779887
    if (!dd)
Packit Service 779887
        xfunc_die(); /* error msg was already logged */
Packit Service 779887
Packit Service 779887
    if (dd->locked)
Packit Service 779887
        return dd;
Packit Service 779887
Packit Service 779887
    log_warning("'%s' is not writable", dump_dir_name);
Packit Service 779887
    dd_close(dd);
Packit Service 779887
Packit Service 779887
    char *spooldir = concat_path_file(g_get_user_cache_dir(), "abrt/spool");
Packit Service 779887
Packit Service 779887
    if (ask && !ask(spooldir, dump_dir_name))
Packit Service 779887
        return NULL;
Packit Service 779887
Packit Service 779887
    dd = steal_directory(spooldir, dump_dir_name);
Packit Service 779887
    free(spooldir);
Packit Service 779887
Packit Service 779887
    if (!dd)
Packit Service 779887
        return NULL;
Packit Service 779887
Packit Service 779887
    bool dd_was_cwd = false;
Packit Service 779887
    {
Packit Service 779887
        char old_cwd[PATH_MAX + 1];
Packit Service 779887
        /* must get CWD before deleting */
Packit Service 779887
        if (getcwd(old_cwd, sizeof(old_cwd)))
Packit Service 779887
            dd_was_cwd = strcmp(old_cwd, dump_dir_name) == 0;
Packit Service 779887
        else
Packit Service 779887
            perror_msg("getcwd()");
Packit Service 779887
    }
Packit Service 779887
Packit Service 779887
    /* Delete old dir and switch to new one.
Packit Service 779887
     * Don't want to keep new dd open across deletion,
Packit Service 779887
     * therefore it's a bit more complicated.
Packit Service 779887
     */
Packit Service 779887
    delete_dump_dir_possibly_using_abrtd(dump_dir_name);
Packit Service 779887
    char *new_name = xstrdup(dd->dd_dirname);
Packit Service 779887
    dd_close(dd);
Packit Service 779887
    dd = dd_opendir(new_name, 0);
Packit Service 779887
    free(new_name);
Packit Service 779887
Packit Service 779887
    if (!dd)
Packit Service 779887
        xfunc_die(); /* error msg was already logged */
Packit Service 779887
Packit Service 779887
    /* Update CWD to the new dump dir path if CWD is the stolen dump dir */
Packit Service 779887
    /* Nonexisting CWD breaks lot of things (i.e. gnome-open can't open URL)*/
Packit Service 779887
    if (dd_was_cwd && chdir(dd->dd_dirname))
Packit Service 779887
        perror_msg("chdir()");
Packit Service 779887
Packit Service 779887
    return dd;
Packit Service 779887
}