# Up2us -- RPM package manager manager for linux and beyond # THIS MODULE: Command line interface. # $Id: cmdline.pm,v 1.6 2003/04/08 20:35:01 tomj Exp $ # Copyright Tom Jennings 2002-2003 # tomj@wps.com, http://wps.com # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public # License along with this program; if not, write to the Free # Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, # MA 02111-1307, USA. ############################################################# # # $error= &cmdline(); # # The main code for silent, command-line interface. Supports # only immediate update from all enabled repositories. # sub cmdline { &load_config(); # read config files # For each repository, run up2date. Skips disabled repositories, but # has no concept of "DONE" as does the Gtk interface. foreach $rep (&rep_list()) { # all of 'em print "\n--------------------------------------------------\n"; print "--------------------------------------------------\n"; print STDERR "Repository $rep:\n"; if ( &rep_item ("$rep.disable")) { print STDERR " disabled, skipped.\n"; next; } print STDERR (" Invoking up2date for repository $rep\n"); $status= &run_prog ("up2date-nox", $rep); # do actual work, if ($status eq $OK) { # whew &set_rep_item ("$rep.last-up2date", "OK " . >od); print STDERR ("Repository $rep completed.\n"); } else { &set_rep_item ("$rep.last-up2date", "ERROR " . >od); print STDERR (" ERROR: $status\n"); last; # time to die } } if ($status eq $OK) { print STDERR ("All updates completed.\n"); } &leave ($status eq $OK ? $noerror : $generror); } ############################################################# # # &load_config(); # # This local routine loads and checks configuration for the # command line functions. Unlike all other code in up2us, this # exits upon error. sub load_config { # First we need to read our main config file, from whence all # knowledge flows; die now elsewise. # eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee # This code can't use leave() which flushes config files) since # they are AFU if it needs to exit here. my $r= &read_up2us_config; # read config files, if ($r ne $OK) { # oops, print STDERR ("$readconfigerr: $r\n"); exit ($rcferror); } exit ($crcerror) if &c_crash_recovery ne $OK; # check for crash. # Before we start, we move the original up2date config file # to a safe place; we'll create one form scratch for eac # repository. The original is restored upon exit. $r= &up2date_original_save; # save up2date config if ($r ne $OK) { # oops print STDERR ("$savefail_title: $r\n"); # bad error, exit ($suderror); # can't continue. } # eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee # Now load up2date's config files. $r= &read_up2date_config; # read config files, if ($r ne $OK) { # oops, print STDERR ("$readconfig_title: " . sprintf ($readconfigerr, $r) . "\n"); &leave ($rcferror); # sigh, error out. } } # Perform crash recovery if required; return OK if success (or # not needed). sub c_crash_recovery { my $r; return $OK if &up2date_original_check eq $OK; # no problemo, print STDERR "WARNING: Previous invokation of up2us crashed, recovering.\n"; return &up2date_original_recover (); # needs recovery, } ############################################################# # # &leave (code) # # Exit the program, flush out dirty files and restore things to a # pristine state, complaining carefully on error. We make every # attempt to back out gracefully. The build_config_for creates # a RedHat-functional (though not pristine) config file should # recovery fail. None if this is likely, but it's a pain in the # ass to lose config data, and code is cheap. sub leave { my $code= shift; my $e= &build_config_for (&RedHat()); # make backup config, &ooyay ($code, "build_config_for", $e, $wcferror) if $e ne $OK; $e= &write_config_data; # flush changes to disk, &ooyay ($code, "write_config_data", $e, $mfferror) if $e ne $OK; $e= &up2date_original_restore (); # restore up2date conf, &ooyay ($code, "up2date_original_restore", $e, $ruderror) if $e ne $OK; exit $code; } # Local convenience. sub ooyay { my $code= shift; my $routine= shift; my $e= shift; my $erp= shift; print "Return code was going to be $code, but we failed "; print "during leave()'s $routine, which said \"$e\"!\n"; exit $erp; } ############################################################# # # &cmdlinelist (); # # Display information on all of the repositories. sub cmdlinelist { my $n= 0; # repository SSL noSSL last-update registered my $f= " Repository: %s (%s) Server: %s No SSL server: %s Last update: %s Registered on: %s "; my ($foo, $en, $h1, $h2, $r, $u); &load_config(); # read config files foreach (&rep_list) { $en= &rep_item ("$_.disable") ? "disabled" : "enabled"; $h1= &rep_item ("$_.serverURL"); $h1 =~ s|\w+://(.*)/.*|$1|; $h2= &rep_item ("$_.noSSLServerURL"); $h2 =~ s|\w+://(.*)/.*|$1|; $u= &rep_item ("$_.last-up2date"); $r= &rep_item ("$_.last-register"); print sprintf ($f, $_, # repository, $en, # en/dis-able, $h1, $h2, # servers, $u, $r, # updated, registered, ); } &leave ($noerror); } ############################################################# # # &cmdlinedel ($rep); # # Remove the repository from the list. Not much else to say. sub cmdlinedel { my $rep= shift; my $n= 0; if ($rep eq "") { print "Can't remove nothing, please specify a repository to remove!\n"; &leave ($generror); } &load_config(); # read config files foreach (&rep_list) { if (uc ($rep) eq uc ($_)) { &del_repository ($_); # delete it, print "Removed repository \"$rep\"\n"; ++$n; } } print "There is no repository \"$rep\", nothing happens.\n" if $n == 0; &leave ($noerror); } ############################################################# # # &cmdlineadd ($rep, $server, $noSSLserver); # # Add and register with the given repository. Exits with an # error code indicating success. sub cmdlineadd { my $rep= shift; # new repository name, my $H1= shift; # SSL server name, my $H2= shift; # no SSL server name, # Error-check input, add to our config if OK. &load_config(); # read config files $rep= uc $rep; # MUST BE upper case print "Adding new repository \"$rep\"\n"; my $e= &addrep ($rep, $H1, $H2); # error-check input, if ($e ne $OK) { # oops, print "ERROR: $e\n"; &leave ($generror); } # Before we can register we need to fetch the SSL certificate # from the server; we'll fetch the GPG keyring at the same time. print "1. Fetching authentication and signature information\n"; $e= &get_auth_junk ($rep); if ($e ne $OK) { print "ERROR: Failed\n"; &del_repository ($rep); # failed, remove it, &leave ($generror); } # Now register with this server. We try three times, if we fail # the new repository is deleted. print "2. Registering at this repository. This may take a few minutes.\n"; foreach (1..3) { $status= &run_prog ("register", $rep); last if $status eq $OK; print " $status; retrying\n"; } # Either successful or we gave up in frustration. if ($status eq $OK) { # if completed OK, print "3. Saving new system ID\n"; $status= &save_rep_systemid ($rep); # save created file, } # If status is OK, clean up and return success. if ($status eq $OK) { &set_rep_item ("$rep.last-register", "OK " . >od); print "Registration at repository $rep successful.\n"; &leave ($noerror); } else { print "ERROR: $status\n"; # went awry, &del_repository ($rep); # failed, remove it, &leave ($generror); } print "OH CRAP\n"; # only programmer error &leave (1); } ############################################################# # # $msg= &addrep ("name", "SSL URL", "noSSL URL"); # # Given the above items, error-check, build and store repository # config. Returns $OK if no error else an error message. sub addrep { my $rep= shift; my $H1= shift; my $H2= shift; # Make sure the repository name exists and is unique. $rep= uc $rep; # force upper case return "You must provide a name for this repository." if $rep eq ""; foreach (&rep_list) { return "There is already a repository named $rep." if uc ($rep) eq uc ($_); } # Check that at least one of the server fields is filled in, # and that filled-in servers are syntactically correct. return "You must provide at least one server." if not ($H1 or $H2); $H2= $H1 if not $H2; # make the blank one $H1= $H2 if not $H1; # the other. my $error= ""; # total error(s), my $e= ""; # local error, $error= "Server $H1: $e. " # build error message, if $e= &checkfqdn ($H1, "0S"); # if FQDN error, $error .= "Server $H2: $e. " if $e= &checkfqdn ($H2, "0S"); return $error if $error; # Server(s) are syntactically correct; see if they exist. If not, issue # FIXME a warning before continuing. $error= "Server $H1: $e." if $e= &checkfqdn ($H1, "0E"); # check it resolves, $error .= "Server $H2: $e." if $e= &checkfqdn ($H2, "0E"); return $error if $error; # Build the complete URL from the server name(s) entered. $H1= "https://$H1/XMLRPC" if $H1; # SSL $H2= "http://$H2/XMLRPC" if $H2; # no SSL # Now store the data we just built into the repository # config file. &rep_add ($rep); # add to the list, &set_rep_item ("$rep.serverURL", $H1); &set_rep_item ("$rep.noSSLServerURL", $H2); &set_rep_item ("$rep.last-up2date", "ADDED " . >od); &set_rep_item ("$rep.last-register", "NEVER " . >od); # Note that the data that these items points to DOESN'T YET # EXIST. They will be fetched/created in subsequent steps. # The routines that do that need to know where the data goes. &set_rep_item ("$rep.systemIdPath", &upd_item ("systemIdPath") . ".$rep"); &set_rep_item ("$rep.sslCACert", &upd_item ("sslCACert") . ".$rep"); &set_rep_item ("$rep.gpgKeyRing", &upd_item ("gpgKeyRing") . ".$rep"); return $OK; } return 1;