#!/bin/bash # # CDM: The Console Display Manager # # Copyright (C) 2009-2012, Daniel J Griffiths # Thanks to: # # Andrwe beta-testing and submitting the fix for the all # important X incrementation function # brisbin33 code cleanup # tigrmesh finding a critical issue with the gnome-session handler # Profjim several incredibly useful patches # lambchops468 consolekit and hibernation patches # CasperVector Massive rearchitecturing and code sanitation # # 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. name=$(basename "$0") longname='Console Display Manager' ver='0.6' trap '' SIGINT SIGTSTP # Helper functions. warn() { (printf ' \033[01;33m*\033[00m '; echo "$name: $*") > /dev/stderr; } error() { (printf ' \033[01;31m*\033[00m '; echo "$name: $*") > /dev/stderr; } exitnormal() { exit 0; } exiterror() { sleep 1; exit 1; } exitcancel() { exit 2; } yesno() { [ -z "$1" ] && return 1 eval value=\$${1} case "$value" in [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) return 0;; [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) return 1;; *) warn "invalid value for \`$1'; falling back to \`no' for now.";; esac } # Source cdm configurations. if [[ -n "$1" ]]; then if [[ -f "$1" ]] then source "$1" else error "config file \`$1' does not exist." exiterror fi elif [[ -f "$HOME/.cdmrc" ]]; then source "$HOME/.cdmrc" elif [[ -f "$XDG_CONFIG_HOME/cdm/cdmrc" ]]; then source "$XDG_CONFIG_HOME/cdm/cdmrc" elif [[ -f /etc/cdmrc ]]; then source /etc/cdmrc fi # Default options. dialogrc=${dialogrc:-} countfrom=${countfrom:-0} display=${display:-0} xtty=${xtty:-7} locktty=${locktty:-no} consolekit=${consolekit:-yes} cktimeout=${cktimeout:-30} altstartx=${altstartx:-no} startxlog="${startxlog:-/dev/null}" [[ -z "${binlist[*]}" ]] && binlist=() [[ -z "${namelist[*]}" ]] && namelist=() [[ -z "${flaglist[*]}" ]] && flaglist=() [[ -z "${serverargs[*]}" ]] && serverargs=(-nolisten tcp) # Offer all available sessions in /etc/X11/Sessions, # if $binlist if not explicitly set in cdmrc. if [[ "${#binlist[@]}" == 0 && -d /etc/X11/Sessions ]]; then binlist=($(find /etc/X11/Sessions -maxdepth 1 -type f)) flaglist=($(sed 's/[[:digit:]]\+/X/g' <<< ${!binlist[@]})) namelist=(${binlist[@]##*/}) fi # If $binlist is not set in cdmrc or by files in /etc/X11/Sessions, # try .desktop files in /usr/share/xsessions/ . if [[ "${#binlist[@]}" == 0 && -d /usr/share/xsessions ]]; then desktopsessions=($(find /usr/share/xsessions/ -regex .\*.desktop)) #TODO: allow full quoting and expansion according to desktop entry spec: # http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables for ((count=0; count < ${#desktopsessions[@]}; count++)); do # TryExec key is there to determine if executable is present, # but as we are going to test the Exec key anyway, we ignore it. execkey=$(sed -n -e 's/^Exec=//p' <${desktopsessions[${count}]}) namekey=$(sed -n -e 's/^Name=//p' <${desktopsessions[${count}]}) if [[ -n ${execkey} && -n ${namekey} ]]; then # The .desktop files allow there Exec keys to use $PATH lookup. binitem="$(which $(cut -f 1 -d ' ' <<< ${execkey}))" # If which fails to return valid path, skip to next .desktop file. if [[ $? != 0 ]]; then continue; fi binlist+=("${binitem} $(cut -s -f 2- -d ' ' <<< ${execkey})") flaglist+=('X') namelist+=("${namekey}") fi done fi case "${#binlist[@]}" in 0) error "No programs found in cdm config file, /etc/X11/Sessions or /usr/share/xsessions." exiterror ;; 1) # No need to call dialog AND clear, only one possible program binindex=0 ;; *) menu=() for ((count = 0; count < ${#namelist[@]}; count++)); do menu=("${menu[@]}" "$((count+countfrom))" "${namelist[${count}]}") done binindex=$( DIALOGRC="$dialogrc" dialog --colors --stdout \ --backtitle "$longname v$ver" --ok-label ' Select ' \ --cancel-label ' Exit ' --menu 'Select session' 0 0 0 "${menu[@]}" ) if [[ $? != 0 ]]; then clear; exitcancel fi clear let binindex-=countfrom ;; esac # Run $bin according to its flag. bin=($(eval echo "${binlist[${binindex}]}")) case ${flaglist[$binindex]} in # *C*onsole programs. [Cc]) # If $bin is a login shell, it might `exec' cdm again, causing an endless # loop. To solve this problem, export $CDM_SPAWN when `exec'ing $bin and # only let the shell automatically `exec' cdm when $CDM_SPAWN is not set. # See also the example shell profile file shipped with the cdm package. # Also untrap SIGINT and SIGTSTP before spawning process: If this is not # done, any child process of any child (bash) shell will completely # ignore SIGINT, which is rather confusing, and cannot be undone. trap - SIGINT SIGTSTP CDM_SPAWN=$$ exec "${bin[@]}" ;; # *X* programs. [Xx]) # If X is already running and locktty=yes, activate it. if $(yesno locktty) && xdpyinfo -display ":$display.0" &> /dev/null; then chvt "$((display+xtty))" exitnormal fi # Get the first empty display. display=0 while ((display < 7)); do if dpyinfo=$(xdpyinfo -display ":$display.0" 2>&1 1>/dev/null) || # Display is in use by another user. [[ "$dpyinfo" == 'No protocol specified'* ]] || # Invalid MIT cookie. [[ "$dpyinfo" == 'Invalid MIT'* ]] then let display+=1 else break fi done # Support for running X in current tty. if [[ $xtty == 'keep' ]]; then vt="$(tty)" if [[ "$vt" != '/dev/tty'* ]]; then error 'invalid TTY.' exiterror fi vt="${vt#/dev/tty}" else vt="$((xtty+display))" fi serverargs=(":${display}" "${serverargs[@]}" "vt$vt") $(yesno consolekit) && launchflags=(-c -t "$cktimeout") $(yesno altstartx) && launchflags=("${launchflags[@]}" --altstartx) launchflags=("${launchflags[@]}" --startxlog "$startxlog") if cdm-xlaunch "${launchflags[@]}" -- "${bin[@]}" -- "${serverargs[@]}" then exitnormal else warn "\`cdm-xlaunch' exited unsuccessfully." exiterror fi ;; *) error "unknown flag: \`${flaglist[$binindex]}'." exiterror ;; esac # vim:ts=4:sw=4:et