summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAuke Kok <auke-jan.h.kok@intel.com>2012-04-23 10:51:22 -0700
committerAuke Kok <auke-jan.h.kok@intel.com>2012-04-23 10:51:22 -0700
commit398fb35d2d56a952ba244e6e811ab96e22797cc5 (patch)
treecc0f985349a732786c1c9039b6d30cf340d96dc4
parente44329cfd7cec25aa9b23cbf2798427172070946 (diff)
downloadxorg-launch-helper-398fb35d2d56a952ba244e6e811ab96e22797cc5.tar.gz
xorg-launch-helper-398fb35d2d56a952ba244e6e811ab96e22797cc5.tar.bz2
xorg-launch-helper-398fb35d2d56a952ba244e6e811ab96e22797cc5.zip
Bulk of the xorg-launch-helper checkin.
-rw-r--r--.gitignore4
-rw-r--r--Makefile.am4
-rw-r--r--configure.ac27
-rw-r--r--src/Makefile.am5
-rw-r--r--src/lib.c60
-rw-r--r--src/main.c196
-rw-r--r--src/pam.c130
-rw-r--r--src/user-session.h60
-rw-r--r--src/user.c224
-rw-r--r--src/xserver.c311
-rw-r--r--user-session.service.in17
-rw-r--r--xorg.service.in10
12 files changed, 124 insertions, 924 deletions
diff --git a/.gitignore b/.gitignore
index e409e19..99e62dd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,5 +15,5 @@ src/.deps/
src/Makefile
src/Makefile.in
stamp-h1
-user-session.service
-user-session-*.tar.*
+xorg.service
+xorg-launch-helper-*.tar.*
diff --git a/Makefile.am b/Makefile.am
index bdea291..f68b439 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,5 @@ SUBDIRS = src
EXTRA_DIST = AUTHORS COPYING INSTALL
-DISTCHECK_CONFIGURE_FLAGS = "--with-default-username=user"
-
systemdunitdir = @SYSTEMD_UNITDIR@
-systemdunit_DATA = user-session.service
+systemdunit_DATA = xorg.service xorg.target
diff --git a/configure.ac b/configure.ac
index 4169b0d..b744084 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.68])
-AC_INIT([user-session], [1], [auke-jan.h.kok@intel.com])
+AC_INIT([xorg-launch-helper], [1], [auke-jan.h.kok@intel.com])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_CONFIG_FILES([Makefile src/Makefile])
AC_CONFIG_SRCDIR([src/main.c])
@@ -12,9 +12,6 @@ AC_CONFIG_HEADERS([config.h])
AC_PROG_CC
AC_PROG_INSTALL
-# FIXME: Replace `main' with a function in `-lpam':
-AC_CHECK_LIB([pam], [main], ,
- AC_MSG_ERROR([libpam is required but was not found]))
# FIXME: Replace `main' with a function in `-lpthread':
AC_CHECK_LIB([pthread], [main], ,
AC_MSG_ERROR([libpthread is required but was not found]))
@@ -33,25 +30,15 @@ AC_SUBST(SYSTEMD_UNITDIR)
AM_CONDITIONAL(SYSTEMD, test -n "${path_systemdunit}")
fi
-echo "checking for default username to logon... "
-AC_ARG_WITH([default_username], AC_HELP_STRING([--with-default-username=USER],
- [default username to logon (default: unset)]), [default_username=${withval}],)
-if (test -n "${default_username}"); then
- AC_DEFINE_UNQUOTED([DEFAULT_USERNAME], ["$default_username"], [Which user to logon])
-else
- AC_ERROR([Required value for --with-default-username=<USER> is missing.])
-fi
-
# Checks for header files.
-AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h sys/ioctl.h sys/time.h syslog.h unistd.h])
-
-# Checks for typedefs, structures, and compiler characteristics.
-AC_TYPE_UINT64_T
+AC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/ioctl.h unistd.h])
# Checks for library functions.
-AC_FUNC_CHOWN
AC_FUNC_FORK
-AC_CHECK_FUNCS([clock_gettime gettimeofday memset mkdir setenv strchr strdup strstr uname])
+AC_CHECK_FUNCS([clock_gettime memset strdup])
-AC_OUTPUT(user-session.service)
+AC_OUTPUT([
+xorg.service
+xorg.target
+])
diff --git a/src/Makefile.am b/src/Makefile.am
index 712f092..333c07b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,5 @@
-bin_PROGRAMS = user-session
-user_session_SOURCES = lib.c pam.c user.c xserver.c main.c
+bin_PROGRAMS = xorg-launch-helper
+xorg_launch_helper_SOURCES = main.c
-noinst_HEADERS = user-session.h
diff --git a/src/lib.c b/src/lib.c
deleted file mode 100644
index 0110b62..0000000
--- a/src/lib.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * This file is part of user-session
- *
- * (C) Copyright 2009 Intel Corporation
- * Authors:
- * Auke Kok <auke@linux.intel.com>
- * Arjan van de Ven <arjan@linux.intel.com>
- *
- * 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; version 2
- * of the License.
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <string.h>
-#include <syslog.h>
-
-#include "user-session.h"
-
-
-extern char **environ;
-
-static int first_time = 1;
-
-static struct timeval start;
-
-
-void lprintf(const char* fmt, ...)
-{
- va_list args;
- struct timeval current;
- uint64_t secs, usecs;
- char string[8192];
- char msg[8192];
-
- if (first_time) {
- first_time = 0;
- gettimeofday(&start, NULL);
- }
-
- va_start(args, fmt);
- vsnprintf(msg, 8192, fmt, args);
- va_end(args);
-
- if (msg[strlen(msg) - 1] == '\n')
- msg[strlen(msg) - 1] = '\0';
-
- openlog("user-session", LOG_PID | LOG_CONS,
- geteuid() ? LOG_USER : LOG_USER);
- syslog(LOG_NOTICE, "%s", msg);
- closelog();
-}
-
diff --git a/src/main.c b/src/main.c
index 383782e..4f996b2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -13,131 +13,139 @@
*/
#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <signal.h>
+#include <pthread.h>
+#include <string.h>
+#include <linux/limits.h>
+#include <linux/vt.h>
+#include <linux/kd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
#include <pwd.h>
+#include <time.h>
-#include "user-session.h"
-int tty = 1;
-char username[256] = DEFAULT_USERNAME;
-char dpinum[256] = "auto";
-char addn_xopts[256] = "";
-int session_pid;
+static char displayname[256] = ":0"; /* ":0" */
+static int tty = 1; /* tty1 */
+static pthread_mutex_t notify_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t notify_condition = PTHREAD_COND_INITIALIZER;
-static void
-start_systemd_session(void)
-{
- char *ptrs[3];
- int ret;
- ret = fork();
- if (ret) {
- session_pid = ret;
- return; /* parent remains active */
- }
-
- ret = system("/usr/bin/xdg-user-dirs-update");
- if (ret)
- lprintf("/usr/bin/xdg-user-dirs-update failed");
+static void usr1handler(int foo)
+{
+ /* Got the signal from the X server that it's ready */
+ if (foo++) foo--; /* shut down warning */
- ptrs[0] = strdup("/usr/lib/systemd/systemd");
- ptrs[1] = strdup("--user");
- ptrs[2] = NULL;
- ret = execv(ptrs[0], ptrs);
+ pthread_mutex_lock(&notify_mutex);
+ pthread_cond_signal(&notify_condition);
+ pthread_mutex_unlock(&notify_mutex);
+}
- if (ret != EXIT_SUCCESS)
- lprintf("Failed to start systemd --user");
- return;
-}
-/*
- * Launch apps that form the user's X session
- */
-static void
-launch_user_session(void)
+int main(int argc, char **argv)
{
- char xhost_cmd[80];
+ struct sigaction usr1;
+ char *xserver = NULL;
+ int ret;
+ char vt[80];
+ char xorg_log[PATH_MAX];
+ struct stat statbuf;
+ char *ptrs[32];
+ int count = 0;
+ char all[PATH_MAX] = "";
+ int i;
+
+ /* Step 1: arm the signal */
+ memset(&usr1, 0, sizeof(struct sigaction));
+ usr1.sa_handler = usr1handler;
+ sigaction(SIGUSR1, &usr1, NULL);
+
+ /* Step 2: fork */
+ ret = fork();
+ if (ret) {
+ struct timespec tv;
- dprintf("entering launch_user_session()");
+ fprintf(stderr, "Started Xorg[%d]", ret);
- setup_user_environment();
+ /* setup sighandler for main thread */
+ clock_gettime(CLOCK_REALTIME, &tv);
+ tv.tv_sec += 10;
- start_systemd_session();
+ pthread_mutex_lock(&notify_mutex);
+ pthread_cond_timedwait(&notify_condition, &notify_mutex, &tv);
+ pthread_mutex_unlock(&notify_mutex);
- /* finally, set local username to be allowed at any time,
- * which is not depenedent on hostname changes */
- snprintf(xhost_cmd, 80, "/usr/bin/xhost +SI:localuser:%s",
- pass->pw_name);
- if (system(xhost_cmd) != 0)
- lprintf("%s failed", xhost_cmd);
+ //FIXME - return an error code if timer expired instead.
+ exit(EXIT_SUCCESS);
+ }
- dprintf("leaving launch_user_session()");
-}
+ /* if we get here we're the child */
+
+ /* Step 3: find the X server */
-int main(int argc, char **argv)
-{
/*
- * General objective:
- * Do the things that need root privs first,
- * then switch to the final user ASAP.
- *
- * Once we're at the target user ID, we need
- * to start X since that's the critical element
- * from that point on.
- *
- * While X is starting, we can do the things
- * that we need to do as the user UID, but that
- * don't need X running yet.
- *
- * We then wait for X to signal that it's ready
- * to draw stuff.
- *
- * Once X is running, we set up the ConsoleKit session,
- * check if the screensaver needs to lock the screen
- * and then start the window manager.
- * After that we go over the autostart .desktop files
- * to launch the various autostart processes....
- * ... and we're done.
+ * set the X server sigchld to SIG_IGN, that's the
+ * magic to make X send the parent the signal.
*/
+ signal(SIGUSR1, SIG_IGN);
+
+ if (!xserver) {
+ if (!access("/usr/bin/Xorg", X_OK))
+ xserver = "/usr/bin/Xorg";
+ else if (!access("/usr/bin/X", X_OK))
+ xserver = "/usr/bin/X";
+ else {
+ fprintf(stderr, "No X server found!");
+ exit(EXIT_FAILURE);
+ }
+ }
- pass = getpwnam(username);
-
- set_tty();
-
- setup_pam_session();
+ /* assemble command line */
+ memset(ptrs, 0, sizeof(ptrs));
- switch_to_user();
+ ptrs[0] = xserver;
- start_X_server();
+ ptrs[++count] = displayname;
- /*
- * These steps don't need X running
- * so can happen while X is talking to the
- * hardware
- */
- wait_for_X_signal();
+ /* non-suid root Xorg? */
+ ret = stat(xserver, &statbuf);
+ if (!(!ret && (statbuf.st_mode & S_ISUID))) {
+ snprintf(xorg_log, PATH_MAX, "%s/.Xorg.0.log", getenv("HOME"));
+ ptrs[++count] = strdup("-logfile");
+ ptrs[++count] = xorg_log;
+ } else {
+ fprintf(stderr, "WARNING: Xorg is setuid root - bummer.");
+ }
- launch_user_session();
+ ptrs[++count] = strdup("-nolisten");
+ ptrs[++count] = strdup("tcp");
- /*
- * The desktop session runs here
- */
- wait_for_X_exit();
+ ptrs[++count] = strdup("-noreset");
- set_text_mode();
+ for (i = 1; i < argc; i++)
+ ptrs[++count] = strdup(argv[i]);
- // close_consolekit_session();
- close_pam_session();
+ snprintf(vt, 80, "vt%d", tty);
+ ptrs[++count] = vt;
- /* Make sure that we clean up after ourselves */
- sleep(1);
+ for (i = 0; i <= count; i++) {
+ strncat(all, ptrs[i], PATH_MAX - strlen(all) - 1);
+ if (i < count)
+ strncat(all, " ", PATH_MAX - strlen(all) - 1);
+ }
+ fprintf(stderr, "starting X server with: \"%s\"", all);
- lprintf("Terminating user-session and all children");
- kill(0, SIGKILL);
+ execv(ptrs[0], ptrs);
- return EXIT_SUCCESS;
+ exit(EXIT_FAILURE);
}
diff --git a/src/pam.c b/src/pam.c
deleted file mode 100644
index 8a1b04e..0000000
--- a/src/pam.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * This file is part of user-session
- *
- * (C) Copyright 2009 Intel Corporation
- * Authors:
- * Auke Kok <auke@linux.intel.com>
- * Arjan van de Ven <arjan@linux.intel.com>
- * Michael Meeks <michael.meeks@novell.com>
- *
- * 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; version 2
- * of the License.
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <pwd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <security/pam_appl.h>
-
-#include "user-session.h"
-
-static pam_handle_t *ph;
-static struct pam_conv pc;
-
-/*
- * Sometimes PAM likes to chat with you, before it is assured
- * enough to let you log-in: fun.
- */
-static int
-pam_conversation_fn(int msg_count,
- const struct pam_message **messages,
- struct pam_response **responses,
- void *user_data)
-{
- int i;
- (void)user_data;
-
- d_in();
-
- lprintf("pam conversation with %d messages", msg_count);
- if (responses)
- *responses = NULL;
-
- if (msg_count < 1) /* ping */
- return PAM_SUCCESS;
-
- /* otherwise find any helpful data we can to print, and bail */
- if (!responses || !messages) {
- lprintf("pam conversation with no message, or response");
- return PAM_CONV_ERR;
- }
- *responses = calloc (msg_count, sizeof (struct pam_response));
- for (i = 0; i < msg_count; i++) {
- const struct pam_message *msg = messages[i];
-
- if (msg->msg_style == PAM_TEXT_INFO)
- lprintf("pam chats to us: '%s'", msg->msg);
- else if (msg->msg_style == PAM_ERROR_MSG)
- lprintf("Error: pam error msg '%s'", msg->msg);
- else
- lprintf("pam message %d style %d: '%s'",
- i, msg->msg_style, msg->msg);
- (*responses)[i].resp = NULL;
- (*responses)[i].resp_retcode = PAM_SUCCESS;
- }
-
- d_out();
- return PAM_SUCCESS;
-}
-
-/*
- * Creating a PAM session. We need a pam "login" session so that the dbus
- * "at_console" logic will work correctly, as well as various /dev file
- * permissions.
- *
- * for pam_console to work we need to set the PAM_TTY and PAM_XDISPLAY variables,
- * before we open the session. "PAM_TTY" takes input in the form "ttyX", without
- * the /dev prefix, so we need to construct that in place here.
- */
-void setup_pam_session(void)
-{
- char x[256];
- int err;
-
- d_in();
-
- snprintf(x, 256, "tty%d", tty);
-
- pc.conv = pam_conversation_fn;
- pc.appdata_ptr = NULL;
-
- err = pam_start("login", pass->pw_name, &pc, &ph);
-
- err = pam_set_item(ph, PAM_TTY, &x);
- if (err != PAM_SUCCESS) {
- lprintf("pam_set_item PAM_TTY returned %d: %s\n", err, pam_strerror(ph, err));
- exit(EXIT_FAILURE);
- }
-
- err = pam_set_item(ph, PAM_XDISPLAY, &displayname);
- if (err != PAM_SUCCESS) {
- lprintf("pam_set_item PAM_DISPLAY returned %d: %s\n", err, pam_strerror(ph, err));
- exit(EXIT_FAILURE);
- }
-
- err = pam_open_session(ph, 0);
- if (err != PAM_SUCCESS) {
- lprintf("pam_open_session returned %d: %s\n", err, pam_strerror(ph, err));
- exit(EXIT_FAILURE);
- }
- d_out();
-}
-
-void close_pam_session(void)
-{
- int err;
-
- d_in();
-
- err = pam_close_session(ph, 0);
- if (err)
- lprintf("pam_close_session returned %d: %s\n", err, pam_strerror(ph, err));
- pam_end(ph, err);
- d_out();
-}
diff --git a/src/user-session.h b/src/user-session.h
deleted file mode 100644
index b47d008..0000000
--- a/src/user-session.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef __USER_SESSION_H__
-#define __USER_SESSION_H__
-
-#include <X11/Xauth.h>
-#include <sys/types.h>
-#include <pwd.h>
-
-#include "../config.h"
-
-/*
- * Target user information
- */
-extern struct passwd *pass;
-
-extern char displaydev[];
-extern char displayname[];
-
-extern int tty;
-extern char session[];
-extern char username[];
-extern char dpinum[];
-
-extern int session_pid;
-extern int xpid;
-
-extern int verbose;
-extern char addn_xopts[];
-
-extern void get_options(int argc, char **argv);
-extern void set_i18n(void);
-extern void setup_pam_session(void);
-extern void close_pam_session(void);
-extern void switch_to_user(void);
-extern void setup_user_environment(void);
-extern void set_tty(void);
-extern void start_X_server(void);
-extern void wait_for_X_signal(void);
-extern void wait_for_session_exit(void);
-extern void start_bash(void);
-extern void wait_for_X_exit(void);
-extern void set_text_mode(void);
-
-extern void lprintf(const char *, ...);
-
-#define NORMAL 0
-#define NICE 1
-#define PIN 2
-#define DELAYED 4
-#define BACKGROUND 8
-
-
-#define d_in() dprintf("Enter: %s/%s", __FILE__, __func__)
-#define d_out() dprintf("Exit: %s/%s", __FILE__, __func__)
-#ifdef DEBUG
-#define dprintf(...) lprintf(__VA_ARGS__)
-#else
-#define dprintf(...) do {} while (0)
-#endif
-
-#endif /* ! __USER_SESSION_H_ */
diff --git a/src/user.c b/src/user.c
deleted file mode 100644
index 640c03e..0000000
--- a/src/user.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * This file is part of user-session
- *
- * (C) Copyright 2009 Intel Corporation
- * Authors:
- * Auke Kok <auke@linux.intel.com>
- * Arjan van de Ven <arjan@linux.intel.com>
- *
- * 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; version 2
- * of the License.
- */
-
-#define _GNU_SOURCE
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dirent.h>
-#include <sys/types.h>
-#include <pwd.h>
-#include <grp.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-
-#include "user-session.h"
-
-#include <X11/Xauth.h>
-
-static int uid;
-struct passwd *pass;
-
-static void do_env(void)
-{
- char buf[PATH_MAX];
- FILE *file;
-
- d_in();
-
- /* start with a clean environ */
- clearenv();
-
- setenv("USER", pass->pw_name, 1);
- setenv("LOGNAME", pass->pw_name, 1);
- setenv("HOME", pass->pw_dir, 1);
- setenv("SHELL", pass->pw_shell, 1);
- snprintf(buf, PATH_MAX, "/var/spool/mail/%s", pass->pw_name);
- setenv("MAIL", buf, 1);
- setenv("DISPLAY", displayname, 1);
- snprintf(buf, PATH_MAX, "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:%s/bin", pass->pw_dir);
- setenv("PATH", buf, 1);
-
- file = popen("/bin/bash -l -c export", "r");
- if (!file)
- return;
-
- while (!feof(file)) {
- char *c;
- memset(buf, 0, sizeof(buf));
- if (fgets(buf, sizeof(buf) - 1, file) == NULL)
- break;
- c = strchr(buf, '\n');
-
- if (strlen(buf) < 12)
- continue;
- if (c)
- *c = 0;
-
- if (strstr(buf, "PWD"))
- continue;
-// if (strstr(buf, "DISPLAY"))
-// continue;
-
- c = strchr(buf, '=');
- if (c) {
- char *c2;
- *c = 0;
- c++;
- if (*c == '"') c++;
- c2 = strchr(c, '"');
- if (c2)
- *c2 = 0;
- dprintf("Setting %s to %s\n", &buf[11], c);
- setenv(&buf[11], c, 1);
- }
-
- }
-
- pclose(file);
- d_out();
-}
-
-/*
- * Change from root (as we started) to the target user.
- * Steps
- * 1) setuid/getgid
- * 2) env variables: HOME, MAIL, LOGNAME, USER, SHELL, DISPLAY and PATH
- * 3) chdir(/home/foo);
- */
-void switch_to_user(void)
-{
- FILE *fp;
- char fn[PATH_MAX];
- int ret;
-
- d_in();
-
- initgroups(pass->pw_name, pass->pw_gid);
-
- /* make sure that the user owns /dev/ttyX */
- ret = chown(displaydev, pass->pw_uid, pass->pw_gid);
- if (ret)
- lprintf("Failed to fix /dev/tty permission");
-
- if (!((setgid(pass->pw_gid) == 0) && (setuid(pass->pw_uid) == 0))) {
- lprintf("Fatal: Unable to setgid()/setuid()\n");
- exit(EXIT_FAILURE);
- }
-
- if (access(pass->pw_dir, R_OK || W_OK || X_OK) != 0) {
- lprintf("Fatal: \"%s\" has incompatible permissions", pass->pw_dir);
- exit(EXIT_FAILURE);
- }
-
- /* This should fail, so, only print out info when it succeeded */
- ret = setpgid(0, getpgid(getppid()));
- if (ret != -1)
- lprintf("setpgid() returned %d", ret);
- ret = setsid();
- if (ret != -1)
- lprintf("setsid returned %d", ret);
-
- do_env();
-
- set_i18n();
-
- ret = chdir(pass->pw_dir);
-
- d_out();
-}
-
-void setup_user_environment (void)
-{
- unsigned int i;
- char buf[PATH_MAX];
- const char *lang = getenv ("LANG");
-
- d_in();
-
- /* setup misc. user directories and variables */
- snprintf(buf, PATH_MAX, "%s/.cache", pass->pw_dir);
- mkdir(buf, 0700);
- setenv("XDG_CACHE_HOME", buf, 0);
-
- snprintf(buf, PATH_MAX, "%s/.config", pass->pw_dir);
- setenv("XDG_CONFIG_HOME", buf, 0);
-
- snprintf(buf, PATH_MAX, "/run/user/%s", pass->pw_name);
- setenv("XDG_RUNTIME_DIR", buf, 0);
-
- snprintf(buf, PATH_MAX, "unix:path=/run/user/%s/dbus-session-bus-socket", pass->pw_name);
- setenv("DBUS_SESSION_BUS_ADDRESS", buf, 0);
-
- setenv("LIBC_FATAL_STDERR_", "1", 0);
-
- d_out();
-}
-
-void set_i18n(void)
-{
- FILE *f;
- char path[PATH_MAX];
- char buf[256];
- char *key;
- char *val;
-
- d_in();
-
- /*
- * /etc/sysconfig/i18n contains shell code that sets
- * various i18n options in environment, typically:
- * LANG, SYSFONT
- */
- snprintf(path, PATH_MAX, "%s/.config/i18n", pass->pw_dir);
- f = fopen(path, "r");
- if (f)
- goto parse;
- dprintf("Unable to open ~/.config/i18n, trying /etc/sysconfig/i18n");
- f = fopen("/etc/sysconfig/i18n", "r");
- if (f)
- goto parse;
- d_out();
- return;
-
-parse:
- while (fgets(buf, 256, f) != NULL) {
- char *c;
-
- c = strchr(buf, '\n');
- if (c) *c = 0; /* remove trailing \n */
- if (buf[0] == '#')
- continue; /* skip comments */
-
- key = strtok(buf, "=");
- if (!key)
- continue;
- val = strtok(NULL, "=\""); /* note \" */
- if (!val)
- continue;
-
- /* grab the stuff we need, avoiding comments
- * and other user stuff we don't care for now */
- if (!strcmp(key, "LANG"))
- setenv(key, val, 1);
- if (!strcmp(key, "SYSFONT"))
- setenv(key, val, 1);
- }
- fclose(f);
-
- d_out();
-}
diff --git a/src/xserver.c b/src/xserver.c
deleted file mode 100644
index 41702a4..0000000
--- a/src/xserver.c
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * This file is part of user-session
- *
- * (C) Copyright 2009 Intel Corporation
- * Authors:
- * Auke Kok <auke@linux.intel.com>
- * Arjan van de Ven <arjan@linux.intel.com>
- *
- * 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; version 2
- * of the License.
- */
-
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <pthread.h>
-#include <string.h>
-#include <linux/limits.h>
-#include <linux/vt.h>
-#include <linux/kd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/utsname.h>
-#include <pwd.h>
-#include <time.h>
-
-#include "user-session.h"
-
-char displaydev[PATH_MAX]; /* "/dev/tty1" */
-char displayname[256] = ":0"; /* ":0" */
-
-static pthread_mutex_t notify_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t notify_condition = PTHREAD_COND_INITIALIZER;
-
-int xpid;
-
-static volatile int exiting = 0;
-
-/*
- * We need to know the DISPLAY and TTY values to use, for passing
- * to PAM, ConsoleKit but also X.
- * TIOCLINUX will tell us which console is currently showing
- * for this purpose.
- */
-void set_tty(void)
-{
- int fd;
- struct vt_stat v;
-
- d_in();
-
- /* switch to this console */
- fd = open("/dev/console", O_RDWR);
- if (fd < 0) {
- lprintf("Unable to open /dev/console, using stdin");
- fd = 0;
- }
-
- if (ioctl(fd, VT_GETSTATE, &v)) {
- lprintf("VT_GETSTATE failed");
- close(fd);
- return;
- }
-
- if (v.v_active != tty) {
- if (ioctl(fd, VT_ACTIVATE, tty))
- lprintf("VT_ACTIVATE failed");
- }
- close(fd);
-
- snprintf(displaydev, PATH_MAX, "/dev/tty%d", tty);
-
- lprintf("Using %s as display device", displaydev);
-
- d_out();
-}
-
-static void usr1handler(int foo)
-{
- /* Got the signal from the X server that it's ready */
- if (foo++) foo--; /* shut down warning */
-
- dprintf("received USR1");
- pthread_mutex_lock(&notify_mutex);
- pthread_cond_signal(&notify_condition);
- pthread_mutex_unlock(&notify_mutex);
-}
-
-
-static void termhandler(int foo)
-{
- if (foo++) foo--; /* shut down warning */
-
- d_in();
-
- exiting = 1;
- /*
- * we received either:
- * - a TERM from init when switching to init 3
- * - an INT from a ^C press in the console when running in fg
- *
- * This kills ONLY the X server, everything else will be killed
- * when we exit the waitpid() loop.
- */
- if (session_pid)
- kill(session_pid, SIGKILL);
-
- kill(xpid, SIGTERM);
- d_out();
-}
-
-
-/*
- * start the X server
- * Step 1: arm the signal
- * Step 2: fork to get ready for the exec, continue from the main thread
- * Step 3: find the X server
- * Step 4: start the X server
- */
-void start_X_server(void)
-{
- struct sigaction usr1;
- struct sigaction term;
- char *xserver = NULL;
- int ret;
- char vt[80];
- char xorg_log[PATH_MAX];
- struct stat statbuf;
- char *ptrs[32];
- int count = 0;
- char all[PATH_MAX] = "";
- int i;
- char *opt;
- FILE *fp;
- char fn[PATH_MAX];
-
- d_in();
-
- /* Step 1: arm the signal */
- memset(&usr1, 0, sizeof(struct sigaction));
- usr1.sa_handler = usr1handler;
- sigaction(SIGUSR1, &usr1, NULL);
-
- /* Step 2: fork */
- ret = fork();
- if (ret) {
- xpid = ret;
- lprintf("Started Xorg[%d]", xpid);
- /* setup sighandler for main thread */
- memset(&term, 0, sizeof(struct sigaction));
- term.sa_handler = termhandler;
- sigaction(SIGTERM, &term, NULL);
- sigaction(SIGINT, &term, NULL);
- d_out();
- return; /* we're the main thread */
- }
-
- /* if we get here we're the child */
-
- /* Step 3: find the X server */
-
- /*
- * set the X server sigchld to SIG_IGN, that's the
- * magic to make X send the parent the signal.
- */
- signal(SIGUSR1, SIG_IGN);
-
- if (!xserver) {
- if (!access("/usr/bin/Xorg", X_OK))
- xserver = "/usr/bin/Xorg";
- else if (!access("/usr/bin/X", X_OK))
- xserver = "/usr/bin/X";
- else {
- lprintf("No X server found!");
- _exit(EXIT_FAILURE);
- }
- }
-
- snprintf(vt, 80, "vt%d", tty);
-
- /* assemble command line */
- memset(ptrs, 0, sizeof(ptrs));
-
- ptrs[0] = xserver;
-
- ptrs[++count] = displayname;
-
- /* non-suid root Xorg? */
- ret = stat(xserver, &statbuf);
- if (!(!ret && (statbuf.st_mode & S_ISUID))) {
- snprintf(xorg_log, PATH_MAX, "%s/.Xorg.0.log", pass->pw_dir);
- ptrs[++count] = strdup("-logfile");
- ptrs[++count] = xorg_log;
- } else {
- lprintf("WARNING: Xorg is setuid root - bummer.");
- }
-
- /* dpi */
- if (strcmp(dpinum, "auto")) {
- lprintf("Forcing DPI=%s", dpinum);
- /* hard-coded dpi */
- ptrs[++count] = strdup("-dpi");
- ptrs[++count] = dpinum;
- } /* else dpi==auto */
-
- ptrs[++count] = strdup("-nolisten");
- ptrs[++count] = strdup("tcp");
-
- ptrs[++count] = strdup("-noreset");
-
- opt = strtok(addn_xopts, " ");
- while (opt) {
- dprintf("adding xopt: \"%s\"", opt);
- ptrs[++count] = strdup(opt);
- opt = strtok(NULL, " ");
- }
- ptrs[++count] = vt;
-
- for (i = 0; i <= count; i++) {
- strncat(all, ptrs[i], PATH_MAX - strlen(all) - 1);
- if (i < count)
- strncat(all, " ", PATH_MAX - strlen(all) - 1);
- }
- lprintf("starting X server with: \"%s\"", all);
-
- execv(ptrs[0], ptrs);
-
- d_out();
-
- exit(EXIT_FAILURE);
-}
-
-/*
- * The X server will send us a SIGUSR1 when it's ready to serve clients,
- * wait for this.
- */
-void wait_for_X_signal(void)
-{
- struct timespec tv;
-
- d_in();
-
- clock_gettime(CLOCK_REALTIME, &tv);
- tv.tv_sec += 10;
-
- pthread_mutex_lock(&notify_mutex);
- pthread_cond_timedwait(&notify_condition, &notify_mutex, &tv);
- pthread_mutex_unlock(&notify_mutex);
-
- d_out();
-}
-
-void wait_for_X_exit(void)
-{
- int ret;
- int status;
-
- d_in();
-
- while (!exiting) {
- ret = waitpid(-1, &status, 0);
-
- if (WIFEXITED(status))
- lprintf("process %d exited with exit code %d",
- ret, WEXITSTATUS(status));
- if (WIFSIGNALED(status))
- lprintf("process %d was killed by signal %d",
- ret, WTERMSIG(status));
- if (WIFCONTINUED(status))
- lprintf("process %d continued", ret);
-
- if (ret == xpid) {
- lprintf("Xorg[%d] exited, cleaning up", ret);
- break;
- }
- if (ret == session_pid) {
- lprintf("Session process [%d] exited, cleaning up",
- ret);
- kill(xpid, SIGTERM);
- }
- }
-
- d_out();
-}
-
-void set_text_mode(void)
-{
- int fd;
-
- d_in();
-
- fd = open(displaydev, O_RDWR);
-
- if (fd < 0) {
- lprintf("Unable to open /dev/console, using stdin");
- fd = 0;
- }
- ioctl(fd, KDSETMODE, KD_TEXT);
- if (fd != 0)
- close(fd);
-
- d_out();
-}
diff --git a/user-session.service.in b/user-session.service.in
deleted file mode 100644
index 5238937..0000000
--- a/user-session.service.in
+++ /dev/null
@@ -1,17 +0,0 @@
-
-#
-# Minimal user session launcher for systemd.
-#
-
-[Unit]
-Description=User Session launcher
-Wants=syslog.target dbus.service
-
-[Service]
-ExecStart=@prefix@/bin/user-session
-Restart=always
-RestartSec=10
-
-[Install]
-Alias=display-manager.service
-WantedBy=graphical.target
diff --git a/xorg.service.in b/xorg.service.in
index 3efac12..c04e0c8 100644
--- a/xorg.service.in
+++ b/xorg.service.in
@@ -3,11 +3,21 @@
# Minimal Xorg service file - launches Xorg as a service unit
#
+# The Xorg launch helper forks, launches Xorg and waits for Xorg to
+# accept incoming connections to $DISPLAY, and then exits. This
+# guarantees that services that require access to $DISPLAY during the
+# session don't start too early.
+#
+# If you implement a service that requires access to $DISPLAY, your
+# service unit file needs to include 'After=xorg.target'.
+
[Unit]
Description=Xorg server launch helper
Wants=syslog.target dbus.service
+Before=xorg.target
[Service]
+Type=forking
ExecStart=@prefix@/bin/xorg-launch-helper
Restart=always
RestartSec=10