From 398fb35d2d56a952ba244e6e811ab96e22797cc5 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 23 Apr 2012 10:51:22 -0700 Subject: [PATCH] Bulk of the xorg-launch-helper checkin. --- .gitignore | 4 +- Makefile.am | 4 +- configure.ac | 27 ++--- src/Makefile.am | 5 +- src/lib.c | 60 ---------- src/main.c | 196 +++++++++++++++--------------- src/pam.c | 130 -------------------- src/user-session.h | 60 ---------- src/user.c | 224 ---------------------------------- src/xserver.c | 311 ------------------------------------------------ user-session.service.in | 17 --- xorg.service.in | 10 ++ 12 files changed, 124 insertions(+), 924 deletions(-) delete mode 100644 src/lib.c delete mode 100644 src/pam.c delete mode 100644 src/user-session.h delete mode 100644 src/user.c delete mode 100644 src/xserver.c delete mode 100644 user-session.service.in 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= 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 - * Arjan van de Ven - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#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 +#include +#include +#include +#include #include #include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include -#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(¬ify_mutex); + pthread_cond_signal(¬ify_condition); + pthread_mutex_unlock(¬ify_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(¬ify_mutex); + pthread_cond_timedwait(¬ify_condition, ¬ify_mutex, &tv); + pthread_mutex_unlock(¬ify_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 - * Arjan van de Ven - * Michael Meeks - * - * 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 -#include -#include -#include -#include -#include - -#include - -#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 -#include -#include - -#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 - * Arjan van de Ven - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "user-session.h" - -#include - -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 - * Arjan van de Ven - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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(¬ify_mutex); - pthread_cond_signal(¬ify_condition); - pthread_mutex_unlock(¬ify_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(¬ify_mutex); - pthread_cond_timedwait(¬ify_condition, ¬ify_mutex, &tv); - pthread_mutex_unlock(¬ify_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 -- 2.7.4