#!/usr/local/bin/perl use warnings; use strict; use Term::ANSIColor; use File::Tee qw(tee); use Net::Ping; use File::Basename; use Capture::Tiny qw(capture); use constant DEFAULT_USER => 'jozan'; use constant { DASH_PATH => '/usr/local/bin/dash', SU_PATH => '/usr/bin/su', GREP_PATH => '/usr/bin/grep', WC_PATH => '/usr/bin/wc', TR_PATH => '/usr/bin/tr', TEE_PATH => '/usr/bin/tee', FREEBSD_UPDATE_PATH => '/usr/sbin/freebsd-update', PKG_PATH => '/usr/sbin/pkg', PORTSNAP_PATH => '/usr/sbin/portsnap', PORTMASTER_PATH => '/usr/local/sbin/portmaster', ESPEAK_PATH => '/usr/local/bin/espeak', NOTIFY_PATH => '/usr/local/bin/notify-send' }; use constant { STDOUT_CAPTURE => 0, STDERR_CAPTURE => 1, EXIT_CAPTURE => 2 }; sub user_shell { my $ret = system( DASH_PATH, '-c', SU_PATH . ' ' . DEFAULT_USER . ' << EOF ' . $_[0] . ' >/dev/null 2>&1 EOF' ); return $ret; } sub fbsd_update { my $output; print " +----------------+ | | | FreeBSD update | | | +----------------+\n\n"; user_shell(NOTIFY_PATH . ' "Fetching" "Fetching FreeBSD updates"'); user_shell(ESPEAK_PATH . ' "Initializing. Fetching FreeBSD updates" &'); open( PS, DASH_PATH . ' -c "' . FREEBSD_UPDATE_PATH . ' fetch" |' ); while (my $read = ) { print $read; $output .= $read; } close(PS); if (!($output =~ m/No updates needed/)) { user_shell(NOTIFY_PATH . ' "Installing" "Installing FreeBSD updates"'); user_shell(ESPEAK_PATH . ' "Installing FreeBSD updates" &'); system( FREEBSD_UPDATE_PATH, 'install' ); } return; } sub ports_update { print " +----------------+ | | | ports update | | | +----------------+\n\n"; user_shell(NOTIFY_PATH . ' "Refreshing repos" "Updating pkg and ports repositories"'); user_shell(ESPEAK_PATH . ' "Updating pkg and ports repositories" &'); system( PKG_PATH, 'update' ); system( PORTSNAP_PATH, 'fetch', 'update' ); user_shell(NOTIFY_PATH . ' "Listing ports" "Listing ports in need for update, this may take a while..."'); user_shell(ESPEAK_PATH . ' "Listing ports in need for update, please stand by" &'); print "Listing ports in need for update, this may take a while...\n"; my @pre_list = capture{ system( PORTMASTER_PATH, '-L' ); }; my @pre_array = split("\n", $pre_list[STDOUT_CAPTURE]); my @pre_amount_array = grep(/new\ version/, @pre_array); my $pre_amount; foreach my $i (@pre_amount_array) { $pre_amount .= $i; } $pre_amount =~ s/\D//g; print colored("\nPorts to be updated: ", 'bold') . colored($pre_amount, 'bold green') . "\n"; my @update_array; foreach my $i (@pre_array) { if ($i =~ /New\ version\ available/) { $i =~ s/.+?(?=:).+\s+//; $i .= "\n"; push @update_array, $i; } } print @update_array; user_shell(NOTIFY_PATH . ' "Answer needed" "Do you whish to update these ' . $pre_amount . ' ports?"'); user_shell(ESPEAK_PATH . ' "Listing complete. Should I upgrade these ' . $pre_amount . ' ports?" &'); print colored("\nUpgrade these ports? ", 'bold yellow') . colored('[', 'bold green') . colored('y', 'bold red') . colored('/N', 'bold green') . colored("]\n", 'bold green') . colored("~> ", 'yellow'); my $answer = ; chomp $answer; if ($answer ne "y" && $answer ne "Y") { print "Exiting...\n"; exit; } user_shell(NOTIFY_PATH . ' "Initiating upgrade" "Ports upgrade has started\nTotal: ' . $pre_amount . ' to be updated"'); if ($pre_amount == 1) { user_shell(ESPEAK_PATH . ' "Initiating ' . $pre_amount . ' port upgrade. Configuration might be needed before compilation." &'); } else { user_shell(ESPEAK_PATH . ' "Initiating ' . $pre_amount . ' ports upgrade. Configuration might be needed before compilation." &'); } if ( system( PORTMASTER_PATH, '-dya', '--no-confirm' ) == 0 ) { user_shell(NOTIFY_PATH . ' "Upgrade complete!" "Ports upgrade installed successfully\nTotal: ' . $pre_amount . ' installed"'); user_shell(ESPEAK_PATH . ' "Success: ' . $pre_amount . ' ports installed successfully" &'); } else { print "Some ports failed. Listing ports in need for update, this may take a while...\n"; user_shell(NOTIFY_PATH . ' -u critical -t 15000 "Failure!" "One or several ports failed to build"'); user_shell(ESPEAK_PATH . ' "Failure: one or several ports failed to install. Listing ports in need for update, please stand by" &'); my @post_list = capture{ system( PORTMASTER_PATH, '-L' ); }; my @post_array = split("\n", $post_list[STDOUT_CAPTURE]); my @post_amount_array = grep(/new\ version/, @post_array); my $post_amount; foreach my $i (@post_amount_array) { $post_amount .= $i; } $post_amount =~ s/\D//g; my $diff_nbr = $pre_amount - $post_amount; print . "\n" . colored($diff_nbr, 'bold green') . ' were updated, ' . colored($post_amount, 'bold yellow') . " ports still need to be updated.\n"; user_shell(NOTIFY_PATH . ' -u critical -t 15000 "Summary" "Upgraded - ' . $diff_nbr . '\nRemaining - ' . $post_amount . '"'); user_shell(ESPEAK_PATH . ' "Failure: not all ports were upgraded - ' . $diff_nbr . ' upgraded - ' . $post_amount . ' remaining. Listing ports in need for update, please stand by" &'); } return; } sub clean_exit { my $end_date = `/bin/date`; chomp($end_date); print "\n\n" . $end_date . ": system upgrade complete!\n"; exit; } sub main { my $p = Net::Ping->new; if (!($p->ping('freebsd.org', 2))) { print STDERR colored(basename($0) . ":" , 'bold') . colored(" failure:", 'bold red') . " you seem not connected to the internet.\n"; user_shell(NOTIFY_PATH . ' -u critical -t 10000 "Failure" "Internet connection required"'); user_shell(ESPEAK_PATH . ' "Failure: internet connection required" &'); exit 1; } my $user = $ENV{LOGNAME} || $ENV{USER} || getpwuid($<); if ($user ne 'root') { print STDERR colored(basename($0) . ":" , 'bold') . colored(" failure:", 'bold red') . " insufficent privileges, needs to be run as root.\n"; user_shell(NOTIFY_PATH . ' -u critical -t 10000 "Failure" "root privileges required"'); user_shell(ESPEAK_PATH . ' "Failure: root privileges required" &'); exit 2; } fbsd_update(); ports_update(); clean_exit(); } main(); __END__