#!/usr/bin/perl # # This is the function library for the Node Assassin un/install programs. # # Node Assassin - Fence Agent # Digimer; digimer@alteeve.com # Jul. 11, 2010. # Version: 1.1.5 # # Play safe! use strict; use warnings; # This handles copying files. sub copy_file { my ($conf, $log, $src, $dst_dir, $dst_file)=@_; make_directory($conf, $log, $dst_dir); my $dst=$dst_dir.$dst_file; record($conf, $log, __LINE__, "I will now copy: [$src] -> [$dst]"); if ( -f $dst ) { record($conf, $log, __LINE__, "\nWARNING! The destination file: [$dst] already exists.\n"); record($conf, $log, __LINE__, "WARNING! If I proceed, it will be overwritten.\n"); print "Proceed? [y/N] " if ((not $conf->{'system'}{'no'}) && (not $conf->{'system'}{yes})); if ($conf->{'system'}{'no'}) { record($conf, $log, __LINE__, "\nAssume 'No' was set via command line switch, skipping.\n"); return; } elsif ($conf->{'system'}{yes}) { record($conf, $log, __LINE__, "\nAssume 'Yes' was set via command line switch, proceeding.\n"); } else { my $answer=; chomp $answer; if ((lc($answer) ne "y") && (lc($answer) ne "yes")) { record($conf, $log, __LINE__, "Skipping.\n"); return; } } } copy($src, $dst) or record($conf, $log, __LINE__, "\nFailed to copy: [$src] -> [$dst], error: $!\n", 2); record($conf, $log, __LINE__, " - Copied.\n"); return; } # This creates directories as needed. sub make_directory { my ($conf, $log, $dir)=@_; record($conf, $log, __LINE__, "The 'make_directory' function was called without a directory parameter. This is a program error.", 2) if not $dir; if ( not -d $dir) { record($conf, $log, __LINE__, "I need to create: [$dir]\n"); my @dirs=split/\//, $dir; my $rebuilt_dir="/"; foreach my $dir (@dirs) { next if not $dir; $rebuilt_dir.="$dir/"; if ( not -d $rebuilt_dir ) { print "doesn't exist... creating.\n"; my $ok=mkdir $rebuilt_dir, 0755 or record($conf, $log, __LINE__, "Failed to create the directory: [$rebuilt_dir], error: $!\n", 2); # my $ok=mkdir($rebuilt_dir, 0755) or record($conf, $log, __LINE__, "Failed to create the directory: [$rebuilt_dir], error: $!\n", 2); record($conf, $log, __LINE__, " - Created: [$rebuilt_dir]\n") if $ok; } } } return; } # This cleanly exits the agent. sub do_exit { my ($conf, $log, $exit_status)=@_; $exit_status=9 if not defined $exit_status; # Close the Node Assassin and log file handle, if they exist. $log->close() if $log; exit ($exit_status); } # Read in the config file. sub read_conf { my ($conf, $log)=@_; $conf={} if not $conf; # I can't call the 'record' method here because I've not read in the # log file and thus don't know where to write the log to yet. Comment # out or delete 'print' statements before release. my $read=IO::Handle->new(); my $shell_call="$conf->{'system'}{conf_file}"; open ($read, "<$shell_call") or record($conf, $log, __LINE__, "Failed to read: [$shell_call], error was: $!\n", 2); # To see this log message, debug will need to be set true in the # initialization hash. record($conf, $log, __LINE__, "Shell call: [$shell_call]\n") if $conf->{'system'}{debug}; while (<$read>) { chomp; my $line=$_; next if not $line; next if $line !~ /=/; $line=~s/^\s+//; $line=~s/\s+$//; next if $line =~ /^#/; next if not $line; my ($var, $val)=(split/=/, $line, 2); $var=~s/^\s+//; $var=~s/\s+$//; $val=~s/^\s+//; $val=~s/\s+$//; next if (not $var); record($conf, $log, __LINE__, "Storing: [$var] = [$val]\n") if $conf->{'system'}{debug}; _make_hash_reference($conf, $var, $val); } $read->close(); return (0); } # This function simply prints messages to both the log and to stdout. sub record { my ($conf, $log, $line, $msg, $critical)=@_; $critical=0 if not $critical; # The log file gets everything. print $log $msg; print $msg if not $conf->{'system'}{quiet}; # Critical messages have to print, so this ensure that it gets out # when 'quiet' is in use. print $msg if (($critical == 1) && ($conf->{'system'}{quiet})); die "\nERROR: Fatal error at line: [$line]\nERROR: $msg\n" if $critical == 2; return(0); } # This looks at the '/etc/issue' file to determine the OS. sub detect_os { my ($conf, $log)=@_; # Read it. my $issue="/etc/issue"; record($conf, $log, __LINE__.": Reading: [$issue]\n") if $conf->{'system'}{debug}; my $read=IO::Handle->new(); my $shell_call="<$issue"; open ($read, $shell_call) or record($conf, $log, __LINE__, "Failed to read: [$issue], error: $!\n", 2); while (<$read>) { chomp; next if not $_; record($conf, $log, __LINE__.": line: [$_]\n") if $conf->{'system'}{debug}; # This captures Red Hat variant OS. if (lc($_)=~/^(\w+)\s+release\s+(.*?)\s+/) { $conf->{'system'}{os_name}=$1; $conf->{'system'}{os_ver}=$2; } record($conf, $log, __LINE__.": OS: [$conf->{'system'}{os_name}], Ver: [$conf->{'system'}{os_ver}]\n") if $conf->{'system'}{debug}; # Once this is set, exit the loop. last if $conf->{'system'}{os_name}; } $read->close(); if ($conf->{'system'}{os_name}) { record($conf, $log, __LINE__.": OS: [$conf->{'system'}{os_name}], Ver: [$conf->{'system'}{os_ver}]\n") if $conf->{'system'}{debug}; } else { record($conf, $log, __LINE__, "ERROR: Failed to detect the operating system!\n", 1); record($conf, $log, __LINE__, "Please post a copy of your: [$issue] file on the AN!BBS; http://bbs.alteeve.com!\n", 1); record($conf, $log, __LINE__, "Doing so will allow Node Assassin to add support for your operating system.\n", 1); exit (1); } return(0); } ############################################################################### # Private functions # ############################################################################### ### Contributed by Shaun Fryer and Viktor Pavlenko by way of TPM. # This is a helper to the above '_add_href' method. It is called each time a # new string is to be created as a new hash key in the passed hash reference. sub _add_hash_reference { my $href1=shift; my $href2=shift; for my $key (keys %$href2) { if (ref $href1->{$key} eq 'HASH') { _add_hash_reference($href1->{$key}, $href2->{$key}); } else { $href1->{$key}=$href2->{$key}; } } } ### Contributed by Shaun Fryer and Viktor Pavlenko by way of TPM. # This takes a string with double-colon seperators and divides on those # double-colons to create a hash reference where each element is a hash key. sub _make_hash_reference { my $href=shift; my $key_string=shift; my $value=shift; # print "variable: [$key_string], value: [$value]\n"; my $chomp_root=0; if ($chomp_root) { $key_string=~s/\w+:://; } my @keys = split /::/, $key_string; my $last_key = pop @keys; my $_href = {}; $_href->{$last_key}=$value; while (my $key = pop @keys) { my $elem = {}; $elem->{$key} = $_href; $_href = $elem; } _add_hash_reference($href, $_href); } 1;