From: Ian Jackson Date: Fri, 20 Feb 2015 19:11:36 +0000 (+0000) Subject: serialmgr: Copy from woking.cam.xci-test.com X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=sympathy.git;a=commitdiff_plain;h=e398b84ba34f0290e21830e36ff40719e2ec7125 serialmgr: Copy from woking.cam.xci-test.com Copy serialmgrd and run_sympathy from woking:/root/projects/serialmgr. The repo is not suitable for import because it contains config data from some other installation, and other things. From CVS/Entries: /run_sympathy/1.1/Fri May 9 13:06:50 2008// /serialmgrd/1.25/Sat Jun 27 18:24:33 2009// We will have to perhaps hack these about a bit, and arrange to install them somewhere. Signed-off-by: Ian Jackson --- diff --git a/serialmgr/run_sympathy b/serialmgr/run_sympathy new file mode 100755 index 0000000..d4f80dd --- /dev/null +++ b/serialmgr/run_sympathy @@ -0,0 +1,5 @@ +#!/usr/bin/env perl +# +# $Id: run_sympathy,v 1.1 2008/05/09 13:06:50 staffcvs Exp $ +# +exec '@prefix@/bin/sympathy', '-c', '-k', $ENV{HOME} . '/console-socket'; diff --git a/serialmgr/serialmgrd b/serialmgr/serialmgrd new file mode 100755 index 0000000..6a839ad --- /dev/null +++ b/serialmgr/serialmgrd @@ -0,0 +1,422 @@ +#!/usr/bin/env perl +# +#$Id: serialmgrd,v 1.25 2009/06/27 18:24:33 staffcvs Exp $ +# + +use Data::Dumper; +use Error qw(:try); +use POSIX; +use Sys::Syslog; + +my $stuff = []; +my $hosts = []; +my $hup = 0; + +my $consolidate_exe = "/usr/local/bin/consolidate"; +my $sympathy_exe = "/usr/local/bin/sympathy"; + +my @keys = qw(host portcode baud task user password name options); + +my $labeling = { + shedu => { offsets => [ 0, 7, 3, 11, 15 ], }, + phoenix => { offsets => [ 0, 3, 11, 15 ], }, + leprechaun => { offsets => [ 0, 3 ], }, + imp => { offsets => [ 0, 3 ], }, + pixie => { offsets => [ 0, 3, 11 ], }, + basilisk => { offsets => [ 0, 3, 11, 7, 15 ], }, + wyvern => { offsets => [ 0, 3, 11 ], }, + goblin => { offsets => [ 0, 3 ], }, + naga => { offsets => [ 0, 5 ], }, + dragon => { offsets => [ 0, 3, 11 ], }, + woking => { offsets => [ 0, 3, 11 ], }, +}; + +sub port_decode($$) { + my ( $host, $code ) = @_; + + return "/dev/ttyS" . $code if ( $code =~ /^\d+$/ ); + return "/dev/ttyUSB" . $1 if ( $code =~ /^u.(\d+)$/ ); + return "/dev/ttyS" . ( $labeling->{$host}->{offsets}->[$1] + $2 ) + if ( $code =~ /^(\d+)\.(\d+)$/ ); + + return $code; +} + +sub quit() { + sleep(10); + exit(1); +} + +sub read_file() { + my $lines = []; + my $c; + open FILE, "<" . "/etc/serialmgr/config"; + + while () { + next if ( $_ =~ /^#/ ); + + chomp; + split(':'); + $c = 0; + push @$lines, { map { $keys[ $c++ ] => $_ } @_ }; + } + close FILE; + return $lines; +} + +sub hostname() { + my ( $sysname, $nodename, $release, $version, $machine ) = POSIX::uname(); + return $1 if ( $nodename =~ /([^.]+)\./ ); + return $nodename; +} + +sub check_users($) { + my $c = shift; + + for my $l (@$c) { + my $shell; + if ( $l->{task} eq "sympathy" ) { + $shell = "/usr/local/bin/run_sympathy"; + } + else { + $shell = "/usr/local/bin/run_conclient"; + } + if ( not defined getpwnam( $l->{user} ) ) { + syslog( LOG_ERR, "creating an account for user " . $l->{user} ); + mkdir "/export/home"; + mkdir "/export/home/colo"; + my @cmd = (); + push @cmd, "useradd"; + push @cmd, "-d", "/export/home/colo/" . $l->{user}; + if ( length( $l->{password} ) > 2 ) { + push @cmd, "-p", $l->{password}; + } + push @cmd, "-s", $shell; + push @cmd, "-m"; + push @cmd, $l->{user}; + + #print join( ' ', @cmd ), "\n"; + system @cmd; + } + if ( not defined getgrnam( $l->{user} ) ) { + syslog( LOG_ERR, "need to create a group for " . $l->{user} ); + quit(); + } + my $current_shell = ( getpwnam( $l->{user} ) )[8]; + my $uid = getpwnam( $l->{user} ) ; + + if (( $uid > 0 ) and ( $current_shell ne $shell )) { + syslog( LOG_ERR, + "changing shell for user " . $l->{user} . " to " . $shell ); + my @cmd = (); + push @cmd, "usermod"; + push @cmd, "-s", $shell; + push @cmd, $l->{user}; + system @cmd; + + } + + if ( length( $l->{password} ) > 2 ) { + my $pwd = ( getpwnam( $l->{user} ) )[1]; + if ( $l->{password} ne $pwd ) { + syslog( LOG_ERR, "changing password for user " . $l->{user} ); + my @cmd = (); + push @cmd, "usermod"; + push @cmd, "-p", $l->{password}; + push @cmd, $l->{user}; + system @cmd; + + } + } + + if ( $l->{user} eq 'root' ) { + } + elsif ( ! -d "/export/home/colo/".$l->{user} ) { + syslog( LOG_ERR, + "need to create a home directory for " . $l->{user} ); + quit(); + } + elsif ( ( getpwnam( $l->{user} ) )[2] != ( stat _ )[4] || + ( getpwnam( $l->{user} ) )[3] != ( stat _ )[5] ) { + syslog( LOG_ERR, + "changing home directory ownership for user " . $l->{user} ); + my @cmd = (); + push @cmd, "chown", "-R"; + push @cmd, $l->{user}.".".$l->{user}; + push @cmd, "/export/home/colo/".$l->{user}; + system @cmd; + } + } + +} + +sub resolve_users($) { + my $c = shift; + my $ret=[]; + my $host = hostname(); + + for my $l (@$c) { + next if ( $l->{host} ne $host ); + + my $uid = $l->{user}; + my $gid = $l->{user}; + + if ( $uid =~ /[^\d]/ ) { + $uid = getpwnam($uid); + if ( !defined($uid) ) { + syslog( LOG_ERR, "unknown user " . $l->{user} ); + quit(); + } + } + + if ( $gid =~ /[^\d]/ ) { + $gid = getgrnam($gid); + if ( !defined($gid) ) { + syslog( LOG_ERR, "unknown group " . $l->{user} ); + quit(); + } + } + $l->{uid} = $uid; + $l->{gid} = $gid; + $l->{backoff} = 0; + $l->{badstarts} = 0; + $l->{running} = 0; + + if ( $l->{uid} > 0 ) { + $l->{socket} = "/export/home/colo/" . $l->{user} . "/console-socket"; + $l->{socket_dir} = "/export/home/colo/" . $l->{user}; + $l->{log} = "/export/home/colo/" . $l->{user} . "/logs/console"; + $l->{log_dir} = "/export/home/colo/" . $l->{user} . "/logs"; + } + else { + if ( $l->{task} eq "sympathy" ) { + $l->{socket} = "/root/sympathy/" . $l->{name}; + $l->{socket_dir} = "/root/sympathy"; + $l->{log} = "/root/sympathy/" . $l->{name} . ".log"; + $l->{log_dir} = "/root/sympathy"; + } + else { + $l->{socket} = "/root/consoles/" . $l->{name}; + $l->{socket_dir} = "/root/consoles"; + $l->{log} = "/root/consoles/" . $l->{name} . ".log"; + $l->{log_dir} = "/root/consoles"; + } + } + push @$ret,$l; + } + +return $ret; +} + +sub get_config() { + my $cf = read_file(); + my $stuff = []; +# my $host = hostname(); + + for $line (@$cf) { +# if ( $line->{host} eq $host ) { + $line->{device} = port_decode( $line->{host}, $line->{portcode} ); + push @$stuff, $line; +# } + } + + return $stuff; +} + +sub start($) { + my $t = shift; + my $exe; + my @args; + + $t->{started} = time(); + + my $pid = fork(); + if ( !defined($pid) ) { + syslog( LOG_ERR, "fork failed" ); + return undef; + } + elsif ( $pid != 0 ) { + $t->{pid} = $pid; + $t->{running} = 1; + syslog( LOG_ERR, + "Started " + . $t->{task} . " for " + . $t->{name} . " on " + . $t->{device} . " (" + . $t->{portcode} + . ") pid " + . $t->{pid} ); + return $pid; + } + + # use sympathy to clean up any old lock files whilst we're still root + system( $sympathy_exe, "-S", "-C", "-d", $t->{device} ); + + chown $t->{gid}, $t->{uid}, $t->{device}; + $( = $) = $t->{gid} if ( $t->{gid} != 0 ); + $< = $> = $t->{uid} if ( $t->{uid} != 0 ); + + mkdir $t->{socket_dir}; + mkdir $t->{log_dir}; + + if ( $t->{task} eq "sympathy" ) { + + push @args, "-S"; + push @args, "-s"; + push @args, "-F"; + push @args, "-d"; + push @args, $t->{device}; + push @args, "-b"; + push @args, $t->{baud}; + push @args, "-K"; + push @args, "-k"; + push @args, $t->{socket}; + push @args, "-L"; + push @args, $t->{log}; + push @args, "-R"; + push @args, $t->{options} if $t->{options}; + + $exe = $sympathy_exe; + } + else { + push @args, "-d"; + push @args, "-e"; + push @args, "-s"; + push @args, $t->{baud} . ",n,8"; + push @args, "-f"; + push @args, "none"; + push @args, "-l"; + push @args, "1048576"; + push @args, $t->{device}; + push @args, $t->{log}; + push @args, $t->{socket}; + push @args, $t->{options} if $t->{options}; + + $exe = $consolidate_exe; + + } + + syslog(LOG_ERR, $exe. " ". join( ' ', @args )); + + exec( $exe, @args ); + + exit(1); + +} + +sub died($) { + my $t = shift; + + my $ranfor = $t->{ended} - $t->{started}; + + syslog( LOG_ERR, + "Finished " + . $t->{task} . " for " + . $t->{name} . " on " + . $t->{device} . " (" + . $t->{portcode} + . ") pid " + . $t->{pid} + . " lasted " + . $ranfor + . "s" ); + + if ( $ranfor < 20 ) { + $t->{badstarts}++; + } + + if ( $t->{badstarts} > 5 ) { + syslog( LOG_ERR, + "Looping " + . $t->{task} . " for " + . $t->{name} . " on " + . $t->{device} . " (" + . $t->{portcode} + . ") pid " + . $t->{pid} + . " suspended" ); + $t->{backoff} = time() + 5 * 60; + $t->{badstarts} = 0; + } + $t->{pid} = undef; + +} + +sub hup() { + $hup++; +} + +sub medea() { + for $t (@$stuff) { + kill POSIX::SIGTERM, $t->{pid} if ( defined( $t->{pid} ) ); + } +} + +sub terminate() { + syslog( LOG_ERR, "shutting down on signal" ); + medea(); + exit(0); +} + +sub sigchld() { + for $t (@$stuff) { + if ( $t->{running} and ( $t->{pid} == waitpid( $t->{pid}, WNOHANG ) ) ) + { + $t->{ended} = time(); + $t->{running} = 0; + } + } +} + +openlog( "serialmgrd", "pid,console", LOG_LOCAL0 ); + +syslog( LOG_ERR, "starts" ); + +$stuff = get_config(); +check_users($stuff); +$stuff=resolve_users($stuff); + +$SIG{HUP} = \&hup; +$SIG{INT} = $SIG{TERM} = \&terminate; +$SIG{CHLD} = \&sigchld; + +while (1) { + my $now = time(); + + sigchld(); + + for $t (@$stuff) { + if ( defined $t->{pid} ) { + if ( ( $t->{running} ) and ( kill( 0, $t->{pid} ) == 0 ) ) { + $t->{running} = 0; + $t->{ended} = time(); + } + + if ( not $t->{running} ) { + died($t); + } + } + + if ( ( not defined( $t->{pid} ) ) and ( $t->{backoff} < $now ) ) { + start($t); + + } + } + + + if ( scalar(@$stuff) < 1 ) { + syslog( LOG_ERR, "Nothing to do - sleeping 3600s" ); + sleep(3600); + } + if ($hup) { + $hup = 0; + syslog( LOG_ERR, "SIGHUP rereading config" ); + medea(); + + $stuff = get_config(); + check_users($stuff); + $stuff=resolve_users($stuff); + } + + sleep(10); +}