chiark / gitweb /
serialmgr: Copy from woking.cam.xci-test.com
authorIan Jackson <Ian.Jackson@eu.citrix.com>
Fri, 20 Feb 2015 19:11:36 +0000 (19:11 +0000)
committerIan Jackson <Ian.Jackson@eu.citrix.com>
Fri, 20 Feb 2015 19:11:36 +0000 (19:11 +0000)
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 <Ian.Jackson@eu.citrix.com>
serialmgr/run_sympathy [new file with mode: 0755]
serialmgr/serialmgrd [new file with mode: 0755]

diff --git a/serialmgr/run_sympathy b/serialmgr/run_sympathy
new file mode 100755 (executable)
index 0000000..d4f80dd
--- /dev/null
@@ -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 (executable)
index 0000000..6a839ad
--- /dev/null
@@ -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 (<FILE>) {
+        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);
+}