#!/usr/bin/perl # Copyright (c) 1996 SuSE GmbH Nuernberg, Germany. All rights reserved. # # Author: Marcus Schaefer , 2000 # xc.pl configuration level 2 after sax startup level 1 (init) # # CVS ID: # -------- # Status: Up-to-date # use lib '/usr/share/sax/modules'; use strict; use Env; use FileHandle; use CreateSections; use CheckServer; use ParseConfig; use Getopt::Long; use Storable; use XFree; #========================================== # Globals #------------------------------------------ my %var; # hold all the configuration parameters my %spec; # hold specifications for xc.pl my $EnableAutoConf; # option variable: enable auto config my $YaSTMode; # called from YaST2 my $StartWithSystemConfig; # option start with system config my $EnableXF86AutoMode; # option variable: enable auto modeline my $DialogToStartWith; # dialog to start with (xapi option) my $Display; # option variable: set Display my $TmpDir; # secure dir name my %tune; # tune hash for changed mode timings my $logHandle; # log file handle my $FullScreen; # full screen mode my $NoCheckPacs; # do not check package requirements my $NoIntro; # prevent intro appearance #========================================== # Call main... #------------------------------------------ main(); #========================================== # main #------------------------------------------ sub main { # ... # This function will open the configuration hash (registry) # created by init.pl and will create configuration suggestion # from this data. If there is no X-Server running start # my own X-Server otherwhise try to access the running one. # The last step is to run the GUI (xapi) on the server # --- #========================================== # Initialize xc options and spec hash #------------------------------------------ init(); #========================================== # Open configuration hash... #------------------------------------------ if ((prepare()) == -1) { print "xc: level 2... abort\n"; Exit(0); } #========================================== # Open LOG file handler... #------------------------------------------ $logHandle = OpenLog(); #========================================== # Create config suggestion #------------------------------------------ my @part0; # header my @part1; # Files section my @part2; # Module section my @part3; # ServerFlags section my @part4; # InputDevice sections my @part5; # Monitor sections my @part6; # Modes sections my @part7; # Device section my @part8; # Screen section my @part9; # ServerLayout section my @part10; # DRI section my @part11; # Extensions section @part0 = CreateHeaderSection (); @part1 = CreateFilesSection (\%var); @part2 = CreateModuleSection (\%var); @part3 = CreateServerFlagsSection (\%var); @part4 = CreateInputDeviceSection (\%var); if (defined $EnableXF86AutoMode) { @part5 = CreateMonitorSection (\%var,"yes"); } else { @part5 = CreateMonitorSection (\%var,"no"); @part6 = CreateModesSection (\%var,"no"); } @part7 = CreateDeviceSection (\%var); @part8 = CreateScreenSection (\%var); @part9 = CreateServerLayoutSection (\%var); @part10 = CreateDRISection (); @part11 = CreateExtensionsSection (\%var); #========================================== # Write preliminary config file #------------------------------------------ open (HANDLE,">$spec{AutoConf}"); print HANDLE @part0; print HANDLE "\n"; print HANDLE @part1; print HANDLE "\n"; print HANDLE @part2; print HANDLE "\n"; print HANDLE @part3; print HANDLE "\n"; print HANDLE @part4; print HANDLE "\n"; print HANDLE @part5; print HANDLE "\n"; print HANDLE @part6; print HANDLE "\n"; print HANDLE @part7; print HANDLE "\n"; print HANDLE @part8; print HANDLE "\n"; print HANDLE @part9; print HANDLE "\n"; print HANDLE @part10; print HANDLE "\n"; print HANDLE @part11; print HANDLE "\n"; close HANDLE; #========================================== # Write automatic config file and exit #------------------------------------------ if (defined $EnableAutoConf) { # /.../ # Auto configuration is enabled. This will save the auto # detected configuration file as final config file # --- my $final = LinkConfiguration(); print "SaX: Automatic configuration is done\n"; print "SaX: The file $final has been written\n"; CleanTmp(); Exit(0); } #========================================== # Check display server status #------------------------------------------ my $disp = ":0.0"; my $haveServer = 0; my @displayStatus = (); my @xpid = GetPids(); if (@xpid > 0) { #============================================ # check on local system according to pid's #-------------------------------------------- @displayStatus = GetDisplay (@xpid,$spec{Corner}); $disp = $displayStatus[0]; if ($displayStatus[1] eq "grant") { $haveServer = 1; } } else { #============================================ # check for remote access, x11 forward #-------------------------------------------- @displayStatus = X11ForwardEnabled(); if ($displayStatus[1] eq "grant") { $disp = $displayStatus[0]; $haveServer = 1; } } #========================================== # Apply log message about display status #------------------------------------------ Logger ("Startup...",$logHandle); if ($haveServer) { print "SaX: X-Server: $displayStatus[0] -> $displayStatus[1]\n"; Logger ("Startup on already running Server: $displayStatus[0] -> $displayStatus[1]", $logHandle ); } else { Logger ("Startup on new Server: <$disp>", $logHandle ); Logger ($spec{AutoConf}, $logHandle ); } #========================================== # Start new X-Server if needed #------------------------------------------ $spec{haveServer} = $haveServer; if ($haveServer == 0) { my $vt = GetVirtualTerminal(); my $XLoader = "$spec{X} $spec{Xmsg} -br -xf86config $spec{AutoConf}"; my $XFlags = "-allowMouseOpenFail -verbose 10 +accessx $vt"; my $XDisp = $disp; if ($disp =~ /(:.*)\./) { $XDisp = $1; } system("$XLoader $XFlags $XDisp >$spec{XpidFile}"); if (! open(FD,"$spec{XpidFile}")) { die "xc: could not open file: $spec{XpidFile}"; } while () { $spec{Xpid} = $_; } close(FD); unlink($spec{XpidFile}); #========================================== # save terminal settings to /var/log/xvt #------------------------------------------ my $terminal = 7; my $tty = Getty(); unlink($spec{XTerminal}); open (FD,">$spec{XTerminal}"); print FD "TTyX:$terminal\n"; print FD "TTyT:$tty\n"; close(FD); #========================================== # Check if the server starts up correctly #------------------------------------------ if (CheckPID($spec{Xpid}) != 0) { #========================================== # check for missing packages #------------------------------------------ my $install = ""; my $data = qx($spec{Sysp} -q 3d); if ($data =~ /Card3D0.*Install.*:(.*)\n.*/) { $install = $1; $install =~ s/ +//g; } if ($install ne "") { print "xc: missing base package:\n"; print " please install the following package(s):\n"; print "\n"; print " $install\n"; print "\n"; print "xc: abort...\n"; } else { #========================================== # Server startup failed... abort #------------------------------------------ print "\n"; print "xc: sorry could not start configuration server\n"; print "xc: for details refer to the log file:\n"; print "\n"; print " $spec{LogFile}\n"; print "\n"; print "xc: abort...\n"; } Logger($spec{Xmsg},$logHandle); unlink($spec{Xmsg}); Exit(0); } } #========================================== # prepare the options passed to xapi (GUI) #------------------------------------------ my @parent = getParentName(); my $apiopt = "--middle"; #======================================= # Check if we are called from YaST2 #--------------------------------------- if (defined $YaSTMode) { $apiopt = "--yast"; } #======================================= # Check if we are called from SaX2 #--------------------------------------- if (($haveServer) && ($parent[0] eq "sax")) { $apiopt = ""; } #======================================= # In case of own server; check size #--------------------------------------- if ($haveServer == 0) { $apiopt .= " --sizecheck"; } #======================================= # Check for package check flag #--------------------------------------- if (! defined $NoCheckPacs) { system ("$spec{Xapi} $apiopt --checkpacs -display $disp"); } #======================================= # Check for fullscreen mode #--------------------------------------- if (defined $FullScreen) { $apiopt = $apiopt." --fullscreen"; } #========================================== # Apply log message about server status #------------------------------------------ if ($haveServer == 0) { my $glxinfo = qx (/usr/X11R6/bin/glxinfo -display $disp); Logger ($spec{Xmsg},$logHandle); Logger ("GLX Info:\n$glxinfo",$logHandle); unlink ($spec{Xmsg}); } #======================================= # Show the intro message #--------------------------------------- my $exit = 2; if (defined $NoIntro) { #======================================= # Don't want to see a intro message #--------------------------------------- $exit = 1; } else { if ($haveServer == 0) { #======================================= # Call intro and save exit code #--------------------------------------- system ("$spec{Xapi} $apiopt --info -display $disp"); $exit = $? >> 8; #======================================= # Get information about our own server #--------------------------------------- my @xpid = GetPids(); if (@xpid > 0) { @displayStatus = GetDisplay (@xpid,$spec{Corner}); $disp = $displayStatus[0]; if ($displayStatus[1] ne "grant") { $exit = 2; } } else { $exit = 2; } } else { #======================================= # There is already a server to access #--------------------------------------- $exit = 1; } } #======================================= # Handle the exit code from the intro #--------------------------------------- my $exitCode = 0; if ($exit == 1) { #======================================= # (1) Run the GUI (xapi)... #--------------------------------------- if (open (OPT,">$spec{StartOptions}")) { print OPT $apiopt; close OPT; } if (defined $DialogToStartWith) { $apiopt = "$apiopt -O $DialogToStartWith"; } if ($haveServer == 0) { if ((defined $StartWithSystemConfig) && (HeaderOK())) { print "SaX: importing current configuration...\n"; system ("$spec{Xapi} $apiopt -display $disp"); } else { print "SaX: using cache data...\n"; system ("$spec{Xapi} $apiopt --mode auto -display $disp"); } } else { if ((-f $spec{HWFlag}) || (! HeaderOK())) { print "SaX: using cache data...\n"; system ("$spec{Xapi} $apiopt --mode auto -display $disp"); } else { print "SaX: importing current configuration...\n"; system ("$spec{Xapi} $apiopt -display $disp"); } } $exitCode = $? >> 8; } elsif ($exit == 0) { #======================================= # (0) Save the configuration file #--------------------------------------- # /.../ # recreate Module Section because some modues not used # for initial configuration are needed for final # configuration # ---- @part2 = CreateModuleSection(\%var); open (HANDLE,">$spec{AutoConf}"); print HANDLE @part0; print HANDLE "\n"; print HANDLE @part1; print HANDLE "\n"; print HANDLE @part2; print HANDLE "\n"; print HANDLE @part3; print HANDLE "\n"; print HANDLE @part4; print HANDLE "\n"; print HANDLE @part5; print HANDLE "\n"; print HANDLE @part6; print HANDLE "\n"; print HANDLE @part7; print HANDLE "\n"; print HANDLE @part8; print HANDLE "\n"; print HANDLE @part9; print HANDLE "\n"; print HANDLE @part10; print HANDLE "\n"; close(HANDLE); LinkConfiguration(); $exitCode = 1; } #======================================= # In case of own server; Kill it now #--------------------------------------- if ($haveServer == 0) { Kill ($spec{Xpid}); } #======================================= # Clean temp dir and exit #--------------------------------------- CleanTmp(); Exit ($exitCode); } #========================================== # CreateSecureDir #------------------------------------------ sub CreateSecureDir { # ... # this function create a secure tmp directory # and return the name of the directory # --- my $saxdir = "sax2-$$"; my $result = mkdir("/tmp/$saxdir",0700); if ($result == 0) { print "xc: could not create tmp dir... abort\n"; Exit(0); } return($saxdir); } #========================================== # CleanTmp #------------------------------------------ sub CleanTmp { # ... # this function send a signal to the process # itself and forces removement of the tmp dir # --- kill (15,$$); } #----[ init ]----# sub init { # ... # init spec hash and test for root privileges # --- #========================================== # Create secure directory #------------------------------------------ $TmpDir = CreateSecureDir(); $SIG{HUP} = "HandleTmpSignal"; $SIG{INT} = "HandleTmpSignal"; $SIG{QUIT} = "HandleTmpSignal"; $SIG{ABRT} = "HandleTmpSignal"; $SIG{SEGV} = "HandleTmpSignal"; $SIG{PIPE} = "HandleTmpSignal"; $SIG{TERM} = "HandleTmpSignal"; $spec{Sysp} = "/usr/sbin/sysp"; $spec{DbmFile} = "/var/cache/sax/files/config"; $spec{HWFlag} = "/var/cache/sax/files/hardware.chg"; $spec{LogFile} = "/var/log/SaX.log"; $spec{XpidFile} = "/var/log/SaX.pid"; $spec{AutoConf} = "/tmp/$TmpDir/xorg.conf"; $spec{Xmsg} = "/var/log/xlog"; $spec{X} = "/usr/sbin/xw"; $spec{Xapi} = "/usr/sbin/xapi"; $spec{Intro} = "/usr/share/sax/intro.pl"; $spec{Corner} = "/usr/sbin/corner"; $spec{XTerminal} = "/var/log/xvt"; $spec{StartOptions}= "/var/cache/sax/files/xapi.opt"; #========================================== # Get options... #------------------------------------------ undef ($spec{Xpid}); undef ($YaSTMode); undef ($EnableAutoConf); undef ($Display); undef ($FullScreen); undef ($NoCheckPacs); undef ($EnableXF86AutoMode); undef ($StartWithSystemConfig); undef ($DialogToStartWith); undef (%tune); my $result = GetOptions( "auto|a" => \$EnableAutoConf, "yast|y" => \$YaSTMode, "xmode|x" => \$EnableXF86AutoMode, "sysconfig|s" => \$StartWithSystemConfig, "fullscreen|f" => \$FullScreen, "nocheckpacs|p" => \$NoCheckPacs, "nointro|n" => \$NoIntro, "dialog|O=s" => \$DialogToStartWith, "help|h" => \&usage, "<>" => \&usage ); if ( $result != 1 ) { usage(); } my $api = $spec{Xapi}; if ( ! -f $api ) { $EnableAutoConf = ""; } #========================================== # Test for root privileges #------------------------------------------ my $user = qx (whoami); if ($user !~ /root/i) { print "xc: only root can do this\n"; exit(0); } } #========================================== # prepare #------------------------------------------ sub prepare { # ... # read saved data dictionary hash from file # import registry information # --- my $hashref; if (! -s $spec{DbmFile}) { print "xc: could not open tree: $spec{DbmFile}\n"; return -1; } eval { $hashref = retrieve($spec{DbmFile}); }; if (! defined $hashref) { print "xc: could not open tree: $spec{DbmFile}\n"; return -1; } %var = %{$hashref}; return 0; } #========================================== # save #------------------------------------------ sub save { # ... # save hash data as file $spec{DbmFile} # --- unlink($spec{DbmFile}); if(!store(\%var,$spec{DbmFile})) { print "init: could not create tree: $spec{DbmFile}\n"; return -1; } return 0; } #========================================== # HandleTmpSignal #------------------------------------------ sub HandleTmpSignal { # ... # signal function to remove tmp stuff # --- qx (rm -rf /tmp/$TmpDir); qx (rm -rf /tmp/sysp-*); } #========================================== # Logger #------------------------------------------ sub Logger { # ... # Append log file data to LOG handler... # --- my $data = $_[0]; my $handle = $_[1]; my $date = qx ( LANG=POSIX /bin/date "+%d-%h %H:%M:%S" ); $date =~ s/\n$//; if (-f $data) { #========================================== # got file for logging #------------------------------------------ print $handle "$date Logging File contents: $data [\n"; my $xf = new FileHandle; if ($xf->open("$data")) { while (my $line=<$xf>) { $line =~ s/^\n//; $line =~ s/\n$//; $line =~ s/^\t+//g; print $handle "\t$line\n"; } } print $handle "]\n"; $xf->close; } else { #========================================== # got string data for logging #------------------------------------------ print $handle "$date "; my $lineWrap = 0; $data =~ s/^\n//; $data =~ s/\n$//; if ($data =~ /\n+/) { $lineWrap = 1; } if ($lineWrap) { my @list = split ("\n",$data); my $topic = shift (@list); print $handle "[ $topic\n"; foreach (@list) { $_ =~ s/^\t+//g; print $handle "\t$_\n"; } print $handle "]\n"; } else { print $handle "$data\n"; } } } #========================================== # LinkConfiguration #------------------------------------------ sub LinkConfiguration { # ... # this function is called to copy the temporary config # file to /etc/X11/xorg.conf and create the symbolic # X links # --- my $final = "/etc/X11/xorg.conf"; my $save = "/etc/X11/xorg.conf.saxsave"; my $server = "/usr/X11R6/bin/XFree86"; if (! -f $server) { $server = "/usr/X11R6/bin/Xorg"; } if (-f $final) { qx (cp $final $save); } #========================================== # Save configuration to /etc/X11 #------------------------------------------ qx (cp $spec{AutoConf} $final); #========================================== # Create startup links #------------------------------------------ if (-f $server) { qx (rm -f /usr/X11R6/bin/X); qx (rm -f /var/X11R6/bin/X); qx (ln -s /var/X11R6/bin/X /usr/X11R6/bin/X); qx (ln -s $server /var/X11R6/bin/X); } unlink ( $spec{HWFlag} ); return ( $final ); } #========================================== # Exit #------------------------------------------ sub Exit { # ... # exit function wrapper which close the # LOG handler first... # --- my $code = $_[0]; CloseLog ($logHandle); qx (rm -rf $TmpDir); exit ($code); } #========================================== # Getty #------------------------------------------ sub Getty { # ... # look for the terminal ID and return it. Please # note this function has to return a number # --- my $tty; $tty = qx (tty | cut -f2 -dy); return($tty); } #========================================== # CheckPID #------------------------------------------ sub CheckPID { # ... # check if the given process id still exist in # the process table # --- my $pid = $_[0]; if ($pid eq "") { return 1; } sleep(2); qx (ps $pid); my $exit = $? >> 8; return $exit; } #========================================== # OpenLog #------------------------------------------ sub OpenLog { # ... # remove old auto configuration file and open a # new log file descriptor... # --- my $io; unlink ($spec{AutoConf}); $io = new FileHandle; if (! $io->open(">>$spec{LogFile}")) { die "xc: could not create LogFile: $spec{LogFile}"; } my $LOG = $io->fileno; open(STDERR,">&$LOG") || die "could not duplicate LOG on stderr"; binmode($io, ':unix'); return ($io); } #========================================== # CloseLog #------------------------------------------ sub CloseLog { # ... # close current log file descriptor... # --- my $io = $_[0]; if (defined $io) { $io->close; } } #========================================== # Kill #------------------------------------------ sub Kill { # ... # This function will try to kill a process with # signal 15 first and if it still exists with signal # number 9 to be sure it gets killed # --- my $pid = $_[0]; my $err; if ($pid eq "") { return; } $err = system("kill -15 $pid"); $err = $? >> 8; if ($err > 0) { Logger ("die hard on pid: $pid",$logHandle); system ("kill -9 $pid"); } } #========================================== # getParentName #------------------------------------------ sub getParentName { # ... # get the name of the parent process calling # this script # --- my @return; my $parent = getppid(); my $name = qx ( cat /proc/$parent/cmdline ); $name =~ /\/.*\/+(.*)/; my @list = split(/\./,$1); my $base = shift (@list); my $cmdline = qx ( cat /proc/$parent/cmdline ); chomp ($base); push(@return,$base); if ($cmdline =~ /.*-font(.*)-iso10646-1/) { push(@return,"-fn $1-iso10646-1"); } return ( @return ); } #========================================== # HeaderOK #------------------------------------------ sub HeaderOK { # ... # check if the header of the config file has been created # from SaX2/ISaX... otherwhise this file shouldn't be # read in # --- my $file = "/etc/X11/xorg.conf"; my $hunk = "SaX generated X.* config file"; my $msg1 = "SaX: header check failed !\n"; my $msg2 = "SaX: will not import $file\n"; if (! -f $file) { print $msg1.$msg2; return 0; } if (! open (FD,$file)) { print $msg1.$msg2; return 0; } while () { if ($_ =~ /$hunk/) { close FD; return 1; } } close FD; print $msg1.$msg2; return 0; } #========================================== # usage #------------------------------------------ sub usage { # ... # usage message for calling xc.pl # --- print "Linux SaX Version 7.1 level (xc) (2005-09-26)\n"; print "(C) Copyright 2005 - SUSE LINUX Products GmbH\n"; print "\n"; print "usage: xc [ options ]\n"; print "options:\n"; print "[ -a | --auto ]\n"; print " enable automatic configuration\n"; print "\n"; print "[ -x | --xmode ]\n"; print " do not use sax calculated Modelines,\n"; print " use the server generated once instead\n"; print "\n"; print "[ -s | --sysconfig ]\n"; print " this option will only take effect if xc\n"; print " has to start its own X-Server. It will than\n"; print " read the system installed config file\n"; print " instead of the HW detection data\n" ; print "[ -y | --yast ]\n"; print "\n"; print " start in yast mode which passed the option\n"; print " named --yast to the xapi binary\n"; print "\n"; print "[ -f | --fullscreen ]\n"; print " start the GUI in fullscreen mode\n"; print "\n"; print "[ -O | --dialog ]\n"; print " pass the option --dialog to the xapi binary\n"; print "\n"; print "[ -n | --nointro ]\n"; print " skip the greeting message\n"; print "\n"; print "[ -p | --nocheckpacs ]\n"; print " skip the check for required packages\n"; print "\n"; print "[ -h | --help ]\n"; print " show this message\n"; print "--\n"; Exit(0); }