mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-25 03:40:07 +01:00
settings: add a simpler session monitor
Heavily modified from polkitbackendsessionmonitor.c, thanks davidz!
This commit is contained in:
parent
8f7aedc7e0
commit
0c409d75ea
3 changed files with 541 additions and 1 deletions
|
|
@ -29,7 +29,9 @@ libsystem_settings_la_SOURCES = \
|
|||
nm-session-info.c \
|
||||
nm-session-info.h \
|
||||
nm-session-manager.c \
|
||||
nm-session-manager.h
|
||||
nm-session-manager.h \
|
||||
nm-session-monitor.c \
|
||||
nm-session-monitor.h
|
||||
|
||||
libsystem_settings_la_CPPFLAGS = \
|
||||
$(DBUS_CFLAGS) \
|
||||
|
|
|
|||
478
src/system-settings/nm-session-monitor.c
Normal file
478
src/system-settings/nm-session-monitor.c
Normal file
|
|
@ -0,0 +1,478 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* 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.
|
||||
*
|
||||
* (C) Copyright 2008 - 2010 Red Hat, Inc.
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
* Author: Dan Williams <dcbw@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <gio/gio.h>
|
||||
#include "nm-logging.h"
|
||||
#include "nm-system-config-error.h"
|
||||
|
||||
#include "nm-session-monitor.h"
|
||||
|
||||
#define CKDB_PATH "/var/run/ConsoleKit/database"
|
||||
|
||||
/* <internal>
|
||||
* SECTION:nm-session-monitor
|
||||
* @title: NMSessionMonitor
|
||||
* @short_description: Monitor sessions
|
||||
*
|
||||
* The #NMSessionMonitor class is a utility class to track and monitor sessions.
|
||||
*/
|
||||
|
||||
struct _NMSessionMonitor {
|
||||
GObject parent_instance;
|
||||
|
||||
GKeyFile *database;
|
||||
GFileMonitor *database_monitor;
|
||||
time_t database_mtime;
|
||||
GHashTable *sessions_by_uid;
|
||||
GHashTable *sessions_by_user;
|
||||
};
|
||||
|
||||
struct _NMSessionMonitorClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*changed) (NMSessionMonitor *monitor);
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
CHANGED,
|
||||
LAST_SIGNAL,
|
||||
};
|
||||
static guint signals[LAST_SIGNAL] = {0};
|
||||
|
||||
G_DEFINE_TYPE (NMSessionMonitor, nm_session_monitor, G_TYPE_OBJECT);
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
typedef struct {
|
||||
char *user;
|
||||
uid_t uid;
|
||||
gboolean local;
|
||||
gboolean active;
|
||||
} Session;
|
||||
|
||||
static void
|
||||
session_free (Session *s)
|
||||
{
|
||||
g_free (s->user);
|
||||
memset (s, 0, sizeof (Session));
|
||||
g_free (s);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_key (GKeyFile *keyfile, const char *group, const char *key, GError **error)
|
||||
{
|
||||
if (g_key_file_has_key (keyfile, group, key, error))
|
||||
return TRUE;
|
||||
|
||||
if (!error) {
|
||||
g_set_error (error,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR_GENERAL,
|
||||
"ConsoleKit database " CKDB_PATH " group '%s' had no '%s' key",
|
||||
group, key);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static Session *
|
||||
session_new (GKeyFile *keyfile, const char *group, GError **error)
|
||||
{
|
||||
Session *s;
|
||||
struct passwd *pw;
|
||||
|
||||
s = g_new0 (Session, 1);
|
||||
g_assert (s);
|
||||
|
||||
if (!check_key (keyfile, group, "uid", error))
|
||||
return FALSE;
|
||||
s->uid = (uid_t) g_key_file_get_integer (keyfile, group, "uid", error);
|
||||
if (error)
|
||||
goto error;
|
||||
|
||||
if (!check_key (keyfile, group, "is_active", error))
|
||||
return FALSE;
|
||||
s->active = g_key_file_get_boolean (keyfile, group, "is_active", error);
|
||||
if (error)
|
||||
goto error;
|
||||
|
||||
if (!check_key (keyfile, group, "is_local", error))
|
||||
return FALSE;
|
||||
s->local = g_key_file_get_boolean (keyfile, group, "is_local", error);
|
||||
if (error)
|
||||
goto error;
|
||||
|
||||
pw = getpwuid (s->uid);
|
||||
if (!pw) {
|
||||
g_set_error (error,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR_GENERAL,
|
||||
"Could not get username for UID %d",
|
||||
s->uid);
|
||||
goto error;
|
||||
}
|
||||
s->user = g_strdup (pw->pw_name);
|
||||
|
||||
return s;
|
||||
|
||||
error:
|
||||
session_free (s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
static void
|
||||
free_database (NMSessionMonitor *self)
|
||||
{
|
||||
if (self->database != NULL) {
|
||||
g_key_file_free (self->database);
|
||||
self->database = NULL;
|
||||
}
|
||||
|
||||
g_hash_table_remove_all (self->sessions_by_uid);
|
||||
g_hash_table_remove_all (self->sessions_by_user);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
reload_database (NMSessionMonitor *self, GError **error)
|
||||
{
|
||||
struct stat statbuf;
|
||||
char **groups;
|
||||
gsize len = 0, i;
|
||||
Session *s;
|
||||
|
||||
free_database (self);
|
||||
|
||||
if (stat (CKDB_PATH, &statbuf) != 0) {
|
||||
g_set_error (error,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR_GENERAL,
|
||||
"Error statting file " CKDB_PATH ": %s",
|
||||
strerror (errno));
|
||||
goto error;
|
||||
}
|
||||
self->database_mtime = statbuf.st_mtime;
|
||||
|
||||
self->database = g_key_file_new ();
|
||||
if (!g_key_file_load_from_file (self->database, CKDB_PATH, G_KEY_FILE_NONE, error))
|
||||
goto error;
|
||||
|
||||
groups = g_key_file_get_groups (self->database, &len);
|
||||
if (!groups) {
|
||||
g_set_error_literal (error,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR_GENERAL,
|
||||
"Could not load groups from " CKDB_PATH "");
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!g_str_has_prefix (groups[i], "Session "))
|
||||
continue;
|
||||
|
||||
s = session_new (self->database, groups[i], error);
|
||||
if (!s)
|
||||
goto error;
|
||||
g_hash_table_insert (self->sessions_by_user, (gpointer) s->user, s);
|
||||
g_hash_table_insert (self->sessions_by_uid, GUINT_TO_POINTER (s->uid), s);
|
||||
}
|
||||
|
||||
g_strfreev (groups);
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
if (groups)
|
||||
g_strfreev (groups);
|
||||
free_database (self);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ensure_database (NMSessionMonitor *self, GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
|
||||
if (self->database != NULL) {
|
||||
struct stat statbuf;
|
||||
|
||||
if (stat (CKDB_PATH, &statbuf) != 0) {
|
||||
g_set_error (error,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR_GENERAL,
|
||||
"Error statting file " CKDB_PATH " to check timestamp: %s",
|
||||
strerror (errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (statbuf.st_mtime == self->database_mtime) {
|
||||
ret = TRUE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = reload_database (self, error);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
on_file_monitor_changed (GFileMonitor * file_monitor,
|
||||
GFile * file,
|
||||
GFile * other_file,
|
||||
GFileMonitorEvent event_type,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMSessionMonitor *self = NM_SESSION_MONITOR (user_data);
|
||||
|
||||
/* throw away cache */
|
||||
free_database (self);
|
||||
|
||||
g_signal_emit (self, signals[CHANGED], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
nm_session_monitor_init (NMSessionMonitor *self)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GFile *file;
|
||||
|
||||
/* Sessions-by-user is responsible for destroying the Session objects */
|
||||
self->sessions_by_user = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
NULL, (GDestroyNotify) session_free);
|
||||
self->sessions_by_uid = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
|
||||
|
||||
error = NULL;
|
||||
if (!ensure_database (self, &error)) {
|
||||
nm_log_err (LOGD_SYS_SET, "Error loading " CKDB_PATH ": %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
error = NULL;
|
||||
file = g_file_new_for_path (CKDB_PATH);
|
||||
self->database_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &error);
|
||||
g_object_unref (file);
|
||||
if (self->database_monitor == NULL) {
|
||||
nm_log_err (LOGD_SYS_SET, "Error monitoring " CKDB_PATH ": %s", error->message);
|
||||
g_error_free (error);
|
||||
} else {
|
||||
g_signal_connect (self->database_monitor,
|
||||
"changed",
|
||||
G_CALLBACK (on_file_monitor_changed),
|
||||
self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
finalize (GObject *object)
|
||||
{
|
||||
NMSessionMonitor *self = NM_SESSION_MONITOR (object);
|
||||
|
||||
if (self->database_monitor != NULL)
|
||||
g_object_unref (self->database_monitor);
|
||||
|
||||
free_database (self);
|
||||
|
||||
if (G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize != NULL)
|
||||
G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
nm_session_monitor_class_init (NMSessionMonitorClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = finalize;
|
||||
|
||||
/**
|
||||
* NMSessionMonitor::changed:
|
||||
* @monitor: A #NMSessionMonitor
|
||||
*
|
||||
* Emitted when something changes.
|
||||
*/
|
||||
signals[CHANGED] = g_signal_new ("changed",
|
||||
NM_TYPE_SESSION_MONITOR,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (NMSessionMonitorClass, changed),
|
||||
NULL, /* accumulator */
|
||||
NULL, /* accumulator data */
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
NMSessionMonitor *
|
||||
nm_session_monitor_get (void)
|
||||
{
|
||||
static NMSessionMonitor *singleton = NULL;
|
||||
|
||||
if (singleton)
|
||||
return NM_SESSION_MONITOR (g_object_ref (singleton));
|
||||
|
||||
return NM_SESSION_MONITOR (g_object_new (NM_TYPE_SESSION_MONITOR, NULL));
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* nm_session_monitor_user_has_session:
|
||||
* @monitor: A #NMSessionMonitor.
|
||||
* @username: A username.
|
||||
* @error: Return location for error.
|
||||
*
|
||||
* Checks whether the given @username is logged into a session or not.
|
||||
*
|
||||
* Returns: %FALSE if @error is set otherwise %TRUE if the given @username is
|
||||
* currently logged into a session.
|
||||
*/
|
||||
gboolean
|
||||
nm_session_monitor_user_has_session (NMSessionMonitor *monitor,
|
||||
const char *username,
|
||||
GError **error)
|
||||
{
|
||||
Session *s;
|
||||
|
||||
if (!ensure_database (monitor, error))
|
||||
return FALSE;
|
||||
|
||||
s = g_hash_table_lookup (monitor->sessions_by_user, (gpointer) username);
|
||||
if (!s) {
|
||||
g_set_error (error,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR_GENERAL,
|
||||
"No session found for user '%s'",
|
||||
username);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_session_monitor_uid_has_session:
|
||||
* @monitor: A #NMSessionMonitor.
|
||||
* @uid: A user ID.
|
||||
* @error: Return location for error.
|
||||
*
|
||||
* Checks whether the given @uid is logged into a session or not.
|
||||
*
|
||||
* Returns: %FALSE if @error is set otherwise %TRUE if the given @uid is
|
||||
* currently logged into a session.
|
||||
*/
|
||||
gboolean
|
||||
nm_session_monitor_uid_has_session (NMSessionMonitor *monitor,
|
||||
uid_t uid,
|
||||
GError **error)
|
||||
{
|
||||
Session *s;
|
||||
|
||||
if (!ensure_database (monitor, error))
|
||||
return FALSE;
|
||||
|
||||
s = g_hash_table_lookup (monitor->sessions_by_uid, GUINT_TO_POINTER (uid));
|
||||
if (!s) {
|
||||
g_set_error (error,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR_GENERAL,
|
||||
"No session found for uid %d",
|
||||
uid);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_session_monitor_user_active:
|
||||
* @monitor: A #NMSessionMonitor.
|
||||
* @username: A username.
|
||||
* @error: Return location for error.
|
||||
*
|
||||
* Checks whether the given @username is logged into a active session or not.
|
||||
*
|
||||
* Returns: %FALSE if @error is set otherwise %TRUE if the given @username is
|
||||
* logged into an active session.
|
||||
*/
|
||||
gboolean
|
||||
nm_session_monitor_user_active (NMSessionMonitor *monitor,
|
||||
const char *username,
|
||||
GError **error)
|
||||
{
|
||||
Session *s;
|
||||
|
||||
if (!ensure_database (monitor, error))
|
||||
return FALSE;
|
||||
|
||||
s = g_hash_table_lookup (monitor->sessions_by_user, (gpointer) username);
|
||||
if (!s) {
|
||||
g_set_error (error,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR_GENERAL,
|
||||
"No session found for user '%s'",
|
||||
username);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return s->active;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_session_monitor_uid_active:
|
||||
* @monitor: A #NMSessionMonitor.
|
||||
* @uid: A user ID.
|
||||
* @error: Return location for error.
|
||||
*
|
||||
* Checks whether the given @uid is logged into a active session or not.
|
||||
*
|
||||
* Returns: %FALSE if @error is set otherwise %TRUE if the given @uid is
|
||||
* logged into an active session.
|
||||
*/
|
||||
gboolean
|
||||
nm_session_monitor_uid_active (NMSessionMonitor *monitor,
|
||||
uid_t uid,
|
||||
GError **error)
|
||||
{
|
||||
Session *s;
|
||||
|
||||
if (!ensure_database (monitor, error))
|
||||
return FALSE;
|
||||
|
||||
s = g_hash_table_lookup (monitor->sessions_by_uid, GUINT_TO_POINTER (uid));
|
||||
if (!s) {
|
||||
g_set_error (error,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR,
|
||||
NM_SYSCONFIG_SETTINGS_ERROR_GENERAL,
|
||||
"No session found for uid '%d'",
|
||||
uid);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return s->active;
|
||||
}
|
||||
|
||||
60
src/system-settings/nm-session-monitor.h
Normal file
60
src/system-settings/nm-session-monitor.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* 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.
|
||||
*
|
||||
* (C) Copyright 2008 - 2010 Red Hat, Inc.
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
* Author: Dan Williams <dcbw@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef NM_SESSION_MONITOR_H
|
||||
#define NM_SESSION_MONITOR_H
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define NM_TYPE_SESSION_MONITOR (nm_session_monitor_get_type ())
|
||||
#define NM_SESSION_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NM_TYPE_SESSION_MONITOR, NMSessionMonitor))
|
||||
#define NM_SESSION_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), NM_TYPE_SESSION_MONITOR, NMSessionMonitorClass))
|
||||
#define NM_SESSION_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NM_TYPE_SESSION_MONITOR, NMSessionMonitorClass))
|
||||
#define NM_IS_SESSION_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NM_TYPE_SESSION_MONITOR))
|
||||
#define NM_IS_SESSION_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NM_TYPE_SESSION_MONITOR))
|
||||
|
||||
typedef struct _NMSessionMonitor NMSessionMonitor;
|
||||
typedef struct _NMSessionMonitorClass NMSessionMonitorClass;
|
||||
|
||||
GType nm_session_monitor_get_type (void) G_GNUC_CONST;
|
||||
NMSessionMonitor *nm_session_monitor_get (void);
|
||||
|
||||
gboolean nm_session_monitor_user_has_session (NMSessionMonitor *monitor,
|
||||
const char *username,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_session_monitor_uid_has_session (NMSessionMonitor *monitor,
|
||||
uid_t uid,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_session_monitor_user_active (NMSessionMonitor *monitor,
|
||||
const char *username,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_session_monitor_uid_active (NMSessionMonitor *monitor,
|
||||
uid_t uid,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* NM_SESSION_MONITOR_H */
|
||||
|
||||
Loading…
Add table
Reference in a new issue