From 844507bf2504e770951eab25cf289b78f3662494 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Tue, 28 Jan 2020 13:47:11 +0000 Subject: [PATCH] WIP Signed-off-by: Philip Withnall --- libmalcontent/manager.c | 130 ++++++++++++++++++++++++ libmalcontent/manager.h | 9 ++ libmalcontent/meson.build | 5 +- libmalcontent/session-history-private.h | 42 ++++++++ libmalcontent/session-history.c | 100 ++++++++++++++++++ libmalcontent/session-history.h | 59 +++++++++++ 6 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 libmalcontent/session-history-private.h create mode 100644 libmalcontent/session-history.c create mode 100644 libmalcontent/session-history.h diff --git a/libmalcontent/manager.c b/libmalcontent/manager.c index eef42fb..235c7ad 100644 --- a/libmalcontent/manager.c +++ b/libmalcontent/manager.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "libmalcontent/app-filter-private.h" #include "libmalcontent/session-limits-private.h" @@ -1333,3 +1334,132 @@ mct_manager_set_session_limits_finish (MctManager *self, return g_task_propagate_boolean (G_TASK (result), error); } + +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (sd_journal, sd_journal_close) + +/* TODO Docs */ +MctSessionHistory * +mct_manager_get_session_history (MctManager *self, + uid_t user_id, + GDateTime *start, + GDateTime *end, + MctManagerGetValueFlags flags, + GCancellable *cancellable, + GError **error) +{ + g_auto(sd_journal) *journal = NULL; + int ret; + const gchar * const match_message_ids[] = + { + "MESSAGE_ID=8d45620c1a4348dbb17410da57c60c66", /* new session */ + "MESSAGE_ID=3354939424b4456d9802ca8333ed424a", /* session ended */ + "MESSAGE_ID=6bbd95ee977941e497c48be27c254128", /* entering sleep */ + "MESSAGE_ID=8811e6df2a8e40f58a94cea26f8ebf14", /* leaving sleep */ + "MESSAGE_ID=b07a249cd024414a82dd00cd181378ff", /* startup complete */ + "MESSAGE_ID=98268866d1d54a499c4e98921d93bc40", /* starting to shut down */ + /* TODO: need to add messages to gnome-shell for when the user locks and unlocks the screen, + * including logging in and out and switching user */ + }; + const size_t message_id_len = sizeof (match_message_ids[0]); + g_autoptr(GPtrArray) active_periods = g_ptr_array_new_with_free_func (NULL); /* TODO */ + + g_return_val_if_fail (MCT_IS_MANAGER (self), NULL); + g_return_val_if_fail (start != NULL, NULL); + g_return_val_if_fail (end != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + ret = sd_journal_open (&journal, SD_JOURNAL_SYSTEM); + if (ret < 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Error opening journal: %s", g_strerror (-ret)); + return NULL; + } + + /* TODO: work out what data threshold is needed and set with sd_journal_set_data_threshold() */ + + /* Add matches. */ + for (gsize i = 0; i < G_N_ELEMENTS (match_message_ids); i++) + { + ret = sd_journal_add_match (journal, "MESSAGE_ID=TODO", 0); + if (ret < 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, /* TODO More specific error codes throughout */ + "Error applying matches in journal: %s", g_strerror (-ret)); + return NULL; + } + } + + ret = sd_journal_seek_realtime_usec (journal, (uint64_t) g_date_time_to_unix (start) * G_USEC_PER_SEC); + if (ret < 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, /* TODO More specific error codes throughout */ + "Error finding start entry in journal: %s", g_strerror (-ret)); + return NULL; + } + + while (TRUE) + { + uint64_t entry_realtime = 0; + const void *data = NULL; + size_t data_len = 0; + + ret = sd_journal_next (journal); + if (ret < 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Error seeking journal: %s", g_strerror (-ret)); + return NULL; + } + else if (ret == 0) + { + /* Reached EOF. */ + break; + } + + ret = sd_journal_get_realtime_usec (journal, &entry_realtime); + if (ret < 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Error reading journal: %s", g_strerror (-ret)); + return NULL; + } + + if (entry_realtime / G_USEC_PER_SEC >= g_date_time_to_unix (end)) + { + /* Reached the end of the search range. */ + break; + } + + /* Check the type of the record. */ + ret = sd_journal_get_data (journal, "MESSAGE_ID", &data, &data_len); + if (ret < 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Error reading journal: %s", g_strerror (-ret)); + return NULL; + } + + if (data_len != message_id_len) + { + g_debug ("Unexpected field %s, ignoring", data); + continue; + } + + /* TODO: need to filter by uid */ + if (memcmp (data, "MESSAGE_ID=8d45620c1a4348dbb17410da57c60c66", message_id_len) == 0) + { + /* New session. */ + g_ptr_array_add (active_periods, TODO); + } + +/* TODO */ + "MESSAGE_ID=3354939424b4456d9802ca8333ed424a", /* session ended */ + "MESSAGE_ID=6bbd95ee977941e497c48be27c254128", /* entering sleep */ + "MESSAGE_ID=8811e6df2a8e40f58a94cea26f8ebf14", /* leaving sleep */ + "MESSAGE_ID=b07a249cd024414a82dd00cd181378ff", /* startup complete */ + "MESSAGE_ID=98268866d1d54a499c4e98921d93bc40", /* starting to shut down */ + + } +} diff --git a/libmalcontent/manager.h b/libmalcontent/manager.h index f1bf1ce..5a658d7 100644 --- a/libmalcontent/manager.h +++ b/libmalcontent/manager.h @@ -168,4 +168,13 @@ gboolean mct_manager_set_session_limits_finish (MctManager * GAsyncResult *result, GError **error); +/* TODO */ +MctSessionHistory *mct_manager_get_session_history (MctManager *self, + uid_t user_id, + GDateTime *start, + GDateTime *end, + MctManagerGetValueFlags flags, + GCancellable *cancellable, + GError **error); + G_END_DECLS diff --git a/libmalcontent/meson.build b/libmalcontent/meson.build index 1aa0c45..16c883a 100644 --- a/libmalcontent/meson.build +++ b/libmalcontent/meson.build @@ -3,16 +3,19 @@ libmalcontent_api_name = 'malcontent-' + libmalcontent_api_version libmalcontent_sources = [ 'app-filter.c', 'manager.c', + 'session-history.c', 'session-limits.c', ] libmalcontent_headers = [ 'app-filter.h', 'malcontent.h', 'manager.h', + 'session-history.h', 'session-limits.h', ] libmalcontent_private_headers = [ 'app-filter-private.h', + 'session-history-private.h', 'session-limits-private.h', ] @@ -68,4 +71,4 @@ gnome.generate_gir(libmalcontent, dependencies: libmalcontent_dep, ) -subdir('tests') \ No newline at end of file +subdir('tests') diff --git a/libmalcontent/session-history-private.h b/libmalcontent/session-history-private.h new file mode 100644 index 0000000..c7f47df --- /dev/null +++ b/libmalcontent/session-history-private.h @@ -0,0 +1,42 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright © 2020 Endless Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * - Philip Withnall + */ + +#pragma once + +#include +#include +#include +#include + +G_BEGIN_DECLS + +struct _MctSessionHistory +{ + gint ref_count; + + uid_t user_id; + + GDateTime *start; /* (owned) */ + GDateTime *end; /* (owned) */ +}; + +G_END_DECLS diff --git a/libmalcontent/session-history.c b/libmalcontent/session-history.c new file mode 100644 index 0000000..18e1506 --- /dev/null +++ b/libmalcontent/session-history.c @@ -0,0 +1,100 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright © 2020 Endless Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "libmalcontent/session-history-private.h" + + +/* struct _MctSessionHistory is defined in session-history-private.h */ + +G_DEFINE_BOXED_TYPE (MctSessionHistory, mct_session_history, + mct_session_history_ref, mct_session_history_unref) + +/** + * mct_session_history_ref: + * @history: (transfer none): an #MctSessionHistory + * + * Increment the reference count of @history, and return the same pointer to it. + * + * Returns: (transfer full): the same pointer as @history + * Since: 0.5.0 + */ +MctSessionHistory * +mct_session_history_ref (MctSessionHistory *history) +{ + g_return_val_if_fail (history != NULL, NULL); + g_return_val_if_fail (history->ref_count >= 1, NULL); + g_return_val_if_fail (history->ref_count <= G_MAXINT - 1, NULL); + + history->ref_count++; + return history; +} + +/** + * mct_session_history_unref: + * @history: (transfer full): an #MctSessionHistory + * + * Decrement the reference count of @history. If the reference count reaches + * zero, free the @history and all its resources. + * + * Since: 0.5.0 + */ +void +mct_session_history_unref (MctSessionHistory *history) +{ + g_return_if_fail (history != NULL); + g_return_if_fail (history->ref_count >= 1); + + history->ref_count--; + + if (history->ref_count <= 0) + { + g_clear_pointer (&history->start, g_date_time_unref); + g_clear_pointer (&history->end, g_date_time_unref); + g_free (history); + } +} + +/** + * mct_session_history_get_user_id: + * @history: an #MctSessionHistory + * + * Get the user ID of the user this #MctSessionHistory is for. + * + * Returns: user ID of the relevant user + * Since: 0.5.0 + */ +uid_t +mct_session_history_get_user_id (MctSessionHistory *history) +{ + g_return_val_if_fail (history != NULL, (uid_t) -1); + g_return_val_if_fail (history->ref_count >= 1, (uid_t) -1); + + return history->user_id; +} diff --git a/libmalcontent/session-history.h b/libmalcontent/session-history.h new file mode 100644 index 0000000..303d5e4 --- /dev/null +++ b/libmalcontent/session-history.h @@ -0,0 +1,59 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright © 2020 Endless Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * - Philip Withnall + */ + +#pragma once + +#include +#include +#include + +G_BEGIN_DECLS + +/** + * MctSessionHistory: + * + * TODO + * #MctSessionLimits is an opaque, immutable structure which contains a snapshot + * of the session limits settings for a user at a given time. This includes + * whether session limits are being enforced, and the limit policy — for + * example, the times of day when a user is allowed to use the computer. + * + * Typically, session limits settings can only be changed by the administrator, + * and are read-only for non-administrative users. The precise policy is set + * using polkit. + * + * Since: 0.5.0 + */ +typedef struct _MctSessionHistory MctSessionHistory; +GType mct_session_history_get_type (void); +#define MCT_TYPE_SESSION_HISTORY mct_session_history_get_type () + +MctSessionHistory *mct_session_history_ref (MctSessionHistory *history); +void mct_session_history_unref (MctSessionHistory *history); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MctSessionHistory, mct_session_history_unref) + +uid_t mct_session_history_get_user_id (MctSessionHistory *history); +GDateTime *mct_session_history_get_start (MctSessionHistory *history); +GDateTime *mct_session_history_get_end (MctSessionHistory *history); + +G_END_DECLS