cdm/src/cdm
2013-04-03 09:15:22 -07:00

222 lines
7.4 KiB
Bash
Executable File

#!/bin/bash
#
# CDM: The Console Display Manager
#
# Copyright (C) 2009-2012, Daniel J Griffiths <dgriffiths@ghost1227.com>
# 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; }
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 /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}
[[ -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}))"
binargs="$(cut -s -f 2- -d ' ' <<< ${execkey})"
# If which fails to return valid path, skip to next .desktop file.
if [ -z $binitem ]; then continue; fi
if [ -n $binargs ]; then binitem+=" ${binargs}"; fi
binlist+=("${binitem}")
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; exitnormal
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)
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