|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
Copyright (C) 2015 ABRT team
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
This program is free software; you can redistribute it and/or modify
|
|
Packit |
8ea169 |
it under the terms of the GNU General Public License as published by
|
|
Packit |
8ea169 |
the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
8ea169 |
(at your option) any later version.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
This program is distributed in the hope that it will be useful,
|
|
Packit |
8ea169 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8ea169 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8ea169 |
GNU General Public License for more details.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
You should have received a copy of the GNU General Public License along
|
|
Packit |
8ea169 |
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit |
8ea169 |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#include "abrt_problems2_task_new_problem.h"
|
|
Packit |
8ea169 |
#include "abrt_problems2_entry.h"
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
typedef struct
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
AbrtP2Service *p2tnp_service;
|
|
Packit |
8ea169 |
GVariant *p2tnp_problem_info;
|
|
Packit |
8ea169 |
uid_t p2tnp_caller_uid;
|
|
Packit |
8ea169 |
GUnixFDList *p2tnp_fd_list;
|
|
Packit |
8ea169 |
AbrtP2Object *p2tnp_obj; ///<< AbrtProblems2Entry
|
|
Packit |
8ea169 |
bool p2tnp_wait_before_notify;
|
|
Packit |
8ea169 |
} AbrtP2TaskNewProblemPrivate;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
struct _AbrtP2TaskNewProblem
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
AbrtP2Task parent_instance;
|
|
Packit |
8ea169 |
AbrtP2TaskNewProblemPrivate *pv;
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static AbrtP2TaskCode abrt_p2_task_new_problem_run(AbrtP2Task *task,
|
|
Packit |
8ea169 |
GError **error);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
G_DEFINE_TYPE_WITH_PRIVATE(AbrtP2TaskNewProblem, abrt_p2_task_new_problem, ABRT_TYPE_P2_TASK)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void abrt_p2_task_new_problem_finalize(GObject *gobject)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
AbrtP2TaskNewProblemPrivate *pv = abrt_p2_task_new_problem_get_instance_private(ABRT_P2_TASK_NEW_PROBLEM(gobject));
|
|
Packit |
8ea169 |
g_variant_unref(pv->p2tnp_problem_info);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (pv->p2tnp_fd_list)
|
|
Packit |
8ea169 |
g_object_unref(pv->p2tnp_fd_list);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
G_OBJECT_CLASS(abrt_p2_task_new_problem_parent_class)->finalize(gobject);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void abrt_p2_task_remove_temporary_entry(AbrtP2TaskNewProblem *task,
|
|
Packit |
8ea169 |
GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (task->pv->p2tnp_obj == NULL)
|
|
Packit |
8ea169 |
return;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
AbrtP2Entry *entry = abrt_p2_object_get_node(task->pv->p2tnp_obj);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
log_debug("Task '%p': Removing temporary entry: %s",
|
|
Packit |
8ea169 |
task,
|
|
Packit |
8ea169 |
abrt_p2_entry_problem_id(entry));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
abrt_p2_entry_delete(entry,
|
|
Packit |
8ea169 |
/* act as super user to allow us to delete the temporary dir */0,
|
|
Packit |
8ea169 |
error);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
abrt_p2_object_destroy(task->pv->p2tnp_obj);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
task->pv->p2tnp_obj = NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void abrt_p2_task_new_problem_cancel(AbrtP2Task *task,
|
|
Packit |
8ea169 |
GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
abrt_p2_task_remove_temporary_entry(ABRT_P2_TASK_NEW_PROBLEM(task), error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void abrt_p2_task_new_problem_class_init(AbrtP2TaskNewProblemClass *klass)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
|
Packit |
8ea169 |
object_class->finalize = abrt_p2_task_new_problem_finalize;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
AbrtP2TaskClass *task_class = ABRT_P2_TASK_CLASS(klass);
|
|
Packit |
8ea169 |
task_class->run = abrt_p2_task_new_problem_run;
|
|
Packit |
8ea169 |
task_class->cancel = abrt_p2_task_new_problem_cancel;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void abrt_p2_task_new_problem_init(AbrtP2TaskNewProblem *self)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
self->pv = abrt_p2_task_new_problem_get_instance_private(self);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
AbrtP2TaskNewProblem *abrt_p2_task_new_problem_new(AbrtP2Service *service,
|
|
Packit |
8ea169 |
GVariant *problem_info,uid_t caller_uid,
|
|
Packit |
8ea169 |
GUnixFDList *fd_list)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
AbrtP2TaskNewProblem *task = g_object_new(TYPE_ABRT_P2_TASK_NEW_PROBLEM, NULL);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
task->pv->p2tnp_service = service;
|
|
Packit |
8ea169 |
task->pv->p2tnp_problem_info = problem_info;
|
|
Packit |
8ea169 |
task->pv->p2tnp_caller_uid = caller_uid;
|
|
Packit |
8ea169 |
task->pv->p2tnp_fd_list = fd_list;
|
|
Packit |
8ea169 |
task->pv->p2tnp_wait_before_notify = false;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return task;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void abrt_p2_task_new_problem_wait_before_notify(AbrtP2TaskNewProblem *task,
|
|
Packit |
8ea169 |
bool value)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
task->pv->p2tnp_wait_before_notify = value;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static AbrtP2Object *abrt_p2_task_new_problem_create_directory_task(AbrtP2TaskNewProblem *task,
|
|
Packit |
8ea169 |
GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
int r = abrt_p2_service_user_can_create_new_problem(task->pv->p2tnp_service, task->pv->p2tnp_caller_uid);
|
|
Packit |
8ea169 |
if (r == 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_LIMITS_EXCEEDED,
|
|
Packit |
8ea169 |
"Too many problems have been recently created");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
if (r == -E2BIG)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_LIMITS_EXCEEDED,
|
|
Packit |
8ea169 |
"No more problems can be created");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
|
|
Packit |
8ea169 |
"Failed to check NewProblem limits");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *problem_id = abrt_p2_service_save_problem(task->pv->p2tnp_service,
|
|
Packit |
8ea169 |
task->pv->p2tnp_problem_info,
|
|
Packit |
8ea169 |
task->pv->p2tnp_fd_list,
|
|
Packit |
8ea169 |
task->pv->p2tnp_caller_uid, error);
|
|
Packit |
8ea169 |
if (*error != NULL)
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
AbrtP2Entry *entry = abrt_p2_entry_new_with_state(problem_id,
|
|
Packit |
8ea169 |
ABRT_P2_ENTRY_STATE_NEW);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
AbrtP2Object *obj = abrt_p2_service_register_entry(task->pv->p2tnp_service,
|
|
Packit |
8ea169 |
entry,
|
|
Packit |
8ea169 |
error);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (*error != NULL)
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return obj;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static int abrt_p2_task_new_problem_notify_directory_task(AbrtP2TaskNewProblem *task,
|
|
Packit |
8ea169 |
char **new_path, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
AbrtP2Entry *entry = abrt_p2_object_get_node(task->pv->p2tnp_obj);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *message = NULL;
|
|
Packit |
8ea169 |
const char *problem_id = abrt_p2_entry_problem_id(entry);
|
|
Packit |
8ea169 |
int r = notify_new_path_with_response(problem_id, &message);
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_debug("Task '%p': Failed to communicate with the problems daemon",
|
|
Packit |
8ea169 |
task);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GError *local_error = NULL;
|
|
Packit |
8ea169 |
abrt_p2_entry_delete(entry,
|
|
Packit |
8ea169 |
/* allow us to delete the temporary dir */0,
|
|
Packit |
8ea169 |
&local_error);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (local_error != NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg("Can't remove temporary problem directory: %s",
|
|
Packit |
8ea169 |
local_error->message);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_error_free(local_error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
abrt_p2_object_destroy(task->pv->p2tnp_obj);
|
|
Packit |
8ea169 |
task->pv->p2tnp_obj = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
|
|
Packit |
8ea169 |
"Failed to notify the new problem directory");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return r;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
gint32 code;
|
|
Packit |
8ea169 |
log_debug("Task '%p': New path processed: %d", task, r);
|
|
Packit |
8ea169 |
if (r == 303)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* 303 - the daemon found a local duplicate problem */
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
abrt_p2_object_destroy(task->pv->p2tnp_obj);
|
|
Packit |
8ea169 |
task->pv->p2tnp_obj = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
AbrtP2Object *obj = abrt_p2_service_get_entry_for_problem(task->pv->p2tnp_service,
|
|
Packit |
8ea169 |
message,
|
|
Packit |
8ea169 |
ABRT_P2_SERVICE_ENTRY_LOOKUP_NOFLAGS,
|
|
Packit |
8ea169 |
error);
|
|
Packit |
8ea169 |
if (obj == NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg("Problem Entry for directory '%s' does not exist", message);
|
|
Packit |
8ea169 |
free(message);
|
|
Packit |
8ea169 |
return ABRT_P2_TASK_CODE_ERROR;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
*new_path = xstrdup(abrt_p2_object_path(obj));
|
|
Packit |
8ea169 |
code = ABRT_P2_TASK_NEW_PROBLEM_DUPLICATE;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
log_debug("Task '%p': New occurrence of '%s'",
|
|
Packit |
8ea169 |
task,
|
|
Packit |
8ea169 |
*new_path);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* TODO: what about to teach the service to understand task's signals? */
|
|
Packit |
8ea169 |
abrt_p2_service_notify_entry_object(task->pv->p2tnp_service,
|
|
Packit |
8ea169 |
obj,
|
|
Packit |
8ea169 |
error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else if (r == 410)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* 410 - the problem was refused by the daemon */
|
|
Packit |
8ea169 |
log_debug("Task '%p': Problem dropped", task);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
abrt_p2_object_destroy(task->pv->p2tnp_obj);
|
|
Packit |
8ea169 |
task->pv->p2tnp_obj = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
code = ABRT_P2_TASK_NEW_PROBLEM_DROPPED;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else if (r == 200)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* 200 - the problem was accepted */
|
|
Packit |
8ea169 |
*new_path = xstrdup(abrt_p2_object_path(task->pv->p2tnp_obj));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
code = ABRT_P2_TASK_NEW_PROBLEM_ACCEPTED;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
abrt_p2_entry_set_state(entry, ABRT_P2_ENTRY_STATE_COMPLETE);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
log_debug("Task '%p': New problem '%s'", task, *new_path);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* TODO: what about to teach the service to understand task's signals? */
|
|
Packit |
8ea169 |
abrt_p2_service_notify_entry_object(task->pv->p2tnp_service,
|
|
Packit |
8ea169 |
task->pv->p2tnp_obj,
|
|
Packit |
8ea169 |
error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_debug("Task '%p': Problem was invalid", task);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
abrt_p2_entry_delete(entry,
|
|
Packit |
8ea169 |
/* allow us to delete the temporary dir */0,
|
|
Packit |
8ea169 |
error);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
abrt_p2_object_destroy(task->pv->p2tnp_obj);
|
|
Packit |
8ea169 |
task->pv->p2tnp_obj = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
code = ABRT_P2_TASK_NEW_PROBLEM_INVALID_DATA;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(message);
|
|
Packit |
8ea169 |
return code;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static AbrtP2TaskCode abrt_p2_task_new_problem_run(AbrtP2Task *task, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
AbrtP2TaskNewProblem *np = ABRT_P2_TASK_NEW_PROBLEM(task);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Create the temporary entry. If you ask the question how it is possible
|
|
Packit |
8ea169 |
* that the object already exist, then the answer is that if user requested
|
|
Packit |
8ea169 |
* to stop the task after creation of the object. */
|
|
Packit |
8ea169 |
if (np->pv->p2tnp_obj == NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
AbrtP2Object *obj = abrt_p2_task_new_problem_create_directory_task(np, error);
|
|
Packit |
8ea169 |
if (obj == NULL)
|
|
Packit |
8ea169 |
return ABRT_P2_TASK_CODE_ERROR;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const char *temporary_entry_path = abrt_p2_object_path(obj);
|
|
Packit |
8ea169 |
GVariant *detail_path = g_variant_new_string(temporary_entry_path);
|
|
Packit |
8ea169 |
abrt_p2_task_add_detail(task, "NewProblem.TemporaryEntry", detail_path);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
log_debug("Created temporary entry '%s' for task '%p'",
|
|
Packit |
8ea169 |
temporary_entry_path,
|
|
Packit |
8ea169 |
task);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
np->pv->p2tnp_obj = obj;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (abrt_p2_task_is_cancelled(task))
|
|
Packit |
8ea169 |
return ABRT_P2_TASK_CODE_CANCELLED;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (np->pv->p2tnp_wait_before_notify)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* Stop the task to allow users to modify the temporary object */
|
|
Packit |
8ea169 |
log_debug("Stopping NewProblem task '%p'", task);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return ABRT_P2_TASK_CODE_STOP;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *new_path = NULL;
|
|
Packit |
8ea169 |
gint32 code = abrt_p2_task_new_problem_notify_directory_task(np,
|
|
Packit |
8ea169 |
&new_path,
|
|
Packit |
8ea169 |
error);
|
|
Packit |
8ea169 |
if (code < 0)
|
|
Packit |
8ea169 |
return ABRT_P2_TASK_CODE_ERROR;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GVariantDict response;
|
|
Packit |
8ea169 |
g_variant_dict_init(&response, NULL);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (new_path != NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
g_variant_dict_insert(&response,
|
|
Packit |
8ea169 |
"NewProblem.Entry",
|
|
Packit |
8ea169 |
"s",
|
|
Packit |
8ea169 |
new_path);
|
|
Packit |
8ea169 |
free(new_path);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
log_debug("NewProblem task '%p' has successfully finished", task);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
abrt_p2_task_set_response(task,
|
|
Packit |
8ea169 |
g_variant_dict_end(&response));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return ABRT_P2_TASK_CODE_DONE + code;
|
|
Packit |
8ea169 |
}
|