Skip to content

Instantly share code, notes, and snippets.

@dspreitz
Created April 2, 2017 18:25
Show Gist options
  • Save dspreitz/0474624f2771405dbf425f278368cc74 to your computer and use it in GitHub Desktop.
Save dspreitz/0474624f2771405dbf425f278368cc74 to your computer and use it in GitHub Desktop.
bla
#!/usr/bin/perl
#
# This script is for use with the Open Glider Network FLARM Detection System only
# Any other uses are NOT authorised
#
# Code has been sponsored by Temeletry Limited (http://www.temeletry.co.uk)
#
# Copyright (c) 2014, Melissa Jenkins, Temeletry Limited (melissa-ogn@temeletry.co.uk)
#
use strict;
use File::Copy;
use File::stat;
use Cwd;
# to make sure the file was downloaded properly
# md5sum 57b80f87891f936b9dcd3f38edee7722 RmeupofZYXEIBjkLLbQuxblRB91JL4szA6tTylb4gkggYUJ3YDt1uazxHK7/HmAYlBjcZq+wgrFvqifD9TFB1nl3JBacSmvE5hpp9M+Csbd9kWrYx4xxOBcGO3cns53bG2nHKiD9nkFfhbQ5O71gujXZ4KhCxmydT/zrOK0zrgNYkhQWgBvID78vwl+WRPRg+2w2vyjTr0iOFCgDJCnhxXzoCkC57o3R7mfXc0P22nRhm2P3FOGdo//mzdX6GGaiE5YKq+ufhKn6rimCVqfkn8uc5zY6L4J26/sZDoIAfSQuC6E1zd+uzHFsrtZNg+0YUvnL6DTA8W5Zzof5M7KOrA==
my $version='2.1a';
my $old_handle = select (STDOUT);
$| = 1; # perform flush after each write to STDOUT
select ($old_handle);
my $scriptname = $0;
if( ! ($scriptname =~ m|^/| )) {
$scriptname = cwd() . "/".$0;
$scriptname =~ s|/./|/|;
}
# do they want help?
if( $ARGV[0] =~ '[-]+h' ) {
print "$scriptname - OGN Updater v$version\n\n".
" -r reboot after running. If installing this will tell the crontab to issue a reboot \n".
" after it has checked for updates. Service will not be restarted till after it boots.\n".
" -i Do not start the service when done.\n".
" -t Test, print what path, user and configuration file is being worked on.\n";
exit 1;
}
if( $> != 0 ) {
die "You need to run this as root, or use sudo";
}
# The image version was not good and would sit waiting for a LONG time, use the one from 1.3
my $startupepoch = 1429006250; # on linux date -d '10/25/2014' '+%s', on bsd date -f '%m/%d/%Y' -j '+%s' '1/1/2000'
# old style tokens
if( -e '/home/pi/sitetoken.txt' ) {
move( '/home/pi/sitetoken.txt', '/etc/sitetoken.txt' );
}
# keep the same site id for the whole thing
my $token; my $aprscall = '*early';
if( ! -e "/etc/sitetoken.txt" ) {
my $code = qx( /bin/dd if=/dev/urandom bs=1 count=8 status=noxfer 2>/dev/null );
($token) = join('-',unpack('H4 H4 H4', $code ));
qx( echo $token > /etc/sitetoken.txt );
}
else {
$token = qx( cat /etc/sitetoken.txt );
chomp $token;
}
## exit when a script update is found
print "Checking for updates to update script ($scriptname, existing version $version)... ";
if( ! -e $scriptname ) {
status( "scriptnamewrong,$scriptname" );
die "Unable to identify script name ($scriptname)" ;
}
{
my $lasttime = stat($scriptname)->mtime;
my $currenttime;
my $tempname = '/tmp/update.temporary';
unlink( $tempname );
system( "/usr/bin/curl -s -R https://ognconfig.onglide.com/files/v2.1/update -# -o $tempname" );
if( -e "$tempname" ) {
$currenttime = stat($tempname)->mtime;
}
else {
status("error,no_temp_file");
}
if( defined( $currenttime ) && $lasttime != $currenttime ) {
my ($md5sum_calculated,$md5sum_expected,$signature);
if( qx( /bin/grep -v '^# md5sum' $tempname | /usr/bin/md5sum ) =~ /^([0-9a-f]+) / ) {
$md5sum_calculated = $1;
}
if( qx( /bin/grep -e '^# md5sum' $tempname ) =~ /md5sum ([0-9a-f]+) (.*)/ ) {
$md5sum_expected = $1;
$signature = $2;
}
# if they are defined and the same
if( defined( $md5sum_expected ) && $md5sum_expected eq $md5sum_calculated ) {
# we need to check to make sure we have our public key saved away, without this
# we can't validate the identify
{
if( ! open( OUT, '>', '/etc/ognupdatekey.pem' ) ) {
status("error,write,/etc/ognupdatekey.pem,$!");
if( ! -e '/etc/ognupdatekey.pem' ) {
status("error,nokey");
}
}
print OUT "-----BEGIN PUBLIC KEY-----\n".
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArG/od7cdIuhSvKXNbO80\n".
"tFncaCfwuKUrBGxGE6uxzXRfwcCIn8UukGTnzdMEErh441K+itC69KhgkEhY809K\n".
"sxKMJqZ2FL6lXdin7eIMpOKLIXKmwwRYyTYdChXbnrd3Y5e9BXOWEUJVsg2PYrDt\n".
"xQnm20PiUgQXVCoW0xuxCnltj69nWGdXWPwhvFYT2ulhIXfVivJmUvHESK2GbYTo\n".
"h2Fv7aIQACv4EK7UpPb9zPqBrV4MmwqAKP2LzycIdmlH9D1ebB9T2hK31MIegKuV\n".
"VWQFQyqzxnFou3n1WYN3RBe5VdPuabQGXe4VQGmJVR1/1GQ+rPLRaQYU2zDYdLi1\n".
"EQIDAQAB\n".
"-----END PUBLIC KEY-----\n";
close( OUT );
}
# execute openssl to
my $md5sum_signed = qx( echo "$signature" | /usr/bin/base64 -d | /usr/bin/openssl rsautl -verify -inkey /etc/ognupdatekey.pem -keyform PEM -pubin );
chomp( $md5sum_signed );
if( ! -e '/etc/ognupdatekey.pem' ) {
$md5sum_signed = $md5sum_calculated;
status("not_checking_signature");
print "*** Not Checking signature as no pem file exists ***\n";
}
# make sure it matches
if( defined( $md5sum_signed ) && $md5sum_signed eq $md5sum_calculated ) {
# and that it isn't the same as the one we are running (datetime issue locally)
my $current_md5sum = '';
if( qx( /bin/grep -e '^# md5sum' $scriptname ) =~ /md5sum ([0-9a-f]+) (.*)/ ) {
$current_md5sum = $1;
}
if( $current_md5sum ne $md5sum_calculated ) {
copy( $tempname, $scriptname );
unlink( $tempname );
qx( /bin/chmod +x $scriptname );
status( "scriptupdate" );
print "an update has been found, restarting script.\n";
exec $scriptname, @ARGV ;
}
else {
print "already up to date\n";
status( "uptodate,$current_md5sum" );
}
}
else {
print "invalid signature, not signed by correct key? ($md5sum_signed != $md5sum_calculated), not updating script.\n";
status( "sig_problem,".($md5sum_signed||'?').','.($md5sum_expected||'?') );
}
}
else {
print "invalid checksum ($md5sum_expected != $md5sum_calculated), not updating script.\n";
status( "checksum_problem,".($md5sum_calculated||'?').','.($md5sum_expected||'?') );
}
}
else {
print "up to date.\n";
status("uptodate,".($currenttime||'-').",$lasttime");
}
if( -e "$tempname" ) {
unlink( $tempname );
}
}
## Make sure we have the correct procServer configuration file before we do anything as it
# won't work without it!
if( ! -e '/etc/rtlsdr-ogn.conf' ) {
status( 'noconfig' );
die "Unable to find /etc/rtlsdr-ogn.conf\n";
}
if( $ARGV[0] eq '-t' ) {
status( "testing" );
}
print "Checking automatic updater is installed...";
my $check = qx( /usr/bin/crontab -u root -l );
if( $check =~ /update/ ) {
print "yes.\n";
}
elsif( $ARGV[0] eq '-t' ) {
print "no. testing only\n";
}
else {
# if we are installing and have been asked to do a reboot after running
# then we will add the -r flag to the crontab
my $reboot = '';
if( $ARGV[0] eq '-r' ) {
$reboot = '-r';
}
my $when = sprintf( "%d %d", int(rand(59)), (int(rand(7))+23)%24 );
if( ! open( OUT, "| /usr/bin/crontab -u root -" )) {
status("error,write,crontab,$!");
die "unable to write to crontab to install";
}
print OUT $check;
print OUT "$when * * * $scriptname $reboot\n";
close( OUT );
$when =~ s/ /:/;
status( "crontab/$when" );
print "installed.\n";
}
# what we read from the configuration file
my %config;
my @config_order;
my %config_description;
# next check for daemon startup script and extra details from that
my $installdirectory;
my $username;
my $configfile;# if you need to copy it from /tmp/rtlsdr-ogn.site.conf after the upgrade
my $os; my $processor;
{
my $fh;
if( ! open( $fh, '<', "/etc/rtlsdr-ogn.conf" )) {
status("error,open,/etc/rtlsdr-ogn.conf,$!");
die "Unable to read /etc/rtlsdr-ogn.conf";
}
while( <$fh> ) {
my $line = $_;
chomp $line;
if( $line =~ m|^50000\s+([a-z0-9_-]+)\s+([a-z0-9/._-]+)\s+([a-z0-9/._-]+)\s+([a-z0-9/._-]+)|i ) {
$installdirectory = $2;
$username = $1;
$configfile = $4;
}
}
# sanity check
if( ! ($installdirectory =~ m|/rtlsdr-ogn$|) ) {
status('failed/idir');
die "Please change your /etc/rtlsdr-ogn.conf to point to the rtlsdr-ogn directory rather than a version specific directory.";
}
# remove the rtlsdr as this is included in the original distributions
my $installeddirectory = $installdirectory;
$installdirectory =~ s/rtlsdr-ogn$//;
$installdirectory =~ s|/$||;
# exactly where is the config file, find it the same way the ogn process would - change into the directory
# and then convert to an absolute path
chdir $installeddirectory;
my $expandedconfigfile = Cwd::abs_path( $configfile );
copy( $expandedconfigfile, "/tmp/rtlsdr-ogn.site.conf" );
chdir $installdirectory;
read_config();
$aprscall = $config{APRS_Call}||'unknown';
$aprscall =~ s/"//g;
# make sure the device has been configured, if not then don't do anything
if( $aprscall eq 'Example' || $aprscall eq 'unknown' ) {
status( "failed/unconfigured" );
die "This device has not yet been configured.\nPlease edit $expandedconfigfile\n".
"If you are using an image from https://ognconfig.onglide.com or the bootstrap you should complete configuration before running this.\n".
"If the update script has been installed then it will automatically retry the update every night.\n";
}
# next step is to check which install it is
$processor = qx( /bin/uname -p );
my $hardware = qx( cat /proc/cpuinfo | grep Hardware );
$os = qx( /bin/uname -a );
my $download;
my $md5download = 'http://download.glidernet.org/md5.txt';
my $filename;
my $dist;
my $osv = undef;
if( -e '/etc/init.d/flarm-update' ) {
print "Disabling old updater...";
if( $ARGV[0] ne '-t' ) {
status("old_disabled");
qx( /usr/sbin/update-rc.d flarm-update remove 2>/dev/null);
unlink "/etc/init.d/flarm-update";
print "done.\n";
}
else {
print "skipped... testing\n";
}
}
if( $hardware =~ /BCM2708/ || ( $os =~ /arm/ && -e "$installdirectory/rtlsdr-ogn/gpu_dev") ) {
$filename = "rtlsdr-ogn-bin-RPI-GPU-latest.tgz";
$download = "http://download.glidernet.org/rpi-gpu/$filename";
$dist = 'RPI-GPU';
$os = 'raspberry';
$osv=qx( /bin/uname -r );
}
elsif( $processor =~ /arm/ || $os =~ /arm/ ) {
$filename = "rtlsdr-ogn-bin-ARM-latest.tgz";
$download = "http://download.glidernet.org/arm/$filename";
$dist = 'ARM';
}
elsif( $processor =~ /32/ || $processor =~ /i[0-9]86/ || $os =~ /[0-9]86-pae/ ) {
$filename = "rtlsdr-ogn-bin-x86-latest.tgz";
$download = "http://download.glidernet.org/x86/$filename";
$dist = 'x86';
}
elsif( $processor =~ /64/ ) {
$filename = "rtlsdr-ogn-bin-x64-latest.tgz";
$download = "http://download.glidernet.org/x64/$filename";
$dist = 'x64';
}
else {
my $sstring = "unidentified,$os,$processor,$hardware,".qx( uname -a ).",".qx( uname -m );
$sstring =~ s/[^A-Za-z0-9_.]/_/g;
status( $sstring );
die "Unable to identify installation type :(\n".
"os: $os\n".
"processor: $processor\n".
"uname -m: ". qx( uname -m ). "\n".
"Please email melissa-ognconfig\@littlebluecar with the above output for help!\n";
}
# identify the existing version
my $existingversion = readlink( $installdirectory."/rtlsdr-ogn" );
status( $installdirectory.','.($existingversion||'?').','.$dist );
status( "iedd,".$installeddirectory );
print "Source: $download\n".
"Installation Directory: $installdirectory\n";
print "Configuration file: $configfile ($expandedconfigfile)\n";
print "Callsign: $aprscall\n";
print "\nExisting version: $existingversion\n";
if( $ARGV[0] eq '-t' ) {
print "\n Testing only - no changes made\n";
exit;
}
# this is a work around as the OGN official startup script will hang on NTP for a LONG time
# use the 1_3 version as it is less prone to this problem
{
my $startuptime = stat("/etc/init.d/rtlsdr-ogn")->mtime;
if( $startuptime < $startupepoch ) {
system( "/usr/bin/curl 'https://ognconfig.onglide.com/files/v2.1/rtlsdr-ogn' -R -# -o /etc/init.d/rtlsdr-ogn" );
qx( /bin/chmod +x /etc/init.d/rtlsdr-ogn );
qx( /usr/bin/sudo /usr/sbin/update-rc.d -f rtlsdr-ogn defaults 2>/dev/null);
status( "upgrading/rtlsdr-ogn" );
}
}
# First we need to check the MD5 status and see if we have a different checksum as this will
# trump the file date check we used to use
my $expectedchecksum = 'expected';
{
my $f = "$installdirectory/md5.txt";
my $lasttime = -e $f ? stat($f)->mtime : 0;
qx( /usr/bin/curl -s -z $f $md5download -o $f );
my $currenttime = stat($f)->mtime;
if( qx( cat $f | /bin/grep $filename ) =~ /^([0-9a-f]+) / ) {
$expectedchecksum = $1;
}
# if the file has changed then we need to check to see if the checksum has changed
if ( $lasttime != $currenttime ) {
print "Fetched new checksum file\n";
my $currentchecksum = 'current';
if( qx( /usr/bin/md5sum $installdirectory/$filename ) =~ /^([0-9a-f]+) / ) {
$currentchecksum = $1;
}
if( $currentchecksum ne $expectedchecksum ) {
status( "md5sumdiff,$download,$currentchecksum,$expectedchecksum");
system( "touch -d 2000-01-01T00:00:00 $installdirectory/$filename" );
print "md5: checksum incorrect ($currentchecksum != $expectedchecksum), marking current download as old\n"
}
}
else {
status("md5sum,file_date_unchanged");
}
}
# check for a new download and that the dates are different from before
my $lasttime = -e "$installdirectory/$filename" ? stat("$installdirectory/$filename")->mtime : 0;
qx( /usr/bin/curl -s -z $installdirectory/$filename $download -o $installdirectory/$filename );
my $currenttime = stat("$installdirectory/$filename")->mtime;
# check what version is in the archive
my $symlinkdetails = qx( /bin/tar tf $installdirectory/$filename | grep -e 'rtlsdr-ogn-' | head -1 );
my $archiveversion;
chomp( $symlinkdetails );
if( $symlinkdetails =~ /^(rtlsdr-ogn-[0-9.]+)/ ) {
$archiveversion = $1;
print "Archive version: $archiveversion\n";
}
else {
# error on invalid files and abort
status("invalid,$download,$!,$symlinkdetails,$?");
print "Unable to identify archive version or archive missing symlink for rtlsdr-ogn\n";
exit;
}
# make sure that the downloaded version has the correct checksum, if it doesn't then don't
# do anything with it
if( qx( /usr/bin/md5sum $installdirectory/$filename ) =~ /^([0-9a-f]+) / ) {
my $currentchecksum = $1;
if( $currentchecksum ne $expectedchecksum ) {
status("invalidcsum,$download,$currentchecksum,$expectedchecksum");
print "Downloaded file does not match the published checksum, aborting\n";
exit;
}
}
print "\n";
# if they are then we are upgrading
if( $lasttime != $currenttime || $archiveversion ne ($existingversion||'') ) {
print "Upgrade from ".($existingversion||'no symlink found')." to $archiveversion found. installing\n";
print "$lasttime != $currenttime\n";
status( "upgrading/$archiveversion" );
}
else {
status( "up2date$ARGV[0]" );
print "Up to date. (version $existingversion)\n";
# if we have been asked to reboot then do it upon completion
if( $ARGV[0] eq '-r' ) {
qx( /sbin/reboot );
}
exit;
}
# perform the upgrade, first stop the service so we don't get any conflicts
print "Stopping ogn service: ";
qx( /usr/sbin/service rtlsdr-ogn stop );
print "done.\n";
# then uncompress it
qx( cd $installdirectory ; /bin/tar xzf $filename );
qx( cd $installdirectory ; /bin/rm rtlsdr-ogn; /bin/ln -fs $archiveversion rtlsdr-ogn );
# then make sure it is executable and can run as root
qx( cd $installdirectory/rtlsdr-ogn ; /bin/chown ogn:ogn *; /bin/chown root gsm_scan ogn-rf; /bin/chmod a+s gsm_scan ogn-rf; /usr/bin/mkfifo ogn-rf.fifo; /bin/chown ogn:ogn ogn-rf.fifo );
# if it is a pi then make the gpu_dev
if( $dist eq 'RPI-GPU' ) {
if( ($osv+0) >= 4.1 ) {
qx( cd $installdirectory/rtlsdr-ogn; /bin/mknod gpu_dev c 249 0; /bin/chown ogn:ogn gpu_dev );
}
else {
qx( cd $installdirectory/rtlsdr-ogn; /bin/mknod gpu_dev c 100 0; /bin/chown ogn:ogn gpu_dev );
}
}
###################
# make sure we have the configuration file in the right directory
chdir( $installeddirectory );
my $newexpandedconfigfile = Cwd::abs_path( $configfile );
# check if anything has changed... if it has then we need to copy the file
if( $newexpandedconfigfile ne $expandedconfigfile ) {
if( ! copy( '/tmp/rtlsdr-ogn.site.conf', "$newexpandedconfigfile" ) ) {
print "unable to copy $!\n";
}
status("mvconfig,f,$expandedconfigfile" );
status("mvconfig,t,$newexpandedconfigfile" );
print "Copied configuration file to $configfile ($newexpandedconfigfile)\n";
}
else {
status("config,$expandedconfigfile");
print "Configuration file path has not changed, not copying. Backup in /tmp/rtlsdr-ogn.site.conf if needed\n";
}
# and if we are allowed to start the ogn service
if( $ARGV[0] ne '-i' && $ARGV[0] ne '-r' ) {
print "Restarting ogn service: ";
qx( /usr/sbin/service rtlsdr-ogn start );
print "done.\n";
}
$existingversion = readlink( $installdirectory."/rtlsdr-ogn" );
status( "done/$existingversion/$ARGV[0]" );
print "Upgrade completed ($existingversion)\n";
# if we have been asked to reboot then do it upon completion
if( $ARGV[0] eq '-r' ) {
qx( /sbin/reboot );
}
}
sub read_config {
my @sections;
# read it into the hash
open( my $fh, '<', "/tmp/rtlsdr-ogn.site.conf" ) || return;
while( <$fh> ) {
my $line = $_;
chomp $line;
if( $line =~ /^\s*([A-Za-z]+):/ ) {
push @sections, $1;
push @config_order, "+$1";
}
if( $line =~ /^\s*}/ ) {
pop @sections;
push @config_order, "-$1";
}
if( $line =~ /([A-Za-z]+)\s*=\s*([^;]+)(.*)/ ) {
my $key = join('_',@sections,$1);
$config{$key} = $2;
$config_description{$key} = $3;
push @config_order, "=$key,$1"; # so we know what order to write in
}
}
close ($fh);
}
sub status {
my ($status) = @_;
print $status."\n";
qx( /usr/bin/curl -s https://ognconfig.onglide.com/perl/startupgrade.pl?token=$token/v$version\\&status=$status\\&call=$aprscall );
}
sub date {
my @t = gmtime($_[0]);
return sprintf( "%04d-%02d-%02dT%02d-%02d-%02d", ($t[5]+1900),($t[4]+1),$t[3],$t[2],$t[1],$t[0]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment