1
0
Fork 0
gdm3/daemon/gdm-server.c
Daniel Baumann 83b37a3d94
Adding upstream version 48.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 19:45:29 +02:00

1089 lines
34 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <ctype.h>
#include <pwd.h>
#include <grp.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif
#ifdef WITH_PLYMOUTH
#include <linux/vt.h>
#endif
#include <systemd/sd-daemon.h>
#ifdef ENABLE_SYSTEMD_JOURNAL
#include <systemd/sd-journal.h>
#endif
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <gio/gio.h>
#ifdef ENABLE_X11_SUPPORT
#include <X11/Xlib.h> /* for Display */
#endif
#include "gdm-common.h"
#include "gdm-settings-direct.h"
#include "gdm-settings-keys.h"
#include "gdm-server.h"
extern char **environ;
#define MAX_LOGS 5
struct _GdmServer
{
GObject parent;
char *command;
GPid pid;
gboolean disable_tcp;
int priority;
char *user_name;
char *session_args;
char *log_dir;
char *display_name;
char *display_device;
char *display_seat_id;
char *auth_file;
guint child_watch_id;
gboolean is_initial;
};
enum {
PROP_0,
PROP_DISPLAY_NAME,
PROP_DISPLAY_SEAT_ID,
PROP_DISPLAY_DEVICE,
PROP_AUTH_FILE,
PROP_USER_NAME,
PROP_DISABLE_TCP,
PROP_IS_INITIAL,
};
enum {
READY,
EXITED,
DIED,
LAST_SIGNAL
};
static guint signals [LAST_SIGNAL] = { 0, };
static void gdm_server_class_init (GdmServerClass *klass);
static void gdm_server_init (GdmServer *server);
static void gdm_server_finalize (GObject *object);
G_DEFINE_TYPE (GdmServer, gdm_server, G_TYPE_OBJECT)
char *
gdm_server_get_display_device (GdmServer *server)
{
/* systemd finds the display device out on its own based on the display */
return NULL;
}
static void
gdm_server_ready (GdmServer *server)
{
g_debug ("GdmServer: Got USR1 from X server - emitting READY");
gdm_run_script (GDMCONFDIR "/Init", GDM_USERNAME,
server->display_name,
NULL, /* hostname */
server->auth_file);
g_signal_emit (server, signals[READY], 0);
}
static GSList *active_servers;
static gboolean sigusr1_thread_running;
static GCond sigusr1_thread_cond;
static GMutex sigusr1_thread_mutex;
static gboolean
got_sigusr1 (gpointer user_data)
{
GPid pid = GPOINTER_TO_UINT (user_data);
GSList *l;
g_debug ("GdmServer: got SIGUSR1 from PID %d", pid);
for (l = active_servers; l; l = l->next) {
GdmServer *server = l->data;
if (server->pid == pid)
gdm_server_ready (server);
}
return G_SOURCE_REMOVE;
}
static gpointer
sigusr1_thread_main (gpointer user_data)
{
sigset_t sigusr1_mask;
/* Handle only SIGUSR1 */
sigemptyset (&sigusr1_mask);
sigaddset (&sigusr1_mask, SIGUSR1);
sigprocmask (SIG_SETMASK, &sigusr1_mask, NULL);
g_mutex_lock (&sigusr1_thread_mutex);
sigusr1_thread_running = TRUE;
g_cond_signal (&sigusr1_thread_cond);
g_mutex_unlock (&sigusr1_thread_mutex);
/* Spin waiting for a SIGUSR1 */
while (TRUE) {
siginfo_t info;
if (sigwaitinfo (&sigusr1_mask, &info) == -1)
continue;
g_idle_add (got_sigusr1, GUINT_TO_POINTER (info.si_pid));
}
return NULL;
}
static void
gdm_server_launch_sigusr1_thread_if_needed (void)
{
static GThread *sigusr1_thread;
if (sigusr1_thread == NULL) {
sigusr1_thread = g_thread_new ("gdm SIGUSR1 catcher", sigusr1_thread_main, NULL);
g_mutex_lock (&sigusr1_thread_mutex);
while (!sigusr1_thread_running)
g_cond_wait (&sigusr1_thread_cond, &sigusr1_thread_mutex);
g_mutex_unlock (&sigusr1_thread_mutex);
}
}
static void
gdm_server_init_command (GdmServer *server)
{
gboolean debug = FALSE;
const char *debug_options;
const char *verbosity = "";
if (server->command != NULL) {
return;
}
gdm_settings_direct_get_boolean (GDM_KEY_DEBUG, &debug);
if (debug) {
debug_options = " -logverbose 7 -core ";
} else {
debug_options = "";
}
#define X_SERVER_ARG_FORMAT " -background none -noreset -verbose %s%s"
/* This is a temporary hack to work around the fact that XOrg
* currently lacks support for multi-seat hotplugging for
* display devices. This bit should be removed as soon as XOrg
* gains native support for automatically enumerating usb
* based graphics adapters at start-up via udev. */
/* systemd ships an X server wrapper tool which simply invokes
* the usual X but ensures it only uses the display devices of
* the seat. */
/* We do not rely on this wrapper server if, a) the machine
* wasn't booted using systemd, or b) the wrapper tool is
* missing, or c) we are running for the main seat 'seat0'. */
#ifdef ENABLE_SYSTEMD_JOURNAL
/* For systemd, we don't have a log file but instead log to stdout,
so set it to the xserver's built-in default verbosity */
if (debug)
verbosity = "7 -logfile /dev/null";
else
verbosity = "3 -logfile /dev/null";
#endif
if (g_access (SYSTEMD_X_SERVER, X_OK) < 0) {
goto fallback;
}
if (server->display_seat_id == NULL ||
strcmp (server->display_seat_id, "seat0") == 0) {
goto fallback;
}
server->command = g_strdup_printf (SYSTEMD_X_SERVER X_SERVER_ARG_FORMAT, verbosity, debug_options);
return;
fallback:
server->command = g_strdup_printf (X_SERVER X_SERVER_ARG_FORMAT, verbosity, debug_options);
}
static gboolean
gdm_server_resolve_command_line (GdmServer *server,
const char *vtarg,
int *argcp,
char ***argvp)
{
int argc;
char **argv;
int len;
int i;
gboolean gotvtarg = FALSE;
gboolean query_in_arglist = FALSE;
gdm_server_init_command (server);
if (!g_shell_parse_argv (server->command, &argc, &argv, NULL))
return FALSE;
for (len = 0; argv != NULL && argv[len] != NULL; len++) {
char *arg = argv[len];
/* HACK! Not to add vt argument to servers that already force
* allocation. Mostly for backwards compat only */
if (strncmp (arg, "vt", 2) == 0 &&
isdigit (arg[2]) &&
(arg[3] == '\0' ||
(isdigit (arg[3]) && arg[4] == '\0')))
gotvtarg = TRUE;
if (strcmp (arg, "-query") == 0 ||
strcmp (arg, "-indirect") == 0)
query_in_arglist = TRUE;
}
argv = g_renew (char *, argv, len + 12);
/* shift args down one */
for (i = len - 1; i >= 1; i--) {
argv[i+1] = argv[i];
}
/* server number is the FIRST argument, before any others */
argv[1] = g_strdup (server->display_name);
len++;
if (server->auth_file != NULL) {
argv[len++] = g_strdup ("-auth");
argv[len++] = g_strdup (server->auth_file);
}
if (server->display_seat_id != NULL) {
argv[len++] = g_strdup ("-seat");
argv[len++] = g_strdup (server->display_seat_id);
}
/* If we were compiled with Xserver >= 1.17 we need to specify
* '-listen tcp' as the X server dosen't listen on tcp sockets
* by default anymore. In older versions we need to pass
* -nolisten tcp to disable listening on tcp sockets.
*/
if (!query_in_arglist) {
if (server->disable_tcp) {
argv[len++] = g_strdup ("-nolisten");
argv[len++] = g_strdup ("tcp");
}
#ifdef HAVE_XSERVER_WITH_LISTEN
if (!server->disable_tcp) {
argv[len++] = g_strdup ("-listen");
argv[len++] = g_strdup ("tcp");
}
#endif
}
if (vtarg != NULL && ! gotvtarg) {
argv[len++] = g_strdup (vtarg);
}
argv[len++] = NULL;
*argvp = argv;
*argcp = len;
return TRUE;
}
static void
rotate_logs (const char *path,
guint n_copies)
{
int i;
for (i = n_copies - 1; i > 0; i--) {
char *name_n;
char *name_n1;
name_n = g_strdup_printf ("%s.%d", path, i);
if (i > 1) {
name_n1 = g_strdup_printf ("%s.%d", path, i - 1);
} else {
name_n1 = g_strdup (path);
}
VE_IGNORE_EINTR (g_unlink (name_n));
VE_IGNORE_EINTR (g_rename (name_n1, name_n));
g_free (name_n1);
g_free (name_n);
}
VE_IGNORE_EINTR (g_unlink (path));
}
static void
change_user (GdmServer *server)
{
struct passwd *pwent;
if (server->user_name == NULL) {
return;
}
gdm_get_pwent_for_name (server->user_name, &pwent);
if (pwent == NULL) {
g_warning (_("Server was to be spawned by user %s but that user doesnt exist"),
server->user_name);
_exit (EXIT_FAILURE);
}
g_debug ("GdmServer: Changing (uid:gid) for child process to (%d:%d)",
pwent->pw_uid,
pwent->pw_gid);
if (pwent->pw_uid != 0) {
if (setgid (pwent->pw_gid) < 0) {
g_warning (_("Couldnt set groupid to %d"),
pwent->pw_gid);
_exit (EXIT_FAILURE);
}
if (initgroups (pwent->pw_name, pwent->pw_gid) < 0) {
g_warning (_("initgroups () failed for %s"),
pwent->pw_name);
_exit (EXIT_FAILURE);
}
if (setuid (pwent->pw_uid) < 0) {
g_warning (_("Couldnt set userid to %d"),
(int)pwent->pw_uid);
_exit (EXIT_FAILURE);
}
} else {
gid_t groups[1] = { 0 };
if (setgid (0) < 0) {
g_warning (_("Couldnt set groupid to %d"), 0);
/* Don't error out, it's not fatal, if it fails we'll
* just still be */
}
/* this will get rid of any suplementary groups etc... */
setgroups (1, groups);
}
}
static gboolean
gdm_server_setup_journal_fds (GdmServer *server)
{
#ifdef ENABLE_SYSTEMD_JOURNAL
if (sd_booted () > 0) {
int out, err;
g_autofree char *identifier = NULL;
identifier = g_strdup_printf("gdm-Xorg-%s", server->display_name);
out = sd_journal_stream_fd (identifier, LOG_INFO, FALSE);
if (out < 0)
return FALSE;
err = sd_journal_stream_fd (identifier, LOG_WARNING, FALSE);
if (err < 0) {
close (out);
return FALSE;
}
VE_IGNORE_EINTR (dup2 (out, 1));
VE_IGNORE_EINTR (dup2 (err, 2));
return TRUE;
}
#endif
return FALSE;
}
static void
gdm_server_setup_logfile (GdmServer *server)
{
int logfd;
char *log_file;
char *log_path;
log_file = g_strdup_printf ("%s.log", server->display_name);
log_path = g_build_filename (server->log_dir, log_file, NULL);
g_free (log_file);
/* Rotate the X server logs */
rotate_logs (log_path, MAX_LOGS);
g_debug ("GdmServer: Opening logfile for server %s", log_path);
VE_IGNORE_EINTR (g_unlink (log_path));
VE_IGNORE_EINTR (logfd = open (log_path, O_CREAT|O_APPEND|O_TRUNC|O_WRONLY|O_EXCL, 0644));
g_free (log_path);
if (logfd != -1) {
VE_IGNORE_EINTR (dup2 (logfd, 1));
VE_IGNORE_EINTR (dup2 (logfd, 2));
close (logfd);
} else {
g_warning (_("%s: Could not open log file for display %s!"),
"gdm_server_spawn",
server->display_name);
}
}
static void
server_child_setup (GdmServer *server)
{
struct sigaction ign_signal;
sigset_t mask;
if (!gdm_server_setup_journal_fds(server))
gdm_server_setup_logfile(server);
/* The X server expects USR1/TTIN/TTOU to be SIG_IGN */
ign_signal.sa_handler = SIG_IGN;
ign_signal.sa_flags = SA_RESTART;
sigemptyset (&ign_signal.sa_mask);
if (sigaction (SIGUSR1, &ign_signal, NULL) < 0) {
g_warning (_("%s: Error setting %s to %s"),
"gdm_server_spawn", "USR1", "SIG_IGN");
_exit (EXIT_FAILURE);
}
if (sigaction (SIGTTIN, &ign_signal, NULL) < 0) {
g_warning (_("%s: Error setting %s to %s"),
"gdm_server_spawn", "TTIN", "SIG_IGN");
_exit (EXIT_FAILURE);
}
if (sigaction (SIGTTOU, &ign_signal, NULL) < 0) {
g_warning (_("%s: Error setting %s to %s"),
"gdm_server_spawn", "TTOU", "SIG_IGN");
_exit (EXIT_FAILURE);
}
/* And HUP and TERM are at SIG_DFL from gdm_unset_signals,
we also have an empty mask and all that fun stuff */
/* unblock signals (especially HUP/TERM/USR1) so that we
* can control the X server */
sigemptyset (&mask);
sigprocmask (SIG_SETMASK, &mask, NULL);
/* Terminate the process when the parent dies */
#ifdef HAVE_SYS_PRCTL_H
prctl (PR_SET_PDEATHSIG, SIGTERM);
#endif
if (server->priority != 0) {
if (setpriority (PRIO_PROCESS, 0, server->priority)) {
g_warning (_("%s: Server priority couldnt be set to %d: %s"),
"gdm_server_spawn",
server->priority,
g_strerror (errno));
}
}
setpgid (0, 0);
change_user (server);
}
static void
listify_hash (const char *key,
const char *value,
GPtrArray *env)
{
char *str;
str = g_strdup_printf ("%s=%s", key, value);
g_ptr_array_add (env, str);
}
static GPtrArray *
get_server_environment (GdmServer *server)
{
GPtrArray *env;
char **l;
GHashTable *hash;
env = g_ptr_array_new ();
/* create a hash table of current environment, then update keys has necessary */
hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
for (l = environ; *l != NULL; l++) {
char **str;
str = g_strsplit (*l, "=", 2);
g_hash_table_insert (hash, str[0], str[1]);
g_free (str);
}
/* modify environment here */
g_hash_table_insert (hash, g_strdup ("DISPLAY"), g_strdup (server->display_name));
if (server->user_name != NULL) {
struct passwd *pwent;
gdm_get_pwent_for_name (server->user_name, &pwent);
if (pwent->pw_dir != NULL
&& g_file_test (pwent->pw_dir, G_FILE_TEST_EXISTS)) {
g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup (pwent->pw_dir));
} else {
/* Hack */
g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup ("/"));
}
g_hash_table_insert (hash, g_strdup ("SHELL"), g_strdup (pwent->pw_shell));
g_hash_table_remove (hash, "MAIL");
}
g_hash_table_foreach (hash, (GHFunc)listify_hash, env);
g_hash_table_destroy (hash);
g_ptr_array_add (env, NULL);
return env;
}
static void
server_add_xserver_args (GdmServer *server,
int *argc,
char ***argv)
{
int count;
char **args;
int len;
int i;
len = *argc;
g_shell_parse_argv (server->session_args, &count, &args, NULL);
*argv = g_renew (char *, *argv, len + count + 1);
for (i=0; i < count;i++) {
*argv[len++] = g_strdup (args[i]);
}
*argc += count;
argv[len] = NULL;
g_strfreev (args);
}
static void
server_child_watch (GPid pid,
int status,
GdmServer *server)
{
g_debug ("GdmServer: child (pid:%d) done (%s:%d)",
(int) pid,
WIFEXITED (status) ? "status"
: WIFSIGNALED (status) ? "signal"
: "unknown",
WIFEXITED (status) ? WEXITSTATUS (status)
: WIFSIGNALED (status) ? WTERMSIG (status)
: -1);
g_object_ref (server);
if (WIFEXITED (status)) {
int code = WEXITSTATUS (status);
g_signal_emit (server, signals [EXITED], 0, code);
} else if (WIFSIGNALED (status)) {
int num = WTERMSIG (status);
g_signal_emit (server, signals [DIED], 0, num);
}
g_spawn_close_pid (server->pid);
server->pid = -1;
g_object_unref (server);
}
static void
prune_active_servers_list (GdmServer *server)
{
active_servers = g_slist_remove (active_servers, server);
}
static gboolean
gdm_server_spawn (GdmServer *server,
const char *vtarg,
GError **error)
{
int argc;
gchar **argv = NULL;
GPtrArray *env = NULL;
gboolean ret = FALSE;
char *freeme;
/* Figure out the server command */
argv = NULL;
argc = 0;
if (!gdm_server_resolve_command_line (server,
vtarg,
&argc,
&argv)) {
return FALSE;
}
if (server->session_args) {
server_add_xserver_args (server, &argc, &argv);
}
if (argv[0] == NULL) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
_("%s: Empty server command for display %s"),
"gdm_server_spawn",
server->display_name);
goto out;
}
env = get_server_environment (server);
freeme = g_strjoinv (" ", argv);
g_debug ("GdmServer: Starting X server process: %s", freeme);
g_free (freeme);
active_servers = g_slist_append (active_servers, server);
g_object_weak_ref (G_OBJECT (server),
(GWeakNotify)
prune_active_servers_list,
server);
gdm_server_launch_sigusr1_thread_if_needed ();
if (!g_spawn_async_with_pipes (NULL,
argv,
(char **)env->pdata,
G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
(GSpawnChildSetupFunc)server_child_setup,
server,
&server->pid,
NULL,
NULL,
NULL,
error))
goto out;
g_debug ("GdmServer: Started X server process %d - waiting for READY", (int)server->pid);
server->child_watch_id = g_child_watch_add (server->pid,
(GChildWatchFunc)server_child_watch,
server);
ret = TRUE;
out:
g_strfreev (argv);
if (env) {
g_ptr_array_foreach (env, (GFunc)g_free, NULL);
g_ptr_array_free (env, TRUE);
}
return ret;
}
/**
* gdm_server_start:
* @disp: Pointer to a GdmDisplay structure
*
* Starts a local X server. Handles retries and fatal errors properly.
*/
gboolean
gdm_server_start (GdmServer *server)
{
gboolean res = FALSE;
const char *vtarg = NULL;
GError *local_error = NULL;
GError **error = &local_error;
g_return_val_if_fail (GDM_IS_SERVER (server), FALSE);
/* Hardcode the VT for the initial X server, but nothing else */
if (server->is_initial) {
vtarg = "vt" G_STRINGIFY (GDM_INITIAL_VT);
}
/* fork X server process */
if (!gdm_server_spawn (server, vtarg, error)) {
goto out;
}
res = TRUE;
out:
if (local_error) {
g_printerr ("%s\n", local_error->message);
g_clear_error (&local_error);
}
return res;
}
static void
server_died (GdmServer *server)
{
int exit_status;
g_debug ("GdmServer: Waiting on process %d", server->pid);
exit_status = gdm_wait_on_pid (server->pid);
if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) {
g_debug ("GdmServer: Wait on child process failed");
} else {
/* exited normally */
}
g_spawn_close_pid (server->pid);
server->pid = -1;
if (server->display_device != NULL) {
g_free (server->display_device);
server->display_device = NULL;
g_object_notify (G_OBJECT (server), "display-device");
}
g_debug ("GdmServer: Server died");
}
gboolean
gdm_server_stop (GdmServer *server)
{
int res;
g_return_val_if_fail (GDM_IS_SERVER (server), FALSE);
if (server->pid <= 1) {
return TRUE;
}
/* remove watch source before we can wait on child */
g_clear_handle_id (&server->child_watch_id, g_source_remove);
g_debug ("GdmServer: Stopping server");
res = gdm_signal_pid (server->pid, SIGTERM);
if (res >= 0) {
server_died (server);
}
return TRUE;
}
static void
_gdm_server_set_display_name (GdmServer *server,
const char *name)
{
g_free (server->display_name);
server->display_name = g_strdup (name);
}
static void
_gdm_server_set_display_seat_id (GdmServer *server,
const char *name)
{
g_free (server->display_seat_id);
server->display_seat_id = g_strdup (name);
}
static void
_gdm_server_set_auth_file (GdmServer *server,
const char *auth_file)
{
g_free (server->auth_file);
server->auth_file = g_strdup (auth_file);
}
static void
_gdm_server_set_user_name (GdmServer *server,
const char *name)
{
g_free (server->user_name);
server->user_name = g_strdup (name);
}
static void
_gdm_server_set_disable_tcp (GdmServer *server,
gboolean disabled)
{
server->disable_tcp = disabled;
}
static void
_gdm_server_set_is_initial (GdmServer *server,
gboolean initial)
{
server->is_initial = initial;
}
static void
gdm_server_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdmServer *self;
self = GDM_SERVER (object);
switch (prop_id) {
case PROP_DISPLAY_NAME:
_gdm_server_set_display_name (self, g_value_get_string (value));
break;
case PROP_DISPLAY_SEAT_ID:
_gdm_server_set_display_seat_id (self, g_value_get_string (value));
break;
case PROP_AUTH_FILE:
_gdm_server_set_auth_file (self, g_value_get_string (value));
break;
case PROP_USER_NAME:
_gdm_server_set_user_name (self, g_value_get_string (value));
break;
case PROP_DISABLE_TCP:
_gdm_server_set_disable_tcp (self, g_value_get_boolean (value));
break;
case PROP_IS_INITIAL:
_gdm_server_set_is_initial (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_server_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdmServer *self;
self = GDM_SERVER (object);
switch (prop_id) {
case PROP_DISPLAY_NAME:
g_value_set_string (value, self->display_name);
break;
case PROP_DISPLAY_SEAT_ID:
g_value_set_string (value, self->display_seat_id);
break;
case PROP_DISPLAY_DEVICE:
g_value_take_string (value,
gdm_server_get_display_device (self));
break;
case PROP_AUTH_FILE:
g_value_set_string (value, self->auth_file);
break;
case PROP_USER_NAME:
g_value_set_string (value, self->user_name);
break;
case PROP_DISABLE_TCP:
g_value_set_boolean (value, self->disable_tcp);
break;
case PROP_IS_INITIAL:
g_value_set_boolean (value, self->is_initial);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_server_class_init (GdmServerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = gdm_server_get_property;
object_class->set_property = gdm_server_set_property;
object_class->finalize = gdm_server_finalize;
signals [READY] =
g_signal_new ("ready",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
signals [EXITED] =
g_signal_new ("exited",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE,
1,
G_TYPE_INT);
signals [DIED] =
g_signal_new ("died",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE,
1,
G_TYPE_INT);
g_object_class_install_property (object_class,
PROP_DISPLAY_NAME,
g_param_spec_string ("display-name",
"name",
"name",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_DISPLAY_SEAT_ID,
g_param_spec_string ("display-seat-id",
"Seat ID",
"ID of the seat this display is running on",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_DISPLAY_DEVICE,
g_param_spec_string ("display-device",
"Display Device",
"Path to terminal display is running on",
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_AUTH_FILE,
g_param_spec_string ("auth-file",
"Authorization File",
"Path to X authorization file",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_USER_NAME,
g_param_spec_string ("user-name",
"user name",
"user name",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_DISABLE_TCP,
g_param_spec_boolean ("disable-tcp",
NULL,
NULL,
TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_IS_INITIAL,
g_param_spec_boolean ("is-initial",
NULL,
NULL,
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
}
static void
gdm_server_init (GdmServer *server)
{
server->pid = -1;
server->log_dir = g_strdup (LOGDIR);
}
static void
gdm_server_finalize (GObject *object)
{
GdmServer *server;
g_return_if_fail (object != NULL);
g_return_if_fail (GDM_IS_SERVER (object));
server = GDM_SERVER (object);
gdm_server_stop (server);
g_free (server->command);
g_free (server->user_name);
g_free (server->session_args);
g_free (server->log_dir);
g_free (server->display_name);
g_free (server->display_seat_id);
g_free (server->display_device);
g_free (server->auth_file);
G_OBJECT_CLASS (gdm_server_parent_class)->finalize (object);
}
GdmServer *
gdm_server_new (const char *display_name,
const char *seat_id,
const char *auth_file,
gboolean initial)
{
GObject *object;
object = g_object_new (GDM_TYPE_SERVER,
"display-name", display_name,
"display-seat-id", seat_id,
"auth-file", auth_file,
"is-initial", initial,
NULL);
return GDM_SERVER (object);
}