#!/usr/bin/perl # # sunray Xserver handler for gdm # use strict; use Sys::Syslog; use Data::Dumper; use Time::HiRes qw(sleep); use POSIX ":sys_wait_h"; my $XserversFile = '/var/opt/SUNWut/xconfig/Xservers'; my $UTsession = '/opt/SUNWut/lib/utdmsession'; my $XserversFileMtime = 0; my $xserversArgs = ' -dpi 75 -terminate -query localhost'; my %xservers; ## # log events to syslog sub logger { my $message = shift; openlog('utxd', 'cons,pid', 'user'); syslog('info', $message); closelog; } ## # sub sig_chld_handler { my $child; while (($child = waitpid(-1,WNOHANG)) > 0) { my $child_display = get_display_from_pid ($child); if ($child_display) { remove_xserver( $child_display ); } } $SIG{CHLD} = \&sig_chld_handler; # still loathe sysV } ## # sub cleanup_and_die { logger("terminating all Xservers"); remove_xserver('all'); exit(0); } ## # sub parse_xserver_file { my @confTab; open(FH, $XserversFile); while () { if (/^#/) { next; } chomp; my (@tab) = split(/ /); my ($display, $name, $type) = (shift @tab, shift @tab, shift @tab); my $command = join(' ', @tab) . $xserversArgs; push (@confTab, { 'display' => $display, 'command' => $command} ); } close(FH); # add not existing displays foreach my $conf (@confTab) { my $display = $conf->{'display'}; unless ( exists($xservers{$display})) { $xservers{ $display }->{'command'} = $conf->{'command'}; $xservers{ $display }->{'pid'} = undef; } } # schedule server to be removed foreach my $display ( keys( %xservers )) { my $foundInConfFlag = 0; foreach my $conf (@confTab) { if ($conf->{'display'} eq $display) { $foundInConfFlag = 1; } } if ($foundInConfFlag == 0) { $xservers{$display}->{'removeDisplay'} = 1; } } } ## # find $display using pid # sub get_display_from_pid { my $pid = shift; foreach my $display ( keys( %xservers )) { if ($xservers{$display}->{'pid'} == $pid) { return $display; } } return undef; } ## # kills xserver # @param $pid If 'all' kill all servers # sub remove_xserver { my $display = shift; # kill all servers if ($display eq 'all') { foreach my $display ( keys( %xservers )) { my $pid = $xservers{$display}->{'pid'}; xserver_stop($pid); } %xservers = undef; return; } # kill only one server my $pid = $xservers{$display}->{'pid'}; xserver_stop($pid); $xservers{$display}->{'pid'} = undef; } ## # start xserver sub xserver_start { my $display = shift; unless ( exists ($xservers{$display} ) and $xservers{$display}->{'pid'} == undef ) { # error return; } my $command = $xservers{$display}->{'command'}; my $child_pid; if (!defined( $child_pid = fork())) { die "cannot fork: $!"; } elsif ($child_pid) { $xservers{$display}->{'pid'} = $child_pid; } else { # TODO close all fd, logging exec $command; sleep(1); logger("error: exec $command failed"); exit(-1); } } ## # kill an xserver sub xserver_stop { my $pid = shift; unless ($pid) { return; } kill('KILL', $pid); } # SIGNAL handling $SIG{CHLD} = \&sig_chld_handler; $SIG{INT} = \&cleanup_and_die; $SIG{TERM} = \&cleanup_and_die; $SIG{QUIT} = \&cleanup_and_die; ## # main loop while (1) { sleep(0.1); my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($XserversFile); ## # parse config file if changed if ( $XserversFileMtime != $mtime ) { logger("Xservers files changes, parsing $XserversFile"); parse_xserver_file(); $XserversFileMtime = $mtime; } foreach my $display ( keys( %xservers ) ) { #FIXME: perl fucking weirdness: delete creates an empty element in the hash ($display eq '') and next; if ($xservers{$display}->{'pid'} == undef) { logger("starting Xserver for display: $display"); xserver_start($display); } if ( exists ($xservers{$display}->{'removeDisplay'} )) { #logger("removing Xserver for display: $display"); #remove_xserver($display); #delete $xservers{$display}; } } } exit 0;