以下看看/usr/bin/startx这个脚本。
#!/bin/bash # # This is just a sample implementation of a slightly less primitive # interface than xinit. It looks for user .xinitrc and .xserverrc # files, then system xinitrc and xserverrc files, else lets xinit choose # its default. The system xinitrc should probably do things like check # for .Xresources files and merge them in, startup up a window manager, # and pop a clock and serveral xterms. # # Site administrators are STRONGLY urged to write nicer versions. # unset DBUS_SESSION_BUS_ADDRESS unset SESSION_MANAGER userclientrc=$HOME/.xinitrc # 用户的client定义文件 sysclientrc=/etc/X11/xinit/xinitrc # 系统的client定义文件 userserverrc=$HOME/.xserverrc # 用户的server定义文件 sysserverrc=/etc/X11/xinit/xserverrc # 系统的server定义文件 defaultclient=xterm # 默认的client程序 defaultserver=/usr/bin/X # 默认的server程序 defaultclientargs="" # 以下定义了client和server的參数变量 defaultserverargs="" defaultdisplay=":0" clientargs="" serverargs="" enable_xauth=1 # 參数解析:将whoseargs变量赋值为字符串“client”,表示当前解析的指定client的參数 whoseargs="client" while [ x"$1" != x ]; do # 若第一个參数为空,则直接退出循环 case "$1" in # 须要单引號‘‘以避免cpp把"/*"当作凝视 /‘‘*|\./‘‘*) # 假设$1是/*或者./*形式 (xinit程序要求其指定的client程序和server程序必须以/或./开头, # 否则会被视为client程序和server程序本身的options參数,见man xinit) if [ "$whoseargs" = "client" ]; then # 解析client程序的參数 if [ x"$client" = x ] && [ x"$clientargs" = x ]; then client="$1" # 解析出用户指定的client程序 else clientargs="$clientargs $1" #解析出client程序的options參数 fi else if [ x"$server" = x ] && [ x"$serverargs" = x ]; then server="$1" # 解析出用户指定的X server程序 else serverargs="$serverargs $1" # 解析出X server的options參数 fi fi ;; --) # 遇到“- -”就解析server whoseargs="server" ;; *) if [ "$whoseargs" = "client" ]; then clientargs="$clientargs $1" else # 解析[display]參数,屏幕编号[display]必须为第一个给server程序的參数,以:x的形式(x为数字) if [ x"$serverargs" = x ] && expr "$1" : ‘:[0-9][0-9]*> /dev/null 2>&1; then display="$1" else serverargs="$serverargs $1" # 解析[display]以外的參数 fi fi ;; esac shift # 全部參数左移一次 done # 处理client參数 if [ x"$client" = x ]; then # 假设用户没有指定X client,则使用默认的X client即xterm client=$defaultclient # 假设没有client的选项參数,则用rc文件取代 if [ x"$clientargs" = x ]; then if [ -f "$userclientrc" ]; then client=$userclientrc elif [ -f "$sysclientrc" ]; then client=$sysclientrc fi clientargs=$defaultclientargs fi fi # 处理server參数 if [ x"$server" = x ]; then # 假设用户没有指定X server,则使用默认的X server即X server=$defaultserver # 假设没有server的选项參数或display參数,使用默认值 if [ x"$serverargs" = x -a x"$display" = x ]; then # 为了兼容性的考虑,假设没有server的命令行參数,仅仅使用xserverrc文件 if [ -f "$userserverrc" ]; then server=$userserverrc elif [ -f "$sysserverrc" ]; then server=$sysserverrc fi serverargs=$defaultserverargs display=$defaultdisplay fi fi if [ x"$enable_xauth" = x1 ] ; then if [ x"$XAUTHORITY" = x ]; then # 假设环境变量XAUTHORITY为空,就设定为$HOME/.Xauthority XAUTHORITY=$HOME/.Xauthority export XAUTHORITY fi removelist= # 设置本机的默认Xauth信息 # 检查GNU主机名,假设hostname –version中不包括GNU 就将hostname变量设定为命令hostname –f返回的字符串 if hostname --version > /dev/null 2>&1; then if [ -z "`hostname --version 2>&1 | grep GNU`" ]; then hostname=`hostname -f` fi fi if [ -z "$hostname" ]; then hostname=`hostname` fi authdisplay=${display:-:0} mcookie=`/usr/bin/mcookie` if test x"$mcookie" = x; then echo "Couldn‘t create cookie" exit 1 fi dummy=0 # 为server创建带有auth信息的文件,假设为屏幕编号为‘:0‘ xserverauthfile=`mktemp --tmpdir serverauth.XXXXXXXXXX` trap "rm -f ‘$xserverauthfile‘" HUP INT QUIT ILL TRAP KILL BUS TERM xauth -q -f "$xserverauthfile" << EOF add :$dummy . $mcookie EOF serverargs=${serverargs}" -auth "${xserverauthfile} # now add the same credentials to the client authority file # if ‘$displayname‘ already exists do not overwrite it as another # server man need it. Add them to the ‘$xserverauthfile‘ instead. for displayname in $authdisplay $hostname$authdisplay; do authcookie=`xauth list "$displayname" | sed -n "s/.*$displayname[[:space:]*].*[[:space:]*]//p"` 2>/dev/null; if [ "z${authcookie}" = "z" ] ; then xauth -q << EOF add $displayname . $mcookie EOF removelist="$displayname $removelist" else dummy=$(($dummy+1)); xauth -q -f "$xserverauthfile" << EOF add :$dummy . $authcookie EOF fi done fi # #以下的语句通过xinit启动X server和Clients,把处理的參数传给它 xinit "$client" $clientargs -- "$server" $display $serverargs retval=$? if [ x"$enable_xauth" = x1 ] ; then if [ x"$removelist" != x ]; then xauth remove $removelist fi if [ x"$xserverauthfile" != x ]; then rm -f "$xserverauthfile" fi fi exit $retval
以上即为X Window System的启动过程,startx仅仅是负责一些參数传递,真正的X启动由xinit实现。我们能够知道,startx将会先解析用户的參数,假设该用户指定了该參数(即解析结果不为空),那么startx就会以该參数来启动xinit,否则就会解析(与其说是解析,还不如说是运行)$HOME文件夹下的rc文件,假设该文件不存在,就会解析系统文件夹下(/etc/X11/xinit/)的rc文件,假设这个文件也不存在,那startx就将以默认的client(xterm)和server(/usr/bin/X)为參数来启动xinit。比如,能够在用户文件夹下构造.xinitrc(即X
client)和.xserverrc(即X server)文件。在.xserverrc里写入/usr/bin/X11/X :1。.xinitrc里写入/usr/bin/X11/xeyes -display localhost:1。这就是最简单的X server+ X client了,仅仅只是把屏幕编号从默认的0改为了1。
到眼下为止,我们还不知道只在终端输入startx是怎么样启动gnome桌面的,gnome当然属于X client了。通过对startx的分析可知,startx主要有三种启动方式:
(1)一种是自己指定要启动的client和server, 比如:startx /usr/bin/xclock -- /usr/bin/X :0;
(2)一种是通过在$HOME下新建.xinitrc文件来指定要启动的多个client和.xserverrc来指定要启动的server(注意:这两个文件本来是不存在的);
(3)另一种是直接输入startx而不指定參数,这也就是我们启动gnome桌面的方法。
在第(3)中启动方法中,我们能够知道,startx脚本会先去看系统文件夹(/etc/X11/xinit/)下的rc文件是否存在,假设不存在就会用默认的xterm和/usr/bin/X来启动xinit。显然,startx启动的不是xterm,而是gnome桌面,因此gnome的启动是通过系统文件/etc/X11/xinit/xinitrc来指定的。在“Linux init程序分析”中具体介绍过的gnome的启动。这里以Ubuntu为例,/etc/X11/xinit/xinitrc文件里仅仅包括了. /etc/X11/Xsession一句话,因此gnome是通过Xsession脚本启动的(在Fedora中则是直接用xinitrc来启动gnome)。以下是Xsession文件:
#!/bin/sh # 注意该脚本用的是Bourne shell解析的 # # /etc/X11/Xsession # # global Xsession file -- used by display managers and xinit (startx) # $Id: Xsession 967 2005-12-27 07:20:55Z dnusinow $ set -e # 打开errexit选项,该选项表示假设以下有命令返回的状态非0,则退出程序 PROGNAME=Xsession # 以下4个是信息输出函数,能够无论 message () { # pretty-print messages of arbitrary length; use xmessage if it # is available and $DISPLAY is set MESSAGE="$PROGNAME: $*" echo "$MESSAGE" | fold -s -w ${COLUMNS:-80} >&2 if [ -n "$DISPLAY" ] && which xmessage > /dev/null 2>&1; then echo "$MESSAGE" | fold -s -w ${COLUMNS:-80} | xmessage -center -file - fi } message_nonl () { # pretty-print messages of arbitrary length (no trailing newline); use # xmessage if it is available and $DISPLAY is set MESSAGE="$PROGNAME: $*" echo -n "$MESSAGE" | fold -s -w ${COLUMNS:-80} >&2; if [ -n "$DISPLAY" ] && which xmessage > /dev/null 2>&1; then echo -n "$MESSAGE" | fold -s -w ${COLUMNS:-80} | xmessage -center -file - fi } errormsg () { # exit script with error message "$*" exit 1 } internal_errormsg () { # exit script with error; essentially a "THIS SHOULD NEVER HAPPEN" message # One big call to message() for the sake of xmessage; if we had two then # the user would have dismissed the error we want reported before seeing the # request to report it. errormsg "$*" "Please report the installed version of the \"x11-common\"" "package and the complete text of this error message to" "<debian-x@lists.debian.org>." } # 初始化被全部session脚本使用的变量 OPTIONFILE=/etc/X11/Xsession.options SYSRESOURCES=/etc/X11/Xresources USRRESOURCES=$HOME/.Xresources SYSSESSIONDIR=/etc/X11/Xsession.d USERXSESSION=$HOME/.xsession USERXSESSIONRC=$HOME/.xsessionrc ALTUSERXSESSION=$HOME/.Xsession ERRFILE=$HOME/.xsession-errors # 尝试创建一个error文件,假设不能创建则退出 if (umask 077 && touch "$ERRFILE") 2> /dev/null && [ -w "$ERRFILE" ] && [ ! -L "$ERRFILE" ]; then chmod 600 "$ERRFILE" elif ERRFILE=$(tempfile 2> /dev/null); then if ! ln -sf "$ERRFILE" "${TMPDIR:=/tmp}/xsession-$USER"; then message "warning: unable to symlink \"$TMPDIR/xsession-$USER\" to" "\"$ERRFILE\"; look for session log/errors in" "\"$TMPDIR/xsession-$USER\"." fi else errormsg "unable to create X session log/error file; aborting." fi # 截短ERRFILE,假设它太大了,以避免硬盘空间的DoS攻击 if [ "`stat -c%s \"$ERRFILE\"`" -gt 500000 ]; then T=`mktemp -p "$HOME"` tail -c 500000 "$ERRFILE" > "$T" && mv -f "$T" "$ERRFILE" || rm -f "$T" fi exec >>"$ERRFILE" 2>&1 echo "$PROGNAME: X session started for $LOGNAME at $(date)" # 理智的检查:#假设/etc/X11/Xsession.d不存在或不是一个文件夹则打印错误信息并退出 if [ ! -d "$SYSSESSIONDIR" ]; then errormsg "no \"$SYSSESSIONDIR\" directory found; aborting." fi # Attempt to create a file of non-zero length in /tmp; a full filesystem can # cause mysterious X session failures. We do not use touch, :, or test -w # because they won‘t actually create a file with contents. We also let standard # error from tempfile and echo go to the error file to aid the user in # determining what went wrong. WRITE_TEST=$(tempfile) if ! echo "*" >>"$WRITE_TEST"; then message "warning: unable to write to ${WRITE_TEST%/*}; X session may exit" "with an error" fi rm -f "$WRITE_TEST" # use run-parts to source every file in the session directory; we source # instead of executing so that the variables and functions defined above # are available to the scripts, and so that they can pass variables to each # other SESSIONFILES=$(run-parts --list $SYSSESSIONDIR) # 将/etc/X11/Xsession.d文件夹中的全部文件都读出,并存入SESSIONFILES变量中 if [ -n "$SESSIONFILES" ]; then set +e # 关闭errexit选项 for SESSIONFILE in $SESSIONFILES; do # 运行Xsession.d下的每个脚本 . $SESSIONFILE done set -e fi exit 0 # vim:set ai et sts=2 sw=2 tw=80:从以上的对Xsession脚本文件的分析,能够看出,Xsession脚本不过运行了/etc/X11/Xsession.d文件夹下的全部文件,每个文件名称都以数字开头,这些数字就表示了文件被运行的优先级,数字小的优先级高,run-parts会将数字小的排在前面,这样就能确保以上文件能按数字由小到大的顺序运行。基本的文件例如以下:
/usr/bin/startx --->xinit /etc/X11/xinit/xinitrc -- /etc/X11/xinit/xinitrc --->./etc/X11/Xsession --->/etc/X11/Xsession.d/ --->50x11-common_determine-startup --->/etc/X11/Xsession.options # 寻找相关配置选项 --->STARTUP=$HOME/.xsession # 假设有.xsession脚本,则设置成执行它 --->STARTUP=/usr/bin/x-session-manager # 假设没有.xsession脚本,则设置成执行x-session-manager --->/usr/bin/gnome-session # x-session-manager指向gnome-session程序 --->55gnome-session_gnomerc --->$HOME/.gnomerc # 选择了gnome-session,则执行$HOME/.gnomerc --->75dbus_dbus-launch # 启动dbus --->80im-switch # 设置输入法 --->99x11-common_start --->exec $STARTUP # 启动gnome会话,进入gnome桌面3、跨网络执行X Window System
X Window System介绍,布布扣,bubuko.com
原文:http://www.cnblogs.com/mfrbuaa/p/3866293.html