"Fossies" - the Fresh Open Source Software Archive

Member "fou4s-0.16.0/fou4s" (22 Mar 2012, 158228 Bytes) of package /linux/privat/old/fou4s-0.16.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Bash source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

A hint: This file contains one or more very long lines, so maybe it is better readable using the pure text view mode that shows the contents as wrapped lines within the browser window.


    1 #!/bin/bash
    2 ###################################################
    3 # fou4s - Fast Online Update for SuSE
    4 #
    5 # Copyright (C) 2002-2009 Markus Gaugusch <fou4s@gaugusch.at>
    6 # Many improvements by Lars Ellenberg <l.g.e@web.de>
    7 #
    8 # See man page fou4s(1) for more information or look at http://fou4s.gaugusch.at
    9 #
   10 # SVN info:
   11 # $Author: markus $
   12 # $Date: 2012-03-22 07:38:26 +0100 (Don, 22 Mär 2012) $
   13 # $Rev: 224 $
   14 #
   15 # Optimized for tabstop length 3 and terminal width ~160 chars
   16 #
   17 # This program is free software; you can redistribute it and/or
   18 # modify it under the terms of the GNU General Public License
   19 # as published by the Free Software Foundation; either version 2
   20 # of the License, or (at your option) any later version.
   21 #
   22 # This program is distributed in the hope that it will be useful,
   23 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   25 # GNU General Public License for more details.
   26 #
   27 # You should have received a copy of the GNU General Public License
   28 # along with this program; if not, write to the Free Software
   29 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   30 #
   31 ##################################################
   32 
   33 FOUVERSION=0.16.0
   34 [[ $FOUVERSION == *beta* ]] && BETA=beta- # used for self-update of fou4s
   35 [[ $FOUVERSION == *rc* ]] && BETA=beta- # used for self-update of fou4s
   36 # probably need extended globbing for pattern matching
   37 # available at least since suse 6.1 (but maybe not for people running fou4s
   38 # in "server" mode on other unices)
   39 shopt -s extglob \
   40 || {
   41         echo "Need extended globbing or some features will fail!"
   42         echo "Please update to a newer version of bash."
   43         exit 255
   44     }
   45 unset LANG # to get sane error messages (necessary for parsing)
   46 unset LC_CTYPE
   47 HOSTNAME=`hostname` # for tcsh, which sets $HOSTNAME to fqdn
   48 WHOAMI=$0
   49 [[ $WHOAMI != /* ]] && WHOAMI="$PWD/${0#./}"
   50 DIRNAME=${WHOAMI%/*}
   51 BASENAME=${WHOAMI##*/}
   52 
   53 
   54 if [[ $1 == --rightsok ]] || [[ $1 == --ri* ]] ; then
   55     shift # remove the rightsok parameter from parameter list
   56 elif [[ -x `type -p sg` ]] ; then # only if sg exists - it is missing on some SuSE versions
   57     groups=`grep ^fou4s: /etc/group`
   58     # If root or members of group fou4s call fou4s, set group fou4s and
   59     # make all files group writeable
   60     if [[ $EUID -eq 0 && -n $groups || $groups != *: ]] ; then
   61         umask g+rwx
   62         sg fou4s -c "$0 --rightsok $*" && exit
   63         [[ $? -eq 1 ]] && echo "You don't have group fou4s in your system, please run 'groupadd fou4s'!" || exit $?
   64     fi
   65 fi
   66 
   67 ################################ getSuSEVersion
   68 # get version of the running suse product. Used to get the right
   69 # patches from ftp server.
   70 # Modifies: SUSEVERSION, ARCH, SUSEPRODUCT, NODOTSUSEVERSION
   71 # UsedBy: main
   72 function getSuSEVersion()
   73 {
   74     local ver dir i
   75     dir=`dirname $0`
   76     [[ -O $dir/SuSE-release && -x $dir/SuSE-release ]] && ver=(`$dir/SuSE-release v1.2`) || \
   77     for i in /usr/bin /usr/local/bin ; do
   78         [[ -x $i/SuSE-release ]] && ver=(`$i/SuSE-release v1.2`) && break
   79     done
   80     SUSEVERSION=${ver[1]}
   81     NODOTSUSEVERSION=${ver[2]}
   82     ARCH=${ver[3]}
   83     SUSEPRODUCT=${ver[4]//\"} # vim syntax helper: "
   84     KERNELVER=${ver[5]}
   85     MACHINEARCH=${ver[6]}
   86     VALIDARCHS=${ver[7]//+/ }
   87 } # getSuSEVersion
   88 
   89 
   90 # ---------------------------
   91 # global variable definitions
   92 # ---------------------------
   93 getSuSEVersion  # needed for some variables
   94 ACCEPTPREINSTALLINFO=0 # Don't require interactive mode for preinstall info
   95 ALLCOUNT=0      # current index in list of all packages
   96 ALLPKGDESCFILES= # for package description cache
   97 AUTOLIST=       # List of packages to install automatically
   98 AUTOMODE=0      # Automatic installation of selected packages
   99 BASEDIR=$PWD    # current directory, needed to access relative paths (rpmdir,..)
  100 BENCHMARK=0     # do benchmark and use fastest server
  101 CACHEDIR=/var/cache/fou4s # default cache root directory
  102 CHECKDELETED=1  # check for deleted files that are still accessed after update
  103 CHECKONLYDELETED=0  # check for deleted files and exit
  104 CHECKFOU=1      # check for update of fou4s
  105 CHECKONLY=0     # only compare patch descriptions with RPM db
  106 CLEANCACHE=0    # clean update description cache (see --cleancache)
  107 COLOR=1         # use colored output
  108 COLUMNS=80      # width of screen output (default)
  109 COMMONFUNCS=0   # for announcement2pkgdesc to include fou4s functions
  110 COMPATIBLE=1    # be as compatible as possible to YOU
  111 CONFIGFILE=None # default config file (information text only, in this case)
  112 CONFIGFILES="/etc/fou4s.conf $HOME/.fou4s ./.fou4s" # config files, the last one has highest priority
  113 CRONINST=0      # install cronjob
  114 CRONSERVER=0    # install cronjob for server (24h connected)
  115 CRONWORKSTATION=0 # install cronjob for workstation
  116 DAYSOLDER=0     # only show packages older than n days
  117 DLPATH=$CACHEDIR/packages # default path for downloaded RPMs
  118 DOINSTALL=0     # perform installation/download
  119 DORECODE=0      # translate from UTF8 to ISO8859-15
  120 DOWNLOAD=0      # attempt to download files
  121 EXCLUDELIST=    # skip packages of this series (blank seperated)
  122 EXPORTFILE=     # filename for export function
  123 EXPORT=0        # export files to install/download on/for another host
  124 FAILCOUNT=0     # number of failed updates (dependency problems, etc.)
  125 FIXPERMS=0      # Fix permissions of package descr. file on SuSE 8.1 for nonroot
  126 FORCEDARCH=     # arch given on commandline
  127 FORCEINSTALL=0  # force installation of current patch set
  128 FOU4SKEY=AFB66D7C # fou4s build key id
  129 FOUNDFILE=      # return variable for fileExists()
  130 GENERATED=1     # check for generated package descriptions
  131 GET81PACKAGEDESCRIPTIONS=0 # get package description file for 8.1 from ftp
  132 GETALL=0        # download all packages
  133 GETALLNEW=0     # download only packages that are not installed or newer
  134 GETSOURCE=0     # download src.rpm only
  135 GLOBALRPMOPTS=  # global rpm installation options (to be set later)
  136 GLOBALWGETOPTS='--retr-symlinks -np -nd -e robots=off --reject="=D,=A" --passive-ftp --timestamping -t3'
  137 GLOBALWGETOPTS="$GLOBALWGETOPTS --user-agent=fou4s-$FOUVERSION"
  138 GLOBALCURLOPTS="-A fou4s-$FOUVERSION --progress-bar -C - -L"
  139 HTTPPASSWD=     # For SuSE business products
  140 HTTPUSER=       # For SuSE business products
  141 HOSTEXEC=       # used to execute commands at remote hosts
  142 IGNORELIST=     # packages that shouldn't be installed
  143 IMPORT=0        # import files to install/download from/for another host
  144 IMPORTFILE=     # filename for import function
  145 INSTMODE=1      # 0=Every package alone, 1=each patchfile grouped, 2=All at end
  146 INTERACTIVE=0   # interactive mode
  147 KERNELPKG=      # name of package containing kernel
  148 KERNELCHECK=1   # special handling for linux kernel updates
  149 KERNELBACKUP=1  # create backup when doing a kernel update
  150 LANGUAGE=english # for info from update descriptions
  151 LIMIT=0         # no bandwith limits by default
  152 LISTAVAILRPMS=0 # list available RPM files
  153 LOGFILE=/var/log/fou4s.log # logfile that contains all installed updates
  154 LOGLEVEL=1      # Loglevel for logfile, 0=lowest, 3=full debug
  155 NORESUME=0      # Only work with complete files (no continued download)
  156 OFFLINE=0       # Connect to remote host when checking for updates
  157 ONLYINSTALLEDUSERRPMS=0  # only process installed user specified rpms
  158 PACKAGES81=
  159 PATCHDIR=patches # repodata for 10.1
  160 PATCHRPMS=1     # use patch rpm's on SuSE 8.1 if possible
  161 POSTINSTLIST=   # List of patch descriptions containing postinstall info
  162 POSTINFO=0      # show postinstall information (later overwritten for each pkg)
  163 PROXYDIGEST=0   # use digest auth with proxy (enforces curl)
  164 PROXYPASS=      # http proxy password
  165 PROXYUSER=      # http proxy username
  166 QUIET=0         # quiet mode (for cron jobs)
  167 REMARKLIST=     # packages that shouldn't be installed, but remarked if
  168 REMOVE=1        # remove packages after (successful) install
  169 RPMINSTLIST=    # global RPM installation list
  170 RPMEXPORTLIST=  # list of RPM's to be exported to other host
  171 RPMCACHEVER=2.1 # version of the RPM cache file
  172 RWIDTH=22       # width of rpm name field in output
  173 RSYNCSERVER=rsync://ftp.gwdg.de/SuSE/ftp.suse.com/suse/$ARCH #default for gpd.sh
  174 RSYNCOPTS="-t --partial" # global rsync options: timestamps
  175 SAFEMODE=0      # don't check for package signatures and don't run insttriggers
  176 SECURITY=0      # only install security updates
  177 SERVERLIST=     # download server
  178 SKIPGPG=0       # skip GPG verification
  179 SKIPOPTIONAL=0  # skip optional packages
  180 SRCRPMS=        # list of packages that are downloaded as src.rpm
  181 SUSECONFIG=1    # run SuSEconfig after update
  182 TESTMODE=0      # run in testing mode
  183 THREADS=1       # run in multi-threaded mode
  184 UPDATEPACKAGELIST=0 # update list of available updates
  185 UPDATESERVERLIST=0  # update list of ftp servers
  186 UPDATESUSESERVERS=0 # update /etc/suseservers
  187 USEBUILDTIME=0  # don't compare versions, but the build time of the packages
  188 USECACHE=2      # cache for package descriptions
  189 USECURL=0       # use curl instead of wget
  190 USEDELTARPMS=1  # support for delta rpms
  191 USEDIR=0        # use "directory" or "directory.1" files ...
  192 USEFULLPATH=1   # support for structured (a1/aaa_base.rpm) download dir
  193 USEPROGRESS=1   # default, will be reset later after option parsing
  194 USERRPMS=       # user requested RPM file(s)
  195 USERSYNCPROXY=1 # use --proxy value as rsync proxy
  196 VCMP_OK=0       # try to use zypper vcmp if our vcmp fails
  197 VERBOSE=0       # more (debug) output
  198 VERSIONOVERRIDE=0 # this is set to 1, if user overrides detected values
  199 XMLP=           # path to xmlp awk script (filled later)
  200 LASTANSWER=n    # last answer for user input
  201 INVERSE=0       # inverse coloring (for white background terminals)
  202 BRIGHT=1        # bright colors
  203 COUNTER=(0 0 0 0 0 0 0 0 0) # array for counters
  204 SIZES=(0 0 0 0 0 0 0 0 0)   # array for sizes
  205 HDSIZES=(0 0 0 0 0 0 0 0)   # size on hdd
  206 DLSIZES=(0 0 0 0 0 0 0 0)   # size of missing data
  207 _ZERO=0         # packages with zero size
  208 _SECURITY=1     # -"- for security packages
  209 _RECOMMENDED=2  # ... recommended packages
  210 _OPTIONAL=3     # optional packages
  211 _YAST=4         # yast packages
  212 _GENERATED=5    # generated packages
  213 _SCRIPT=6       # scripts
  214 _ALL=7          # packages that need to be updated
  215 _INST=8         # installed packages
  216 
  217 
  218 # Global variable RETVAL for non $? success/failure return values
  219 # array variable, you could return more than one value
  220 # if refered without index, you get index 0, the default.
  221 RETVAL=()
  222 
  223 
  224 ################################
  225 ################################ Functions
  226 ################################
  227 
  228 
  229 ################################ myEcho
  230 # write message, but only if debug level is right
  231 # parameters:
  232 # $1 verbosity level [0-4]
  233 # $2 Text to write to stdout if level is ok
  234 function myEcho()
  235 {
  236     [[ $VERBOSE -lt $1 ]] || echo -e "${@: 2}"
  237 } # myEcho
  238 
  239 ################################ myWarn
  240 # print warning message, but only if debug level is right
  241 # parameters:
  242 # $1 verbosity level [0-4]
  243 # $2 Text to write to stdout if level is ok
  244 function myWarn()
  245 {
  246     echo -en ${COL_YELLOW}
  247     myEcho "$@"
  248     echo -en ${COL_NORM}
  249 } # myWarn
  250 
  251 
  252 ################################ myError
  253 # print error message, but only if debug level is right
  254 # parameters:
  255 # $1 verbosity level [0-4]
  256 # $2 Text to write to stdout if level is ok
  257 function myError()
  258 {
  259     echo -en ${COL_RED}
  260     myEcho "$@"
  261     echo -en ${COL_NORM}
  262 } # myError
  263 
  264 
  265 ################################ myNote
  266 # print notification message, but only if debug level is right
  267 # parameters:
  268 # $1 verbosity level [0-4]
  269 # $2 Text to write to stdout if level is ok
  270 function myNote()
  271 {
  272     echo -en ${COL_CYAN}
  273     myEcho "$@"
  274     echo -en ${COL_NORM}
  275 } # myNote
  276 
  277 
  278 ################################ myRead
  279 # Like bash "read", but simplifies answer (Y/Yes->y, ...)
  280 # parameters are passed to bash read command, but prompt
  281 # must always be given. The answer is returned in $answer
  282 function myRead()
  283 {
  284         eval read -p '"$*"' answer
  285         case $answer in
  286             Y|yes|Yes|YES) eval answer=y ;;
  287             N|no|No|NO) eval answer=n ;;
  288             S|skip) eval answer=n ;;
  289         esac
  290 }
  291 
  292 
  293 ################################ logWrite
  294 # Appends some text to $LOGFILE with timestamp
  295 # Parameters:
  296 # $1: loglevel (like $VERBOSE)
  297 # rest: text
  298 function logWrite()
  299 {
  300     [[ $LOGLEVEL -lt $1 ]] && return
  301     shift
  302     local time=`date "+%Y-%m-%d %H:%M:%S"`
  303     echo $time $* >> $LOGFILE
  304 } # logWrite
  305 
  306 
  307 ################################ checkLanguage
  308 # checks if the given text is nonzero and changes language to english if it is
  309 function checkLanguage()
  310 {
  311     [[ -z $1 ]] && return 1
  312     return 0
  313 }
  314 
  315 ################################ showUsageShort
  316 # short overview about fou4s options
  317 # UsedBy: checkParameters
  318 function showUsageShort()
  319 {
  320     cat << _EOF
  321 fou4s v$FOUVERSION  (c) 2002-2009 Markus Gaugusch <fou4s@gaugusch.at>
  322 usage: fou4s -u [-bqv] [--checkfou4s] [--proxyuser]
  323                 [--proxypasswd]
  324        fou4s -e [--all] [-bdosv] [--proxyuser] [--proxypasswd]
  325        fou4s --auto [-nosv]
  326        fou4s -i [-abcdgnorsv] [-f file] [--interactive] [--nodeps]
  327                 [--proxyuser] [--proxypasswd]
  328        fou4s -l [-os]
  329        fou4s --server [-vw] [--proxyuser] [--proxypasswd]
  330        fou4s --checkdeleted
  331        fou4s --fixperm
  332 Type fou4s --help for more information.
  333 See the manual page fou4s(1) for detailed help.
  334 _EOF
  335     exit 0
  336 } # showUsageShort
  337 
  338 
  339 ################################ showUsage
  340 # show long usage information and exit
  341 # UsedBy: checkParameters
  342 function showUsage()
  343 {
  344     cat << _EOF
  345 fou4s v$FOUVERSION  (c) 2002-2009 Markus Gaugusch <fou4s@gaugusch.at>
  346 usage: fou4s [task] [options]
  347 task:
  348 -u, --update     Get new package list from FTP server and exit
  349 -i, --install    Compare package list with RPM db and get/install packages
  350 --all            Process all available packages, no matter if they are needed
  351 --allnew         Process packages that are newer or not installed yet
  352 --auto           Works like -ued, plus auto installation of specific packages
  353 -e, --evaluate   Evaluate, if new updates should be installed (no dl/install)
  354 -l, --list       List available RPMs (for use with -f)
  355 --server         Select ftp server to use (interactive)
  356 --checkdeleted   Check for deleted files that are still in use and exit
  357 --fixperm        Fix package descr. file read permissions on 8.1 for group fou4s
  358 options:
  359 -a               Install every package immediately after downloading (see --end)
  360 --arch           Override architecture autodetect (get packages for other arch)
  361 -b, --benchmark  Do benchmark (fou4s-benchmark) and use fastest server
  362 --buildtime      Compare buildtime of packages instead of version number
  363 -c               Do not run SuSEconfig after update (requires -i)
  364 --config cfgfile Use "cfgfile" as configuration file. Must be the first option
  365 --checkfou4s     Check for an updated version of fou4s (requires -u)
  366 -d               Check packages and download RPMs (no installation)
  367 --end            Install all updates at the end, not when listing them (see -a)
  368 --exclude x      Don't check patch description 'x' or series 'x' (wildcards ok)
  369 -f custom.rpm    Try to process the given file(s). -l shows available RPMs
  370 --force          Force RPM updates. (DANGEROUS!!)
  371 -g, --nogpg      Skip GPG signature verification (beware!)
  372 -h               Short help
  373 --help           Show this help screen
  374 --interactive    Interactive mode (ask before downloading/installing a package)
  375 --inversecolor   To see color on black-on-white terminals
  376 --language x     Use the given language for descriptions (e.g. german or french)
  377 --limit-rate x   Limit downloads to x kb/sec
  378 -n, --nodownload Do not attempt to download RPM files
  379 --nocache        Do not use the update description cache
  380 --nocheckdeleted Do not check for deleted files still in use at end of run
  381 --nocolor        Do not use colored output
  382 --nocompatible   Don't try to be compatible to YOU. See man page fou4s(1)
  383 --nodeps         Don't make RPM dependency checks (DANGEROUS!)
  384 --nodeltarpms    Don't use delta RPMs if possible (only SuSE 9.2+)
  385 --nopatchrpms    Don't use patch RPMs if possible
  386 --nogenerated    Don't use generated package descriptions
  387 --noproxy        Don't use http_proxy/ftp_proxy (from environment var.)
  388 -o               Skip optional packages (process everything else)
  389 --older-than x   Only show packages older than x days
  390 --only           Only process specified RPMs, see -f
  391 --product x      Update for SuSE Business product (e.g. eMail-Server)
  392 --proxy x        Use "x" as proxy server. Format is http://host:port/
  393 --proxydigest    Use digest authentication with proxy (curl only!)
  394 --proxyuser user Use username "user" for HTTP proxy (if required)
  395 --proxypasswd pw Use password "pw" for HTTP proxy (if required)
  396 -q, --quiet      Quiet mode (for cron-jobs)
  397 -r, --remove     Remove downloaded packages after successful update
  398 -s, --security   Only process security updates (nothing else)
  399 --safemode       Don't check signatures and disable install triggers (faster)
  400 --src rpm1,...   Download source RPM for given packages
  401 --suseuser x     Username for http auth (for business products)
  402 --susepasswd x   Password for http auth (for business products)
  403 --suseversion    Override version autodetect (get packages for other SuSE rel.)
  404 --usecurl        Use curl instead of wget
  405 --usedir         Use directory.X files from YOU (see fou4s(1))
  406 -v, --verbose    Verbose mode (twice for even more verbosity)
  407 --version        Show version information
  408 -w               Update /etc/suseservers (only valid with --server)
  409 _EOF
  410 # --noresume       Don't resume downloads (delete old files first)
  411     exit 0
  412 } # showUsage
  413 
  414 
  415 ################################ checkParameters
  416 # processes fou4s command line parameters
  417 # UsedBy: main
  418 # Modifies: a lot
  419 # parameters:
  420 # $*: command line parameters to fou4s
  421 function checkParameters()
  422 {
  423     while [[ $# -gt 0 ]] ; do # parameter checking
  424         case "$1" in
  425             -a)
  426                 INSTMODE=0
  427                 shift ;;
  428             --acceptpreinstallinfo)
  429                 ACCEPTPREINSTALLINFO=1
  430                 shift ;;
  431             --all)
  432                 PATCHRPMS=0 # don't use patch rpms when getting all packages
  433                 GETALL=1
  434                 [[ $USECACHE -ge 2 ]] && USECACHE=1 # only use level-1 cache (level-2 is invalid)
  435                 shift ;;
  436             --allnew)
  437                 PATCHRPMS=0 # don't use patch rpms when getting all packages
  438                 GETALL=1
  439                 GETALLNEW=1
  440                 [[ $USECACHE -ge 2 ]] && USECACHE=1 # only use level-1 cache (level-2 is invalid)
  441                 shift ;;
  442             --arch)
  443                 ARCH=$2
  444                 MACHINEARCH=$2
  445                 FORCEDARCH=$2
  446                 shift 2 ;;
  447             --auto)
  448                 DOINSTALL=1 # installs only auto mode packages
  449                 QUIET=1   # quiet is for -u (not used anywhere else)
  450                 VERBOSE=1 # verbose is for -e (show update descriptions)
  451                 AUTOMODE=1 UPDATEPACKAGELIST=1 DOWNLOAD=1
  452                 shift ;;
  453             -b|--benchmark)
  454                 BENCHMARK=1
  455                 shift ;;
  456             --buildtime)
  457                 USEBUILDTIME=1
  458                 shift ;;
  459             -c)
  460                 SUSECONFIG=0
  461                 shift ;;
  462             --checkdeleted)
  463                 CHECKONLYDELETED=1
  464                 shift ;;
  465             --checkfou4s)
  466                 CHECKFOU=1
  467                 shift ;;
  468             --cleancache)
  469                 CLEANCACHE=1
  470                 shift ;;
  471             --commonfuncs)
  472                 COMMONFUNCS=1
  473                 shift ;;
  474             --cronserver)
  475                 CRONINST=1
  476                 CRONSERVER=1
  477                 shift ;;
  478             --cronworkstation)
  479                 CRONINST=1
  480                 CRONWORKSTATION=1
  481                 shift ;;
  482             -d)
  483                 DOWNLOAD=1
  484                 shift ;;
  485             -e|--evaluate)
  486                 CHECKONLY=1
  487                 shift ;;
  488             --end)
  489                 INSTMODE=2
  490                 shift ;;
  491             --exclude)
  492                 EXCLUDELIST="$EXCLUDELIST $2" # multiple --exclude's should be legal
  493                 shift 2 ;;
  494             --exportx) # the appended x is a hack for broken vim colors in getopt
  495                 EXPORTFILE=$2
  496                 EXPORT=1
  497                 DOINSTALL=1 # is skipped later, but needed for storing in tar file
  498                 DOWNLOAD=1
  499                 SUSECONFIG=0
  500                 USEDELTARPMS=0 # delta rpms don't work for remote machines
  501                 shift 2 ;;
  502             -f)
  503                 USERRPMS="$USERRPMS $2"
  504                 shift 2 ;;
  505             --fixperm)
  506                 FIXPERMS=1
  507                 shift ;;
  508             --force)
  509                 GLOBALRPMOPTS="$GLOBALRPMOPTS --force"
  510                 shift ;;
  511             -g|--nogpg)
  512                 SKIPGPG=1
  513                 shift ;;
  514             --getpackagedescriptions)
  515                 GET81PACKAGEDESCRIPTIONS=1
  516                 shift ;;
  517             -h)
  518                 showUsageShort ;; # no shift necessary, function makes exit
  519             --help)
  520                 showUsage ;; # no shift necessary, function makes exit
  521             --host)
  522                 HOSTNAME=${2##*@}
  523                 HOSTEXEC="ssh $2"
  524                 CHECKDELETED=0 # cannot check for deleted files on remote servers!
  525                 USEDELTARPMS=0 # delta rpms don't work for remote machines
  526                 shift 2 ;;
  527             -i|--install|--upgrade)
  528                 DOINSTALL=1 DOWNLOAD=1 CHECKONLY=0
  529                 shift ;;
  530             --import)
  531                 IMPORTFILE=$2
  532                 IMPORT=1
  533                 shift 2 ;;
  534             --interactive)
  535                 INTERACTIVE=1
  536                 shift ;;
  537             --inversecolor)
  538                 INVERSE=1
  539                 shift ;;
  540             -l|--list)
  541                 LISTAVAILRPMS=1
  542                 USECACHE=1
  543                 USEPROGRESS=0
  544                 shift ;;
  545             --language)
  546                 LANGUAGE=$2
  547                 shift 2 ;;
  548             --limit-rate)
  549                 LIMIT=$2
  550                 shift 2 ;;
  551             -n|--nodownload)
  552                 DOWNLOAD=0
  553                 [[ $AUTOMODE -eq 0 ]] && UPDATEPACKAGELIST=0
  554                 shift ;;
  555             --nocache)
  556                 USECACHE=$((USECACHE-1))
  557                 [[ $USECACHE -lt 0 ]] && USECACHE=0
  558                 shift ;;
  559             --nocheckdeleted)
  560                 CHECKDELETED=0
  561                 shift ;;
  562             --nocolor)
  563                 COLOR=0
  564                 shift ;;
  565             --nocompatible)
  566                 COMPATIBLE=0
  567                 shift ;;
  568             --nodeps)
  569                 GLOBALRPMOPTS="$GLOBALRPMOPTS --nodeps"
  570                 shift ;;
  571             --nodeltarpms)
  572                 USEDELTARPMS=0
  573                 shift ;;
  574             --nopatchrpms)
  575                 PATCHRPMS=0
  576                 shift ;;
  577             --noprogress)
  578                 USEPROGRESS=0
  579                 shift ;;
  580             --noresume)
  581                 NORESUME=1
  582                 shift ;;
  583             --nogenerated)
  584                 GENERATED=0
  585                 shift ;;
  586             --noproxy)
  587                 unset http_proxy
  588                 unset ftp_proxy
  589                 shift ;;
  590             -o)
  591                 SKIPOPTIONAL=1
  592                 shift ;;
  593             --offline)
  594                 OFFLINE=1
  595                 SUSEVERSION="*[0-9]"
  596                 shift ;;
  597             --older-than)
  598                 if [[ $2 -ge 1 && $2 -lt 10000 ]] ; then
  599                     DAYSOLDER=$2
  600                 else
  601                     myError 0 "Invalid number of days: $2"
  602                     exit 2 
  603                 fi
  604                 shift 2 ;;
  605             --only)
  606                 ONLYINSTALLEDUSERRPMS=1
  607                 shift ;;
  608             --product)
  609                 SUSEPRODUCT=$2
  610                 VERSIONOVERRIDE=1
  611                 shift 2 ;;
  612             --proxy)
  613                 if [[ $2 == http://*([^\/])/ ]] ; then
  614                     export http_proxy=$2
  615                     export https_proxy=$2
  616                     export ftp_proxy=$2
  617                     if [[ $USERSYNCPROXY -eq 1 ]] ; then
  618                         RSYNC_PROXY=$2
  619                         RSYNC_PROXY=${RSYNC_PROXY##*://}
  620                         export RSYNC_PROXY=${RSYNC_PROXY%/}
  621                     fi
  622                 else
  623                     echo "Proxy must start with http:// and end with / (e.g. http://proxy:8080/)"
  624                     exit 2
  625                 fi
  626                 shift 2 ;;
  627             --proxy-digest|--proxydigest)
  628                 PROXYDIGEST=1
  629                 shift ;;
  630             --proxyuser)
  631                 PROXYUSER=$2
  632                 shift 2 ;;
  633             --proxypasswd)
  634                 PROXYPASS=$2
  635                 shift 2 ;;
  636             -q|--quiet)
  637                 VERBOSE=0 QUIET=1
  638                 shift ;;
  639             -r|--remove)
  640                 REMOVE=1
  641                 shift ;;
  642             -s|--security)
  643                 SECURITY=1
  644                 GENERATED=0 # speed up checking a little bit
  645                 shift ;;
  646             --safemode)
  647                 SAFEMODE=1
  648                 shift ;;
  649             --server)
  650                 UPDATESERVERLIST=1
  651                 shift ;;
  652             --src|--source)
  653                 SRCRPMS=$2
  654                 shift 2 ;;
  655             --suseuser)
  656                 HTTPUSER=$2
  657                 shift 2 ;;
  658             --susepasswd|susepassword)
  659                 HTTPPASSWD=$2
  660                 shift 2 ;;
  661             --suseversion)
  662                 SUSEVERSION=$2
  663                 NODOTSUSEVERSION=${SUSEVERSION//./}
  664                 VERSIONOVERRIDE=1
  665                 shift 2 ;;
  666             --testmode)
  667                 TESTMODE=1
  668                 shift ;;
  669             -u|--update)
  670                 UPDATEPACKAGELIST=1
  671                 shift ;;
  672             --usecurl|--use-curl)
  673                 USECURL=1
  674                 USEDIR=1
  675                 shift;;
  676             --usedir)
  677                 USEDIR=1
  678                 shift ;;
  679             -v|--verbose)
  680                 QUIET=0 VERBOSE=$((VERBOSE+1))
  681                 shift ;;
  682             --version)
  683                 echo "fou4s v$FOUVERSION  (c) 2002-2009 Markus Gaugusch <fou4s@gaugusch.at>"
  684                 exit ;;
  685             -w)
  686                 UPDATESUSESERVERS=1
  687                 shift ;;
  688             --)
  689                 shift # skip "--"
  690                 USERRPMS="$USERRPMS $*" # eat up all remaining params
  691                 [[ $# -ge 1 && $ONLYINSTALLEDUSERRPMS -eq 0 && $USECACHE -eq 2 ]] \
  692                     && USECACHE=1 
  693                     # level 2 cache is invalid with user specified rpms
  694                 set -- # set them to null to be explicit
  695                 break ;;
  696             *)
  697                 myError 0 "Error: Unkown option: $1 (use -h for help)"
  698                 exit 3 ;;
  699         esac
  700     done
  701 } # checkParameters
  702 
  703 
  704 ################################ checkOption
  705 # Verifies one config file option
  706 # Parameters:
  707 # $1 Value from config file
  708 # $2 Option name
  709 # $3 original value
  710 # $4 If it is "bool", only 0/no/false or 1/yes/true is valid
  711 #    If it is "range", parameters $4/$5 are used
  712 # $5 start range
  713 # $6 end range
  714 function checkOption()
  715 {
  716     local optionvalue="$1" option="$2" defaultvalue="$3" type="$4"
  717     local rangestart="$5" rangeend="$6"
  718     if [[ $type == bool ]] ; then
  719         case "$optionvalue" in
  720         0|false|no|off)
  721             echo 0
  722             myEcho 3 Found bool option $option with value 0 >&2 ;;
  723         1|true|yes|on)
  724             echo 1
  725             myEcho 3 Found bool option $option with value 1 >&2 ;;
  726         *)
  727             echo "$defaultvalue"
  728             myError 0 "ERROR: Invalid value for $option in config file $CONFIGFILE." >&2
  729             myError 0 "Value must be 0/off or 1/on. Using default $defaultvalue" >&2
  730         esac
  731     elif [[ $type == range ]] ; then
  732         if [[ $optionvalue -ge $rangestart && $optionvalue -le $rangeend ]] ; then
  733         myEcho 3 "Found range option $option with value $optionvalue" >&2
  734             echo "$optionvalue"
  735         else
  736             echo "$defaultvalue"
  737             myError 0 "ERROR: Invalid value for $option in config file $CONFIGFILE." >&2
  738             myError 0 "Value must be $rangestart..$rangeend, Using default $defaultvalue" >&2
  739         fi
  740     else
  741         echo "$optionvalue"
  742         myEcho 3 "Found option $option with value(s)" $optionvalue >&2
  743     fi
  744 } # checkOption
  745 
  746 
  747 ################################ fixperms
  748 # Fixes permissions of package description file on SuSE 8.1+ for group fou4s
  749 function fixperms()
  750 {
  751     local answer allow=0 dir
  752     if [[ $EUID -ne 0 ]] ; then
  753         myError 0 "Error: you must be root to fix permissions!"
  754         exit 4
  755     fi
  756     echo -e $COL_YELLOW
  757 cat << _EOF
  758 Allowing fou4s group members to access the description file is not considered
  759 to be harmful to the system security in any way. It just allows fou4s to be run
  760 by a non-root user to download packages. Answering no to the following question
  761 will remove the rights.
  762 _EOF
  763     echo -e $COL_NORM
  764     myRead "Allow group fou4s access to the description file (y/n)?"
  765     if [[ $answer == y ]] ; then
  766         if [[ `grep ^fou4s: /etc/group` != fou4s:* ]] ; then
  767             myRead "Group fou4s does not exist, add it (y/n)?"
  768             [[ $answer != y ]] && echo Aborting ... && return
  769             groupadd fou4s
  770             passwd -g fou4s -r # remove group password
  771         fi
  772         echo "Allowing group fou4s members to access to $PACKAGES81 ..." | fmt -$COLUMNS
  773         allow=1
  774     else
  775         echo "Removing rights to access package description file ..."
  776     fi
  777     cd /var/adm
  778     for dir in YaST InstSrcManager ; do
  779         if [[ $allow -eq 1 ]] ; then
  780             mode=g+x
  781             group=fou4s
  782         else
  783             mode=g-x
  784             group=root
  785         fi
  786         chgrp $group YaST YaST/InstSrcManager
  787         chmod $mode YaST YaST/InstSrcManager
  788         cd YaST/InstSrcManager
  789         chgrp $group IS_CACHE_0x* IS_CACHE/0x*/DATA IS_CACHE/0x*/DATA/descr
  790         chmod $mode IS_CACHE_0x* IS_CACHE/0x*/DATA IS_CACHE/0x*/DATA/descr
  791         chgrp $group $PACKAGES81
  792     done
  793     exit 0
  794 } # fixperms
  795 
  796 ################################ installCronjob
  797 # Copy example cronjob to /etc/cron*, depending on workstation or server
  798 # config to cron.daily or cron.d
  799 function installCronjob()
  800 {
  801     local cronfile time crondest ok=0 dirs="examples /usr/share/doc/packages/fou4s ."
  802     local hour=25 min=99
  803     if [[ $EUID -ne 0 ]] ; then
  804         myError 0 "ERROR: You must run fou4s as root!"
  805         exit 2
  806     fi
  807     umask g-w # for safety - fou4s members should not edit cronjobs!
  808     for dir in $dirs ; do
  809         if [[ -f $dir/fou4s-crontab ]] ; then
  810             oldjob=/etc/cron.d/*fou4s*tab
  811             for f in $oldjob ; do
  812                 [[ -f $f ]] && myWarn 0 "Warning: Old cron job detected: $f"
  813             done
  814             if [[ $CRONSERVER -eq 1 ]] ; then
  815                 while [ $ok -eq 0 ] ; do
  816                     echo -n "Please enter time for update checking (e.g. 3:43): "
  817                     read time
  818                     time=${time//[^0-9:]/}
  819                     hour=${time%%:*}
  820                     min=${time##*:}
  821                     [[ -n $min && -n $hour && $hour -ge 0 && $hour -le 23 && \
  822                         $min -ge 0 && $time = *:* && $min -le 59 ]] || continue
  823                     ok=1
  824                     mmin=$((min+10))
  825                     mhour=$hour
  826                     if [[ $min -ge 50 ]] ; then
  827                         mhour=$((mhour+1))
  828                         [[ $mhour -gt 23 ]] && mhour=0
  829                         mmin=$((min+10-60))
  830                     fi
  831                 done
  832                 if [[ -f /etc/cron.d/fou4s ]] ; then
  833                     myWarn 0 -n "File /etc/cron.d/fou4s already exists - overwrite (y/n)? "
  834                     myRead ""
  835                     [[ $answer != y ]] && echo "Not updating crontab ..." && break
  836                 fi
  837                 cat $dir/fou4s-crontab | sed "s/^5 6/$min $hour/g" | \
  838                     sed "s/^17 6/$mmin $mhour/g" > /etc/cron.d/fou4s
  839             else # workstation
  840                 for c in daily monthly ; do
  841                     if [[ -f /etc/cron.$c/fou4s ]] ; then
  842                         myWarn 0 -n "File /etc/cron.$c/fou4s already exists - overwrite (y/n)? "
  843                         myRead ""
  844                         [[ $answer != y ]] && continue
  845                     fi
  846                     cp $dir/fou4s-crontab.workstation.$c /etc/cron.$c/fou4s
  847                     chmod +x /etc/cron.$c/fou4s
  848                 done
  849             fi
  850             ok=1
  851             myNote 0 "Crontab installation finished! Fou4s will now check for updates and download them automatically every day. Notifications about new updates are sent as mail to root." | fmt -$COLUMNS
  852             break
  853         fi
  854     done
  855     if [[ $ok -eq 0 ]] ; then
  856         echo "Could not find cronjob templates in one of the follwing directories:"
  857         echo $dirs
  858     fi
  859     exit 0
  860 } # installCronjob
  861 
  862 ################################ get81packagedescriptions
  863 # Get "packages" file for suse 8.1+. It contains architecture information
  864 # for packages that are not installed.
  865 # This is needed, because the new update descriptions of 8.1+ don't
  866 # contain arch information!
  867 function get81packagedescriptions()
  868 {
  869     local server
  870     for server in $SERVERLIST ; do
  871         if [[ $server == *tp://* ]] && \
  872             [[ $server != *$ARCH/update/$SUSEPRODUCT$SUSEVERSION* ]] ; then
  873             echo Getting package description file from $server ... | fmt -80
  874             getremotefile --output-document $CACHEDIR/descr_packages.$SUSEVERSION $server/$ARCH/$SUSEVERSION/suse/setup/descr/packages
  875             break
  876         fi
  877     done
  878     exit 0
  879 } # get81packagedescriptions
  880 
  881 
  882 ################################ showProgress
  883 # Shows a progress bar and a percentage value
  884 # UsedBy: checkPackage, processServerList
  885 # Parameters:
  886 # $1: index
  887 # $2: max
  888 # $3: special:
  889 #     if 1, then show bar with 100%
  890 #     if 2, then show bar filled with "o", not "#"
  891 function showProgress()
  892 {
  893     local index=$1 max=$2 len special=$3 bar bl restlen
  894     local percent=$((index*100/max))
  895     [[ $special == 1 ]] && percent=100
  896     bl="................................." # blank bar
  897     bar="#################################" # filled bar
  898     if [[ $NODOTSUSEVERSION -ge 110 ]] ; then
  899         if [[ $3 == 2 ]] ; then
  900              bar="ooooooooooooooooooooooooooooooooo" # pass 1 bar
  901              pass="1/2"
  902         else
  903              bl="ooooooooooooooooooooooooooooooooo" # pass 2 bar
  904              pass="2/2"
  905         fi
  906     fi
  907     len=$((percent/3))
  908     restlen=$((33-len))
  909     [[ $restlen -lt 0 ]] && restlen=0
  910     echo -n -e "$server: Checking $pass [${bar:0:$len}${bl:0:$restlen}] $percent %   \r"
  911     [[ $special == 1 ]] && echo # go to next line when forcing 100% ...
  912 } # showProgress
  913 
  914 
  915 ################################# myRecode
  916 # SuSE update descriptions are UTF8 encoded. Usual Linux console
  917 # and xterms are not configured to UTF8. Therefore we show it in
  918 # ISO-8859-15 (western european, with euro symbol) charset
  919 function myRecode()
  920 {
  921     [[ $DORECODE -eq 1 ]] && recode UTF8..ISO-8859-15 
  922     tr '' '\n' | tr '' '='
  923     if [[ $NODOTSUSEVERSION -ge 110 ]] ; then
  924         sed 's/&lt;/</g' 
  925         sed 's/&gt;/>/g' 
  926         sed 's/&amp;/&/g' 
  927     fi
  928 }
  929 
  930 
  931 ################################ getremotefile
  932 # Calls wget and deletes unnecessary index.html
  933 # Parameters:
  934 # $*: wget parameters
  935 function getremotefile()
  936 {
  937     local f ret params user pass verbose=0 cont=0 cache=1 url opts quiet=0 recursive=0 bar=0
  938     local outfile
  939     params=`getopt -l user:,pass:,output-document:,verbose,bar,continue,nocache,quiet,recursive -o u:p:o:vbcnqr -n 'getremotefile' -- "$@"`
  940     myEcho 2 "getremotefile $*"
  941     test $? -ne 0 && myError 0 "Internal error in getremotefile. Info: $@" && exit 2
  942     while [[ $# -gt 0 ]] ; do
  943         case "$1" in
  944             -u|--user) user=$2 ; shift ;;
  945             -p|--pass) pass=$2 ; shift ;;
  946             -o|--output-document) outfile=$2 ; shift ;;
  947             -v|--verbose) verbose=1 ;;
  948             -b|--bar) bar=1 ; shift ;;
  949             -c|--continue) cont=1 ;;
  950             -n|--nocache) cache=0 ;;
  951             -q|--quiet) quiet=1 ;;
  952             -r|--recursive) recursive=1 ;;
  953             --) url=$2 ; shift ;;
  954             *) url=$1 ;;
  955         esac
  956         shift
  957     done
  958 
  959     for f in index.htm* *\??=? ; do # remove index.html?x=y too
  960         [[ -f $f ]] && rm -f "$f"
  961     done
  962     if [[ $USECURL -eq 0 ]] ; then ############ wget
  963         [[ -n $user ]] && opts="$opts --http-user=$user"
  964         [[ -n $pass ]] && opts="$opts --http-passwd=$pass"
  965         [[ -n $outfile ]] && opts="$opts -O $outfile"
  966         [[ $verbose -eq 0 && ($VERBOSE -eq 0 || $QUIET -eq 1) ]] && opts="$opts -q"
  967         [[ $cont -eq 1 ]] && opts="$opts -c"
  968         [[ $recursive -eq 1 ]] && opts="$opts -r"
  969         [[ $cache -eq 0 ]] && opts="$opts --cache=off"
  970         [[ "$url" == "-" ]] && opts="$opts -i -" && url=
  971 
  972         if [[ $NORESUME -eq 1 ]] ; then
  973             o=$outfile
  974             if [[ -z $o ]] ; then
  975                 echo "fixme $url `basename "$url"`"
  976                 o=`basename "$url"`
  977             else
  978                 echo "fixme outfile $o in $PWD"
  979             fi
  980             if [[ -f $o ]] ; then
  981                 myEcho 2 "Removing $outfile (don't want to work with incomplete files)"
  982                 echo rm $outfile
  983             fi
  984         #else
  985         #   if [[ `tail -1 $o` == -----END PGP SIGNATURE----- ]] ; then
  986         #       continue
  987         #   fi
  988         fi
  989         if [[ $VERBOSE -lt 3 ]] ; then
  990             # suppress common errors, like 416 and timestamping turned off.
  991             # The index.html?x=y are also suppressed for cleaner output
  992             if [[ $bar -eq 0 ]] ; then
  993                 wget $GLOBALWGETOPTS $opts $url 2>&1 | grep --line-buffered -v "\(time-stamps turned off\|\?.=.\|ERROR 416: Requested Range Not Satisfiable\|ERROR 416: Unknown\)"
  994             else
  995                 wget $GLOBALWGETOPTS $opts $url
  996             fi
  997             ret=${PIPESTATUS[0]} # thanks to lge
  998         else # on debug level 3 I want to see it all!
  999             wget $GLOBALWGETOPTS $opts $url
 1000             ret=$?
 1001         fi
 1002     else ########## curl
 1003         [[ -n $user && -n $pass ]] && opts="$opts -u $user:$pass"
 1004         [[ -n $outfile ]] && opts="$opts -o $outfile"
 1005         [[ $VERBOSE -eq 0 || $QUIET -eq 1 ]] && opts="$opts -s"
 1006         [[ $VERBOSE -gt 1 ]] && opts="$opts -v" && outputfilter="|grep -v HTTP.server.doesn.t.seem.to.support.byte.ranges"
 1007         [[ $cont -eq 1 ]] && opts="$opts -C -"
 1008         [[ $recursive -eq 1 ]] && opts="$opts " # fixme
 1009         # [[ $cache -eq 0 ]] && opts="$opts --nocache"
 1010         if [[ "$url" == "-" ]] ; then
 1011             opts="$opts -K -"
 1012             url=
 1013         fi
 1014         [[ -z $outfile && -n $url ]] && opts="$opts -O"
 1015         if [[ -z $url ]] ; then
 1016             eval 'grep -v "^$" | sed "s/$/\"/g" | sed "s#^#-O\nurl = \"#g" | \
 1017                 curl $GLOBALCURLOPTS $opts $url 2>&1' $outputfilter
 1018             ret=$?
 1019         else
 1020             eval 'curl $GLOBALCURLOPTS $opts $url 2>&1' $outputfilter
 1021             ret=$?
 1022         fi 
 1023     fi
 1024     f=index.htm*
 1025     [[ $1 == http://* && $f == index.htm\* ]] && USEDIR=1 && myNote 2 "Could not read directory from $server!"
 1026     for f in index.htm* *\??=? ; do # remove index.html?x=y too
 1027         [[ -f $f ]] && rm -f "$f"
 1028     done
 1029     return $ret
 1030 } # getremotefile
 1031 
 1032 
 1033 ################################ checkDeleted
 1034 # check for deleted files that are still in use
 1035 function checkDeleted()
 1036 {
 1037     local p service
 1038     [[ $QUIET -eq 0 ]] && myEcho 1 "Checking for deleted files ..."
 1039 #   PROCS=`lsof -n 2>/dev/null | grep RPMDELETE | grep -v fou4s | \
 1040 #       cut -d " " -f 1 | sort | uniq`
 1041     PROCS=$( lsof -n -F pcn 2>/dev/null |
 1042         sed -ne $'/^p/h;/^c/H;
 1043         /^n.*\(-RPMDELETE\|;\)/{
 1044         x;s/^.//;
 1045         s/\\\n./\t/g;p;
 1046         :1;n;/^p/!b1;h;
 1047         }'
 1048     ) # get the pid, too
 1049     PROCS="`echo "$PROCS" | grep -v "\<fou4s\>"`"
 1050     if [[ -n $PROCS ]] ; then
 1051         echo
 1052         myWarn 0 "WARNING"
 1053         myWarn 0 "======="
 1054         echo
 1055         myWarn 0 "The following processes are accessing deleted files:"
 1056         echo
 1057         myWarn 0 "  PID  COMMAND"
 1058         echo "$PROCS" | while read pid name; do
 1059             testname=${name%d}
 1060             service=$( cd /etc/init.d && ls -1d * | grep -v -F '.rpmsave' \
 1061         | xargs -- grep -s -lE \
 1062     "(^[A-Z0-9]+_BIN=|^DAEMON=|\<startproc\>.*|^[A-Z0-9_]+=)([^ ]+/)?\<$testname" | head -1
 1063             ) # the first two and the last pattern are redundant ...
 1064             [[ -n $service ]] && service="(try /etc/init.d/$service restart)"
 1065             [[ -n $service ]] && which rc$service &>/dev/null && service="(try rc$service restart)"
 1066             [[ $name == mingetty ]] && service="(try killall mingetty)"
 1067             [[ $name == java ]] && service="(try rctomcat restart)"
 1068             printf "${COL_RED}%5i  %-15s ${COL_CYAN}%s${COL_NORM}\n" "$pid" "$name" "$service"
 1069         done
 1070         echo
 1071         myWarn 0 "Please restart these processes to finish the update."
 1072         echo
 1073         myNote 0 "You can check for used files using the command"
 1074         myNote 0 "fou4s --checkdeleted $COL_NORM(can be abbreviated with --checkd)"
 1075         echo or using the command
 1076         myNote 0 "lsof -n | grep RPMDELETE"
 1077     fi
 1078 
 1079     if [[ $KERNELCHECK -eq 1 ]] ; then
 1080         KERNELVER=${KERNELVER//-default/}
 1081         KERNELVER=${KERNELVER//-smp/}
 1082         KERNELVER=${KERNELVER//-bigsmp/}
 1083         KERNELVER=${KERNELVER//-pae/}
 1084         reboot=0
 1085         newkernelver=`rpm -q --qf "%{VERSION}-%{RELEASE}" $KERNELPKG`
 1086         newkernelbuild=`rpm -q --qf "%{BUILDTIME}" $KERNELPKG`
 1087         if [[ -n $SUSEKERNELVER && -n $newkernelver && \
 1088             $SUSEKERNELVER != *$newkernelver* ]] ; then
 1089             reboot=1
 1090         elif [[ $NODOTSUSEVERSION -eq 82 ]] ; then
 1091             # this function is a bit heuristic: if the running kernel
 1092             # (/proc/version) is packaged less than 24 hours after it was built,
 1093             # we assume that it corresponds to the currently installed kernel
 1094             # package. This is because the version numbers are not compareable in
 1095             # some SuSE versions (8.2 has always 2.4.20-4GB, no matter what the
 1096             # RPM says).
 1097             runningkernelbuild="`cat /proc/version | sed 's/SMP //g'`"
 1098             runningkernelbuild=${runningkernelbuild##*#}
 1099             runningkernelbuild=${runningkernelbuild#* }
 1100             runningkernelbuild=`date "+%s" -d "$runningkernelbuild"`
 1101             # we use a little bit more than one day (would be 86400 secs)
 1102             # because it made problems with kernel 2.6.5-7.111
 1103             if [[ $((newkernelbuild - runningkernelbuild)) -gt 100000 ]] ; then
 1104                 reboot=1
 1105             fi
 1106             myEcho 2 "Running kernel build: $runningkernelbuild, Installed kernel build: $newkernelbuild"
 1107         fi
 1108         if [[ $KERNELVER.1 == $newkernelver || $KERNELVER.2 == $newkernelver || $KERNELVER.3 == $newkernelver ]] ; then
 1109             reboot=0 # bugfix for 64bit openSUSE 11.1 kernel, e.g. uname 2.6.27.19-3.2 vs. 2.6.27.19-3.2.1 RPM
 1110         fi
 1111 
 1112         if [[ $reboot -eq 1 ]] ; then
 1113             echo
 1114             myWarn 0 "The running kernel ($KERNELVER) is different from installed \
 1115 kernel ($newkernelver). You must reboot your machine to make the kernel update \
 1116 effective. If this notification is wrong, please contact fou4s@gaugusch.at and \
 1117 set KernelCheck=0 in fou4s.conf to disable it until a fix is available." \
 1118 | fmt -$COLUMNS
 1119         fi
 1120     fi
 1121     myEcho 3 "Done checking for deleted files ..."
 1122     return 0
 1123 } # checkDeleted
 1124 
 1125 
 1126 ################################ printUpdateInformation
 1127 # Shows detailed information about an update
 1128 # parameters:
 1129 # $1: patch description file
 1130 # $2: short description
 1131 function printUpdateInformation()
 1132 {
 1133     local txt txtlen line pkgdescfile=$1 shortdesc=$2 len len2
 1134     local lang gnal width=$((COLUMNS-1))
 1135     if [[ $VERBOSE -ge 1 ]] ; then
 1136         echo -e $COL_CYAN
 1137         line="======================================================================================================================================================================================================"
 1138         [[ $newbuildtime != 0 ]] && date="(`date -d "1970-01-01 $newbuildtime sec" "+%Y-%m-%d"`) "
 1139         txt=" Update Information for $COL_YELLOW${pkgdescfile##*/}$COL_CYAN $date"
 1140         txtlen=$((${#txt}-${#COL_YELLOW}-${#COL_CYAN}+1))
 1141         len=$(( $width-$txtlen ))
 1142         [[ $((len/2)) -ne $(( (len+1)/2 )) ]] && len2=$((len/2+1)) || len2=$((len/2))
 1143         len=$((len/2))
 1144         width=$((len+len2+txtlen)) # if width was odd
 1145         echo -e ${line:0:$len}$txt${line:0:$len2}
 1146         [[ -n $shortdesc ]] && echo -e $COL_WHITE$shortdesc$COL_CYAN | myRecode | sed 's/&quot;/"/g'
 1147         lang=$LANGUAGE gnal=$EGAUGNAL
 1148         if [[ $NODOTSUSEVERSION -lt 101 ]] ; then
 1149             checkLanguage "`awk "/Longdescription.$LANGUAGE:/,/$EGAUGNAL.noitpircsedgnol:/" $pkgdescfile`" || { lang=english gnal=Hsilgne ; }
 1150             awk "/Longdescription.$lang:/,/$gnal.noitpircsedgnol:/" $pkgdescfile \
 1151             | tr --delete '\r' \
 1152             | sed 's/^- -/\n- /g'| sed '1d;$d' | myRecode | fmt -$width | grep -v "^$"
 1153         else
 1154             #echo "$longdesc" | myRecode | tr --delete '\r' | sed 's/&quot;/"/g' | fmt -$width | grep -v "^$"
 1155             echo "$longdesc" | myRecode | sed 's/&quot;/"/g' 
 1156         fi
 1157         echo -e ${line:0:$width}$COL_NORM # show this line only in length of the above
 1158     #else
 1159     #   myNote 0 "----- Updates from $COL_YELLOW${pkgdescfile##*/}$COL_CYAN: "
 1160     fi
 1161     return 0
 1162 } # printUpdateInformation
 1163 
 1164 function showSummaryEntry()
 1165 {
 1166     local pre=$1 which=$2 txt=$3 size hdsize hdcomment="+"
 1167     if [[ ${COUNTER[$which]} -gt 0 ]] ; then
 1168         size=$((SIZES[$which]/1024))
 1169         hdsize=$((HDSIZES[$which]/1024))
 1170         dlsize=$((DLSIZES[$which]/1024))
 1171         [[ $hdsize -lt 0 ]] && hdsize=$((hdsize*-1)) && hdcomment="-"
 1172         [[ $hdsize -eq 0 ]] && hdcomment=""
 1173         #test $hdsize -eq 0 && hdsize="???"
 1174         printf "$pre$COL_YELLOW%3d$COL_NORM $txt$COL_YELLOW%6d${COL_NORM}kB   \
 1175 $COL_YELLOW%6s${COL_NORM}kB   $COL_YELLOW%6s${COL_NORM}kB\n" ${COUNTER[$which]}\
 1176  $size $hdcomment$hdsize $dlsize
 1177     fi
 1178     return 0
 1179 } # showSummaryEntry
 1180 
 1181 function showSummary()
 1182 {
 1183     local prod=${SUSEPRODUCT:=SuSE}
 1184     prod=${prod//\//}
 1185     echo
 1186     myEcho 0 "Update statistics for $prod $SUSEVERSION host $HOSTNAME (fou4s $FOUVERSION):"
 1187     if [ $DAYSOLDER -gt 0 ] ; then
 1188         myEcho 0 "Showing only updates older than $DAYSOLDER days"
 1189     fi
 1190     myEcho 0 "                               Size    After Upd.   To D/L"
 1191     showSummaryEntry "   " $_SECURITY    "${COL_RED}security$COL_NORM update(s)    "
 1192     showSummaryEntry "   " $_RECOMMENDED "${COL_CYAN}recommended$COL_NORM update(s) "
 1193     showSummaryEntry "   " $_YAST        "YaST2 update(s)       "
 1194     showSummaryEntry "   " $_OPTIONAL    "optional update(s)    "
 1195     showSummaryEntry "   " $_SCRIPT      "script(s)             "
 1196     showSummaryEntry "   " $_GENERATED   "generated update(s)   "
 1197     showSummaryEntry "" $_ALL "update(s), total         "
 1198 } # showSummary
 1199 
 1200 
 1201 ################################ getKernelVersion
 1202 # Get info about running SuSE-kernel
 1203 # UsedBy: updateRpmCache
 1204 # Parameters: none
 1205 function getKernelVersion()
 1206 {
 1207     local pkg version
 1208     pkg=`rpm -qf /boot/vmlinuz 2>/dev/null`
 1209     version="`grep "\((root@[-a-zA-Z0-9]*\.suse\.\|-default \|-smp \|-bigsmp \|-pae \)" < /proc/version`"
 1210     version=${version%%(*}
 1211     version=${version//Linux version }
 1212     if [[ $NODOTSUSEVERSION -lt 112 && $KERNELCHECK -eq 1 && `rpm -qf /boot/vmlinuz 2>/dev/null | wc -l` -gt 1 ]] ; then
 1213         myWarn 0 "More than one kernel is installed! Please set KernelCheck=0 in fou4s.conf or remove other kernels"|fmt -$COLUMNS
 1214         KERNELCHECK=0
 1215         KERNELBACKUP=0
 1216     elif [[ -z $pkg ]] ; then
 1217         myWarn 2 "No SuSE kernel installed - can't check Kernel updates"
 1218         KERNELCHECK=0
 1219         KERNELBACKUP=0
 1220     elif [[ -z $version ]] ; then
 1221         myWarn 2 "No SuSE kernel running - can't check Kernel updates"
 1222         KERNELCHECK=0
 1223         KERNELBACKUP=0
 1224     else
 1225         KERNELPKG=${pkg%%-[2-9]*}
 1226         SUSEKERNELVER=$version
 1227         myNote 2 "Found suse kernel $KERNELPKG $SUSEKERNELVER"
 1228     fi
 1229 }
 1230 
 1231 
 1232 ################################ updateRpmCache
 1233 # Make sourceable cache of rpm database
 1234 # UsedBy: main
 1235 # Parameters:
 1236 # $1: if this is "force", creation is forced
 1237 function updateRpmCache()
 1238 {
 1239     local force=0 ver rpmoutput
 1240     RPMCACHECOMPLETE=0
 1241     [[ $OFFLINE -eq 1 ]] && return || [[ -n $HOSTEXEC ]] && force=1
 1242     [[ $UPDATESERVERLIST -eq 1 ]] && return
 1243     [[ $1 == force ]] && force=1
 1244     [[ -z $HOSTEXEC && $RPMVER -eq 30 && /var/lib/rpm/packages.rpm -nt $RPMCACHE ]] && force=1
 1245     [[ -z $HOSTEXEC && $RPMVER -ge 40 && /var/lib/rpm/Packages -nt $RPMCACHE ]] && force=1
 1246     if [[ $RPMCACHE -nt /proc/self/cmdline ]] ; then
 1247         myWarn 0 "Warning: Time skew detected - fou4s cache newer than system time!"
 1248         cleanCache
 1249         force=1
 1250     fi
 1251     if [[ ! -f $RPMCACHE || $force -eq 1 ]] ; then
 1252         trap 'exec 1>&10-; myError 0 "updateRpmCache FAILED"; rm -f "$RPMCACHE.new; exit 13"' EXIT
 1253         set -e # exit if any of the below fails ...
 1254         myEcho 2 "Updating rpm cache"
 1255         query="%{NAME}='%{VERSION}-%{RELEASE} %{BUILDTIME} %{ARCH} %{SIZE}'\n"
 1256         [[ -n $HOSTEXEC ]] && query="\"$query\""
 1257         # by l.g.e
 1258         if [[ -z $HOSTEXEC ]] ; then
 1259             rpmoutput=`rpm -qa --queryformat "$query"`
 1260         else
 1261             myNote 2 "Getting RPM cache from remote host $HOSTNAME"
 1262             rpmoutput=`$HOSTEXEC -- "
 1263                 SuSE-release v1.2 2>/dev/null
 1264                 rpm -qa --queryformat "$query"
 1265             "`
 1266             ver=(`echo "$rpmoutput" | head -1`)
 1267             if [[ ${ver[0]} = SuSE-Release* ]] ; then
 1268                 SUSEVERSION=${ver[1]}
 1269                 NODOTSUSEVERSION=${ver[2]}
 1270                 ARCH=${ver[3]}
 1271                 SUSEPRODUCT=${ver[4]}
 1272                 if [[ ${ver[0]} = SuSE-Release-v1.1: ]] ; then
 1273                     KERNELVER=${var[5]} # only check kernelver with new suse-release
 1274                 elif [[ ${ver[0]} = SuSE-Release-v1.2: ]] ; then
 1275                     KERNELVER=${var[5]} # only check kernelver with new suse-release
 1276                     MACHINEARCH=${var[6]}
 1277                     VALIDARCHS=${ver[7]//+/ }
 1278                 fi
 1279                 RPMCACHE=$CACHEDIR/.cache.$HOSTNAME/rpmcache.$SUSEVERSION # rebuild
 1280                 myNote 2 "New SuSE-release: $SUSEPRODUCT $SUSEVERSION ($ARCH)"
 1281                 rpmoutput=`echo "$rpmoutput" | grep -v ^SuSE-Release`
 1282             else
 1283                 if [[ $VERSIONOVERRIDE -eq 0 ]] ; then
 1284                     myError 0 "Could not determine remote SuSE-release. Install at \
 1285 least fou4s 0.10 or override with --suseversion and --product"| fmt -$COLUMNS
 1286                 fi
 1287             fi
 1288         fi
 1289         echo "RPMCACHEVERSION=$RPMCACHEVER" > $RPMCACHE.new
 1290         echo "$rpmoutput" |
 1291         sed 'h;              # remember line
 1292         s/^.*=/=/;           # cut
 1293         x;                   # exchange
 1294         s/=.*$//;            # cut
 1295         s/[^A-Za-z0-9_]/_/g; # valid identifier
 1296         s/^/pkg_/;           # prefix
 1297         G;                   # append again
 1298         s/'$'\\\n''//;       # newer sed would say s/\n//;' >> $RPMCACHE.new
 1299         # fail if either rpm or sed had problems
 1300         [[ -z ${PIPESTATUS[*]//0} ]]
 1301         echo "SUSEVERSION=$SUSEVERSION" >> $RPMCACHE.new
 1302         echo "NODOTSUSEVERSION=$NODOTSUSEVERSION" >> $RPMCACHE.new
 1303         echo "ARCH=$ARCH" >> $RPMCACHE.new
 1304         echo "MACHINEARCH=$MACHINEARCH" >> $RPMCACHE.new
 1305         echo "SUSEPRODUCT=$SUSEPRODUCT" >> $RPMCACHE.new
 1306         echo "HOSTNAME=$HOSTNAME" >> $RPMCACHE.new
 1307         echo "RPMCACHECOMPLETE=1" >> $RPMCACHE.new
 1308         echo "VALIDARCHS=\"$VALIDARCHS\"" >> $RPMCACHE.new
 1309         mv $RPMCACHE.new $RPMCACHE # atomic. RPMCACHECOMPLETE should no longer be necessary
 1310         set +e # restore default handling
 1311         trap - EXIT
 1312         rm -f $DESCCACHE 2>/dev/null # remove old patch description cache for safety
 1313         DESCCACHE=$CACHEDIR/.cache.$HOSTNAME/descriptioncache.$SUSEVERSION # rebuild
 1314     else
 1315         myEcho 2 "Not updating rpm cache"
 1316     fi
 1317 } # updateRpmCache
 1318 
 1319 ################################ updateDescriptionCache
 1320 # Make sourceable cache of update descriptions
 1321 function updateDescriptionCache()
 1322 {
 1323     local p p1
 1324     rm -f $DESCCACHE.new
 1325     # not writeable -> abort
 1326     echo "DESCRIPTIONCACHE_VERSION='1.4'" 2>/dev/null >$DESCCACHE.new || return 1
 1327     echo "DC_ARCH='$ARCH'" >> $DESCCACHE.new
 1328     echo "DC_PRODUCT='$SUSEPRODUCT'" >> $DESCCACHE.new
 1329     echo "DC_VERSION='$SUSEVERSION'" >> $DESCCACHE.new
 1330     echo "DC_SERVERLIST=\"$SERVERLIST\"" >> $DESCCACHE.new
 1331     echo "DC_LANGUAGE='$LANGUAGE'" >> $DESCCACHE.new
 1332     for p in ${!packageinfo_*} ${!package_*} ${!longdesc_*} ${!license_*} ${!shortdesc_*} ${!dlfile1_*} ${!server1_*} ; do
 1333         p1=${!p} 
 1334         echo "$p='${p1//\'/\"}'" >> $DESCCACHE.new
 1335     done
 1336     mv $DESCCACHE.new $DESCCACHE
 1337     return 0
 1338 } # updateDescriptionCache  
 1339 
 1340 
 1341 ################################ cleanCache
 1342 function cleanCache()
 1343 {
 1344     rm -rf $CACHEDIR/.cache.$HOSTNAME
 1345     mkdir $CACHEDIR/.cache.$HOSTNAME
 1346     return 0
 1347 } # cleanCache
 1348 
 1349 
 1350 ################################ parsePatchesXML
 1351 # Parse the "patches.xml" file from SuSE 10.1 .. 10.3
 1352 # Parameters:
 1353 # $1:
 1354 # -f: get filenames (patch-*.xml)
 1355 # -c: get filenames with bad checksums
 1356 # $2: prefix for all printed filenames
 1357 
 1358 function parsePatchesXML()
 1359 {
 1360     local opt=$1 prefix=$2 filesum checksum
 1361 
 1362     cat patches.xml | $XMLP | while read line ; do
 1363         case $line in
 1364         /patches/patch/checksum=*)
 1365             checksum=${line##*=}
 1366         ;;
 1367         /patches/patch/location/@href=*)
 1368             patch=${line##*/}
 1369             if [[ -f $patch ]] ; then
 1370                 filesum=`sha1sum $patch`
 1371                 filesum=${filesum%% *}
 1372             fi
 1373             [[ $filesum != $checksum || $opt == -f ]] && echo $prefix$patch
 1374             [[ $filesum != $checksum && -f $patch ]] && rm $patch
 1375         ;;
 1376         esac
 1377     done 
 1378 
 1379 }
 1380 
 1381 
 1382 ################################ getDirectory
 1383 # Get all files inside of all 'directory' files in the current directory
 1384 # Parameters:
 1385 # $1: Server URL, including "patches" directory
 1386 # $2: Special fou4s update option: -f (only use for fou4s updates)
 1387 function getDirectory()
 1388 {
 1389     local dir p url=$1
 1390     if [[ $NODOTSUSEVERSION -lt 101 ]] ; then
 1391         for dir in directory directory.* ; do
 1392             [[ -f $dir ]] || continue
 1393             if grep -q '\(<\|`\|\$\|\.\.\|/\)' $dir ; then
 1394                 myWarn 0 "Invalid content found in $PWD/$dir" 
 1395                 rm -f $dir
 1396                 continue
 1397             fi
 1398             grep -v "^$" $dir | sed "s#^#$url#g" | getremotefile $AUTHOPTS $downloadopts -
 1399             [[ $2 == -f ]] && break
 1400         done
 1401     fi
 1402     if [[ $NODOTSUSEVERSION -lt 110 && $NODOTSUSEVERSION -ge 101 ]] ; then
 1403         parsePatchesXML -c $url | getremotefile $AUTHOPTS $downloadopts -
 1404     fi
 1405 } # getDirectory
 1406 
 1407 
 1408 ################################ betterArch
 1409 # Check if one of the two given arch's is better than the other
 1410 # Parameters:
 1411 # $1: base arch
 1412 # $2: arch for comparison
 1413 # Return Value:
 1414 # 0 if $1 is better or equal to $2, 1 otherwise (and in case of error)
 1415 function betterArch()
 1416 {
 1417     local a i=0 a1=0 a2=0
 1418     [[ $1 == $2 ]] && return 0
 1419     if [[ $1 == @(${VALIDARCHS// /|}) && $2 == @(${VALIDARCHS// /|}) ]] ; then
 1420         for a in $VALIDARCHS ; do
 1421             i=$((i+1))
 1422             [[ $a == $1 ]] && a1=$i
 1423             [[ $a == $2 ]] && a2=$i
 1424         done
 1425         [[ $a1 -lt $a2 ]] && return 0
 1426     fi
 1427     return 1
 1428 }
 1429 
 1430 
 1431 ################################ updatePackagelist
 1432 # Get the package list from the server
 1433 # Parameters:
 1434 # $1: server name (e.g. ftp.gwdg.de)
 1435 # $2: serverpath: directory on server, where updates are located
 1436 #     (e.g. /pub/linux/suse/i386/update/8.1/
 1437 function updatePackagelist()
 1438 {
 1439     local server=$1 serverpath=$2 dirspec rsyncopts=-qz err=0 recurse ret err q
 1440     local downloadopts="-c" # default: medium verbosity FIXME -nv!!
 1441     local servername
 1442 
 1443     servername=${SERVERURL##*@}
 1444     cd "$BASEDIR"
 1445     mkdir -p "$DLPATH/$server/$serverpath/$PATCHDIR" || exit
 1446     cd "$DLPATH/$server/$serverpath/$PATCHDIR"
 1447     recurse=          # recurse setting is needed when going over http
 1448     [[ -n $serverpath ]] && serverpath=$serverpath/
 1449     if [[ $SERVERURL == *$SERVERPATH* ]] && \
 1450         [[ $SERVERURL == rsync://* ]] ; then
 1451         if [[ $QUIET -eq 0 ]] ; then
 1452             myNote 0 "Generating patch descriptions from $servername" | fmt -$COLUMNS
 1453         fi
 1454         for g in "$DIRNAME/gpd.sh" /usr/bin/gpd.sh /usr/local/bin/gpd.sh ; do
 1455             [[ -x $g ]] && gpd=$g && break
 1456             g=""
 1457         done
 1458         [[ -n $gpd ]] && $gpd -v $VERBOSE --server $SERVERURL -q 1 --destpath .. || myError 0 "Error while calling gpd.sh!"
 1459         logWrite 1 "Updated patch descriptions from $servername"
 1460         return
 1461     fi
 1462     if [[ $QUIET -eq 1 ]] ; then
 1463         downloadopts="-q -c" # quiet mode
 1464     else
 1465         myNote 0 "Getting patch descriptions from $servername"
 1466         if [[ $VERBOSE -ge 1 ]] ; then
 1467             downloadopts="-c" #default wget is very verbose, only set continue option
 1468             rsyncopts=-vz
 1469         fi
 1470     fi
 1471     if [[ $SERVERURL == ftp://* ]] ; then
 1472         dirspec='*' # ftp servers need * after the path
 1473     else
 1474         dirspec= # http servers don't work with the *
 1475         recurse="-r" # recursive option
 1476     fi
 1477     # check for fou4s updates
 1478     if [[ $CHECKFOU -eq 1 && $NODOTSUSEVERSION -lt 101 ]] ; then
 1479         myEcho 2 "Getting fou4s patches ..."
 1480         if [[ $USEDIR -eq 1 ]] ; then
 1481             [[ -f directory ]] && mv directory directory.old
 1482             getremotefile -q --nocache $downloadopts "http://fou4s.gaugusch.at/${BETA}patches/directory" 
 1483             getDirectory "http://fou4s.gaugusch.at/${BETA}patches/" -f
 1484             [[ -f directory ]] && rm -f directory.old || mv directory.old directory
 1485         else
 1486             getremotefile -q --nocache $downloadopts -r "http://fou4s.gaugusch.at/${BETA}patches/" 
 1487         fi
 1488         CHECKFOU=0 # disable fou4s check when processing other servers
 1489     fi
 1490     # get YOU update descriptions
 1491     if [[ $SERVERURL == @(rsync://*|*:/[^/]*) ]] ; then
 1492         rsync $RSYNCOPTS $rsyncopts "$SERVERURL/$SERVERPATH/$PATCHDIR/*" .
 1493         ret=$?
 1494     else
 1495         if [[ $USEDIR -eq 1 ]] ; then
 1496             if [[ $NODOTSUSEVERSION -ge 110 ]] ; then
 1497                 test -f repomd.xml && mv repomd.xml repomd.xml.old
 1498                 getremotefile $AUTHOPTS $downloadopts $q -n "$SERVERURL/$serverpath$PATCHDIR/repomd.xml?"
 1499                 if [ ! -f repomd.xml ] ; then
 1500                     test -f repomd.xml.old && mv repomd.xml.old repomd.xml
 1501                     myWarn 0 "Description file could not be downloaded for $SERVERURL: repomd.xml"
 1502                 fi
 1503 
 1504                 for infofile in primary updateinfo deltainfo ; do
 1505                     infofilename=`$XMLP < repomd.xml | grep "$infofile.xml.gz\$" | sed 's/.*=repodata.//'`
 1506                     myEcho 3 "fn: $infofilename f: $infofile"
 1507                     test -f $infofile.xml.gz && mv "$infofile.xml.gz" "$infofile.xml.old"
 1508                     test -z $infofilename && continue
 1509                     getremotefile $AUTHOPTS $downloadopts $q "$SERVERURL/$serverpath$PATCHDIR/$infofilename"
 1510                     test -f $infofilename || continue
 1511                     test $infofilename = $infofile.xml.gz || mv $infofilename $infofile.xml.gz
 1512                     if [[ ! -f $infofile.xml.gz && $infofile != deltainfo ]] ; then
 1513                         myWarn 0 "Description file could not be updated for $SERVERURL: $infofile"
 1514                         for i in *.old ; do
 1515                             test -f $i && mv $i ${i%%old}.gz
 1516                         done
 1517                         break
 1518                     fi
 1519                 done
 1520             else
 1521                 [[ $NODOTSUSEVERSION -ge 101 ]] && dir=patches.xml || dir=directory.3
 1522                 [[ $VERBOSE -eq 0 || $QUIET -eq 1 ]] && q= || q=-v
 1523                 [[ -f $dir ]] && mv "$dir" "$dir.old"
 1524                 getremotefile $AUTHOPTS $downloadopts $q "$SERVERURL/$serverpath$PATCHDIR/$dir"
 1525                 ret=$?
 1526                 if [[ $ret -ne 0 && -f $dir.old ]] ; then
 1527                     mv "$dir.old" "$dir"
 1528                 fi
 1529                 getDirectory "$SERVERURL/$serverpath$PATCHDIR/"
 1530             fi
 1531         else
 1532             getremotefile $AUTHOPTS -q $downloadopts $recurse "$SERVERURL/$serverpath$PATCHDIR/$dirspec"
 1533             ret=$?
 1534         fi
 1535     fi
 1536     [[ $ret -ne 0 ]] && myError 0 "Warning: download error $ret from $server" && err=1
 1537     if [[ $err == 0 ]] ; then
 1538         logWrite 1 "Updated patch descriptions from $SERVERURL"
 1539     else
 1540         logWrite 0 "Error while updating patch descriptions from $SERVERURL"
 1541     fi
 1542     cd "$BASEDIR"
 1543 } # updatePackagelist
 1544 
 1545 
 1546 ################################ updateConfigFile
 1547 # Replace value in fou4s.conf
 1548 # Parameters:
 1549 # $1: Key
 1550 # $2: Value
 1551 function updateConfigFile()
 1552 {
 1553     local key=$1 value=$2 oldkey newcfgfile
 1554 
 1555     if [[ -n `grep ^$key= $CONFIGFILE` ]] ; then
 1556         if [[ `grep "^$key=" $CONFIGFILE | wc -l` -gt 1 ]] ; then
 1557             oldkey=`grep "^$key=" $CONFIGFILE| head -1`
 1558             oldkey=${oldkey##$key=}
 1559             myEcho 1 "Replacing first $key: $oldkey"
 1560         else
 1561             oldkey= # just replace existing key
 1562         fi
 1563         myEcho 3 "Key $key Oldkey $oldkey Value $value"
 1564         newcfgfile=`sed "s!^$key=$oldkey.*!$key=$value!g" < $CONFIGFILE`
 1565         if [[ -z $newcfgfile ]] ; then
 1566             myError 0 "Internal error - cannot update config file!"
 1567         else
 1568             echo "$newcfgfile" > $CONFIGFILE
 1569         fi
 1570     else # append new key
 1571         newcfgfile="`grep -v "^$key=" $CONFIGFILE`"
 1572         echo "$newcfgfile" > $CONFIGFILE
 1573         echo $key=$value >> $CONFIGFILE
 1574     fi
 1575     return 0
 1576 }
 1577 
 1578 
 1579 ################################ updateServerlist
 1580 # Get the ftp server list from www.suse.de and install in /etc/suseservers
 1581 function updateServerlist()
 1582 {
 1583     local filename=suseservers.txt
 1584     if [[ $UPDATESUSESERVERS -eq 1 ]] ; then
 1585         if [[ $EUID -eq 0 ]] ; then
 1586             cd /etc
 1587             rm -f suseservers.bak 2>/dev/null
 1588             [[ -f suseservers ]] && cp suseservers suseservers.bak
 1589             if [[ $NODOTSUSEVERSION -eq 101 && $SUSEVERSION = 10 ]] ; then
 1590                 echo https://nu.novell.com/repo/$RCE/SLES10-SP2-Updates/sles-10-$MACHINEARCH > /etc/suseservers
 1591             elif [[ $NODOTSUSEVERSION -lt 103 ]] ; then
 1592                 # the following line is from online_update_start.ycp :-)
 1593                 TIMEZONE=`grep "^TIMEZONE=".*"$" /etc/sysconfig/clock | tail -1 | sed 's/TIMEZONE="//g'| sed 's/"//g'`
 1594                 [[ -n $TIMEZONE ]] && TIMEZONE="&timezone=$TIMEZONE"
 1595                 url="http://www.suse.de/cgi-bin/suseservers.cgi?product=${SUSEPRODUCT:-SUSE%20LINUX}&version=$SUSEVERSION&basearch=$ARCH&arch=$MACHINEARCH&timezone=$TIMEZONE"
 1596                 [[ -n $SUSEPRODUCT ]] && url="$url&business=1&yast2-online-update=2.9.21-0.3&yast2-packagemanager=2.9.67-0.3.1"
 1597                 getremotefile -q --output-document /etc/suseservers "$url"
 1598                 ret=$?
 1599                 if [[ $ret -ne 0 ]] ; then
 1600                     myWarn 0 "Warning: download error $ret while retrieving suseservers"
 1601                 fi
 1602             else ## openSUSE 10.3 has automatic mirror selection through download.opensuse.org
 1603                 echo http://download.opensuse.org/ > /etc/suseservers
 1604             fi
 1605             cd "$BASEDIR"
 1606         else
 1607             myError 0 "ERROR: You must run fou4s as root to update /etc/suseservers!"
 1608             exit 5
 1609         fi
 1610     fi
 1611     echo The download server will be written to $CONFIGFILE
 1612     if [[ ! -f /etc/suseservers ]] ; then
 1613         echo "Could not find /etc/suseservers. Please run fou4s --server -w to get it."
 1614         exit 6
 1615     fi
 1616     if [[ ! -w $CONFIGFILE ]] ; then
 1617         myError 0 "ERROR: No permission to write to $CONFIGFILE - aborting"
 1618         exit 7
 1619     fi
 1620     if [[ `cat /etc/suseservers | wc -l` -gt 1 ]] ; then
 1621         select server in `grep -v "^#" /etc/suseservers | sed 's/;.*//g'` ; do
 1622             cd "$BASEDIR"
 1623             break
 1624         done
 1625     else
 1626         server=`cat /etc/suseservers`
 1627     fi
 1628     if [[ $server == ftp://* ]] ; then
 1629         myRead "Use HTTP instead of FTP (recommended, but doesn't work on all servers!)? (y/n)"
 1630         if [[ $answer == y ]] ; then
 1631             server="http://${server##ftp://}" # strip ftp:// and add http://
 1632             echo Using $server ...
 1633         fi
 1634     fi
 1635     updateConfigFile Server $server
 1636 } # updateServerList
 1637 
 1638 
 1639 ################################ prepareKernelUpdate
 1640 # Makes a backup of the existing kernel before updating it.
 1641 function prepareKernelUpdate()
 1642 {
 1643     local i
 1644     if [[ ! -f /boot/vmlinuz ]] ; then
 1645         myWarn 0 "Warning! Could not find old kernel! Can't make backup."
 1646         return 1
 1647     fi
 1648     myNote 0 "Creating backup of old Kernel (to /boot/vmlinuz.fou4s) ..."
 1649     myNote 0 "Remember to create an appropriate entry in your grub or lilo configuration."
 1650     for i in vmlinuz System.map initrd ; do
 1651         rm -f /boot/$i.fou4s
 1652         [[ -f /boot/$i ]] && cat < /boot/$i > /boot/$i.fou4s
 1653     done
 1654     rm -rf /lib/modules/[23].[0-9]*.fou4s
 1655     cp -a /lib/modules/$KERNELVER /lib/modules/$KERNELVER.fou4s
 1656 }
 1657 
 1658 
 1659 ################################ postKernelUpdate
 1660 # post-kernel-installation work for kernel backup
 1661 function postKernelUpdate()
 1662 {
 1663     local backup="`echo /lib/modules/[23].[0-9]*.fou4s`"
 1664     local target=${backup%%.fou4s}
 1665     myEcho 2 "Finishing Kernel backup ... ($backup, $target)"
 1666     if [[ -d $backup ]] ; then
 1667         if [[ ! -d $target ]] ; then
 1668             ln -s /lib/modules/$KERNELVER.fou4s /lib/modules/$KERNELVER
 1669         else
 1670             myWarn 0 "Could not rename old modules back to original name (`basename "$target"`). Either the kernel update failed or the new kernel uses the same directory name (common on older SuSE 8.x) In case of problems, you must rename the modules directory manually (the backup is at $backup)" | fmt -$COLUMNS
 1671         fi
 1672     fi
 1673 }
 1674 
 1675 
 1676 ################################ suDo
 1677 # parameter:
 1678 # $*: command to execute via su (to get rid of group fou4s when working as root)
 1679 function suDo()
 1680 {
 1681     # we use an additional 'su' to get rid of group fou4s
 1682     if [[ $EUID -eq 0 ]] ; then
 1683         su - root -c "$*" # FIXME check su call below
 1684         # su - root -c '$0 "$@"' -- "$@" #by l.g.e, doesn't work on some machines?
 1685     else
 1686         "$@"
 1687     fi
 1688 }
 1689 
 1690 
 1691 ################################ rpmInstall
 1692 # parameter:
 1693 # $*: filename1.rpm filename2.rpm ...
 1694 function rpmInstall()
 1695 {
 1696     local currentversion
 1697     local allpkgs="$*" count=$# output p lang gnal currentdir cmd
 1698     local postKernel=0 # do kernel-update post-install operations (backup)
 1699     if [[ -n $EXPORTFILE && $EXPORT -eq 1 ]] ; then
 1700         for p in $allpkgs ; do
 1701             addToRpmExportList $p
 1702         done
 1703         return
 1704     fi
 1705     if [[ $EUID -ne 0 && $TESTMODE -eq 0 && $1 != *.src.rpm ]] ; then
 1706         myError 0 "Error: You must be root to install packages!"
 1707         return
 1708     fi
 1709     if [[ $count == 1 ]] ; then
 1710         echo "Installing ${allpkgs##*/}"
 1711     else
 1712         echo
 1713         echo -e "Installing the following $COL_YELLOW$count$COL_NORM package(s): "
 1714         for p in $allpkgs ; do
 1715             output="$output${p##*/} "
 1716         done
 1717         echo "$output" | fmt -$COLUMNS
 1718         echo
 1719     fi
 1720 
 1721     [[ $TESTMODE -eq 0 && $KERNELBACKUP -eq 1 && $allpkgs == *$KERNELPKG* ]] && \
 1722         prepareKernelUpdate && postKernel=1
 1723     #we can use -U in favor of -F because the package is either already
 1724     #installed, or HAS to be installed (because of -f option)
 1725     [[ $TESTMODE -eq 1 ]] && test=--test
 1726     cmd="rpm -Uvh $test $GLOBALRPMOPTS $allpkgs"
 1727     if [[ $VERBOSE -ge 1 ]] ; then
 1728         rpmresult=""
 1729         suDo $cmd
 1730     else
 1731         rpmresult="`suDo $cmd 2>&1`"
 1732     fi
 1733     if [[ $? -eq 0 ]] ; then
 1734         [[ $postKernel -eq 1 ]] && postKernelUpdate
 1735         [[ $TESTMODE -eq 1 ]] && test=" (test mode)"
 1736         for p in $allpkgs ; do
 1737             # FIXME current version not available
 1738             pkgname=`rpm -qp --qf "%{NAME}" $p`
 1739             pkgname=${pkgname//[^a-zA-Z0-9_]/_}
 1740             oldpkg=pkg_$p
 1741             currentversion=pkg_$pkgname currentversion=(${!currentversion})
 1742             currentversion=${currentversion[0]}
 1743             logWrite 0 "Installed $p$test (old version was $currentversion)"
 1744             COUNTER[_INST]=$((COUNTER[_INST]+1))
 1745         done
 1746         for p in $allpkgs ; do
 1747             if [[ $REMOVE -eq 1 ]] ; then
 1748                 myEcho 1 "Removing ... $p$test" | fmt -$COLUMNS
 1749                 logWrite 0 "Removed $p$test"
 1750                 [[ $TESTMODE -eq 0 ]] && rm -f $p
 1751             fi
 1752         done
 1753         if [[ -n $POSTINSTLIST ]] ; then
 1754             currentdir=$PWD
 1755             cd "$BASEDIR"
 1756             POSTINSTLIST=`echo $POSTINSTLIST | sort | uniq`
 1757             for j in $POSTINSTLIST ; do
 1758                 echo -e "$COL_CYAN*** Postinstall information for ${j##*/}:"
 1759                 lang=$LANGUAGE gnal=$EGAUGNAL
 1760                 checkLanguage "`awk "/Postinformation.$lang:/,/$gnal.noitamrofnitsop:/" $j`" || { lang=english gnal=Hsilgne ; }
 1761                 awk "/Postinformation.$lang:/,/$gnal.noitamrofnitsop:/" "$j" | sed '$1;$d' | fmt -$COLUMNS | myRecode
 1762                 echo -e $COL_NORM
 1763             done
 1764             POSTINSTLIST=
 1765             cd "$currentdir"
 1766         fi
 1767         myNote 1 "Update successful!"
 1768         # run suseconfig only if a pkg was installed, and testmode is not active
 1769         [[ $SUSECONFIG -eq 1 ]] && SUSECONFIG=2
 1770         rm -f $DESCCACHE $AUTOSKIPPEDPATCHESFILE &>/dev/null #force creation next time
 1771     else
 1772         echo -e $COL_RED
 1773         cat << _EOF
 1774 
 1775 ************************
 1776 * ERROR: Update failed *
 1777 ************************
 1778 
 1779 $rpmresult
 1780 
 1781 _EOF
 1782         echo -e $COL_NORM
 1783         if [[ $INSTMODE -gt 0 ]] ; then
 1784             echo "Please try option --end, -a or --nodeps in case of dependency problems."
 1785             echo "Using --nopatchrpms might also help"
 1786         else
 1787             echo "Please try without option --end, -a or use --nodeps in case of dependency problems." | fmt -$COLUMNS
 1788             echo "Using --nopatchrpms might also help"
 1789         fi
 1790         myError 0 "THE PACKAGES SHOWN ABOVE HAVE NOT BEEN INSTALLED!"
 1791         FAILCOUNT=$((FAILCOUNT+count))
 1792     fi
 1793     cd "$BASEDIR"
 1794     cd "$DLPATH"
 1795 } # rpmInstall
 1796 
 1797 
 1798 ################################ cleanupPackagelist
 1799 # Remove old patch description files from currently processed server
 1800 function cleanupPackagelist()
 1801 {
 1802     local slashcount lastpkg i pkg
 1803     myEcho 2 "Cleaning up packagelist directory ... "
 1804     if [[ $NODOTSUSEVERSION -ge 101 ]] ; then
 1805         myWarn 0 "Fixme: Implement cleanupPackagelist for 10.1"
 1806         return 
 1807     fi
 1808     local slashcount="$DLPATH/$server/$SERVERPATH/"
 1809     slashcount=${slashcount//[^\/]/}
 1810     slashcount=${#slashcount}
 1811     for i in `ls $DLPATH/$server/$SERVERPATH/$PATCHDIR/*-*([0-9]) 2>/dev/null | sort -t / +$slashcount` ; do
 1812         pkg=${i%-*}
 1813         pkg=${pkg##*/}
 1814         newversion=${i##*-}
 1815         myEcho 4 "Cleanup checking $i"
 1816         if [[ $lastpkg == $pkg ]] ; then
 1817             if [[ $newversion -gt $lastversion ]] ; then
 1818                 myEcho 2 Cleanup removing $lastfullpkg
 1819                 rm -f $lastfullpkg
 1820             else
 1821                 myEcho 2 Cleanup removing $i
 1822                 rm -f $i
 1823                 i=$lastfullpkg
 1824             fi
 1825         fi
 1826         lastpkg=${i%-*}
 1827         lastpkg=${lastpkg##*/}
 1828         lastversion=${i##*-}
 1829         lastfullpkg=$i
 1830     done
 1831 } # cleanupPackagelist
 1832 
 1833 
 1834 ################################ hasGoodSignature
 1835 # checks a signature (gpg output)
 1836 # Parameters:
 1837 # $1: gpg output
 1838 # $2: DSA or RSA
 1839 # $3: key id
 1840 # $4: signer (name + email address)
 1841 # $5: builddate (optional)
 1842 # returns: buildtime (date of signature)
 1843 function hasGoodSignature()
 1844 {
 1845     local sigresult="$1" buildtime cmp1 cmp2 cmp3=xuxux cmp4=xuxux keyid=$3
 1846     if [[ -n $5 ]] ; then
 1847         # get time from signature
 1848         buildtime=${SIGRESULT##*Signature made }
 1849         buildtime=${buildtime%% using $2 key*}
 1850         buildtime=`date -d "$buildtime" +%s`
 1851     fi
 1852     cmp1="*Signature made * using $2 key ID $keyid*"
 1853     cmp2="*Good signature from *$4*"
 1854     if [[ $RPMVER -eq 40 ]] ; then
 1855         keyid=`echo $keyid | tr '[A-Z]' '[a-z]'`
 1856         cmp3="*MD5 digest: OK*"
 1857         cmp4="*V[34] DSA signature: OK, key ID $keyid*"
 1858     elif [[ $RPMVER -ge 48 ]] ; then
 1859         keyid=`echo $keyid | tr '[A-Z]' '[a-z]'`
 1860         cmp1="*V3 $2 Signature, key ID $keyid: OK*"
 1861         cmp2="*Header V3 $2 Signature, key ID $keyid: OK*"
 1862         cmp3="*MD5 digest: OK *"
 1863         cmp4="*V3 RSA/SHA256 Signature, key ID $keyid: OK*"
 1864     elif [[ $RPMVER -ge 44 ]] ; then
 1865         keyid=`echo $keyid | tr '[A-Z]' '[a-z]'`
 1866         cmp3="*MD5 digest: OK*"
 1867         cmp4="*V3 RSA/SHA256 signature: OK, key ID $keyid*"
 1868     fi
 1869     if [[ $sigresult == $cmp1 && $sigresult == $cmp2 ]] ; then
 1870         [[ $5 ]] && RETVAL="$buildtime"
 1871         return 0
 1872     elif [[ $sigresult == $cmp3 && $sigresult == $cmp4 ]] ; then
 1873         [[ $5 ]] && RETVAL="$buildtime"
 1874         return 0
 1875     elif [[ $sigresult == *no\ valid\ OpenPGP\ data\ found* ]] ; then
 1876         RETVAL="$sigresult"
 1877         return 254
 1878     else
 1879         RETVAL="$sigresult"
 1880         return 255 # error
 1881     fi
 1882 } # hasGoodSignature
 1883 
 1884 
 1885 ################################ hasGoodRpmSignature
 1886 # check the signature of an rpm file
 1887 # parameter:
 1888 # $1 rpm file to check
 1889 function hasGoodRpmSignature()
 1890 {
 1891     local baserpm=$1
 1892     sigresult="`rpm -v --checksig $baserpm 2>&1`"
 1893     if hasGoodSignature "$sigresult" RSA/SHA256 3dbdc284 "openSUSE Project Signing Key <opensuse@opensuse.org>" ; then
 1894         return 0 # ok
 1895     elif hasGoodSignature "$sigresult" DSA 9C800ACA "SuSE Package Signing Key <build@suse.de>" ; then
 1896         return 0 # ok
 1897     elif [[ $pkg == fou4s ]] && hasGoodSignature "$sigresult" DSA $FOU4SKEY "fou4s build key <fou4s@gaugusch.at>" ; then
 1898         return 0 # ok
 1899     elif [[ $pkg == fou4s ]] && hasGoodSignature "$sigresult" DSA/SHA1 $FOU4SKEY "fou4s build key <fou4s@gaugusch.at>" ; then
 1900         return 0 # ok
 1901     elif [[ $sigresult == *gpg:\ Good\ signature\ from* ]] && \
 1902         [[ $sigresult != *gpg:\ WARNING:\ This\ key\ is\ not\ certified\ with\ a\ trusted\ signature* ]] ; then
 1903         return 0 # ok
 1904     elif [[ $sigresult == *V3\ DSA\ signature:\ OK* ]] && \
 1905         [[ $sigresult != *gpg:\ WARNING:\ This\ key\ is\ not\ certified\ with\ a\ trusted\ signature* ]] ; then
 1906         return 0 # ok
 1907     else
 1908         if [[ `echo "$sigresult" | wc -l` -le 2 && $sigresult == *MD5\ sum\ OK* ]] ; then
 1909             myError 0 "No signature found in $baserpm! You may want to use -g to ignore this error" | fmt -$COLUMNS
 1910         else
 1911             myError 0 "Signature verification failed for $baserpm (no installation)! You may want to try the -g option to ignore this error." | fmt -$COLUMNS
 1912             myWarn 0 "$sigresult"
 1913         fi
 1914         echo
 1915         return 254 # not ok
 1916     fi
 1917 } # hasGoodRpmSignature
 1918 
 1919 
 1920 ################################ padZero
 1921 # replaces all consecutive digits with zero padded equivalents of known
 1922 # length, all nondigits remain intact:
 1923 # 3.0.20 -> 00000003.00000000.00000020
 1924 # 3.0.3  -> 00000003.00000000.00000003
 1925 # by l.g.e
 1926 function padZero()
 1927 {
 1928     local v="$1" part allzeroes=0000000000
 1929     RETVAL=()
 1930     while [[ -n $v ]] ; do
 1931         part=${v%%[0-9]*} # nondigits
 1932         v=${v#$part}
 1933         RETVAL=$RETVAL$part
 1934         [[ $v ]] || break
 1935         part=${v%%[^0-9]*} # digits
 1936         v=${v#$part}
 1937         part=${allzeroes: ${#part}}$part
 1938         RETVAL=$RETVAL$part
 1939     done
 1940 } # padZero
 1941 
 1942 
 1943 ################################ vcmp
 1944 # version compare version_a op version_b
 1945 # op is one of the allowed operators in [ ]
 1946 # by l.g.e
 1947 function vcmp()
 1948 {
 1949     local a=$1 op=$2 b=$3 ret bool
 1950     padZero $a; a=$RETVAL
 1951     padZero $b; b=$RETVAL
 1952 
 1953     [ $a $op $b ]
 1954     ret=$?
 1955     myEcho 3 "Comparing $a $op $b: $ret "
 1956     # if this happens, you called this with an invalid op
 1957     # check source code!
 1958     [[ $ret -gt 1 ]] && { myError 0 "Error ($ret) in vcmp ($pkg):" [ $a \\$op $b ]; }
 1959 
 1960     # warn to stderr if length of padded a and b differ
 1961     # it was something like a=3.0 and b=3.0.1
 1962     # or a=0.8.7 and b=0.9.1_beta
 1963     if [[ ${#a} != ${#b} && $FORCEINSTALL -eq 0 && $3 != 0.0.0.0-0 && $3 != N/A && $kind != generated ]] && ! packageFiltered $pkg $kind $series; then
 1964         if [ $VCMP_OK -eq 0 ] ; then
 1965             if [[ "`zypper vcmp 2>&1 | head -1`" == "Required argument missing." ]]; then
 1966                 myEcho 3 "Tested zypper fallback ok"
 1967                 VCMP_OK=1
 1968             fi
 1969         fi
 1970         if [[ $VCMP_OK -eq 1 ]] ; then
 1971                 myEcho 3 "Falling back to zypper vcmp $1 $3"
 1972             if [[ `zypper vcmp $1 $3` == *newer* ]] ; then
 1973                 ret=0
 1974             else
 1975                 ret=1
 1976             fi
 1977         else
 1978             if [[ $QUIET -eq 0 ]] ; then
 1979                 [[ $ret -eq 1 ]] && bool=false || bool=true
 1980                 myWarn 2 "Warn: Different version structure: $pkg: $1 $op $3 = $bool" >&2
 1981                 myWarn 2 "Using buildtime to check again for safety ..." >&2
 1982             fi
 1983             usebuildtime=1 # non-global variable only used for this check in checkpkg.
 1984             ret=1
 1985         fi
 1986     fi
 1987     return $ret
 1988 } # vcmp
 1989 
 1990 
 1991 ################################ packageFiltered
 1992 # Returns true, if package should not be processed
 1993 # parameters:
 1994 # $1: package name
 1995 # $2: kind
 1996 # $3: series
 1997 function packageFiltered()
 1998 {
 1999     local pkg=$1 kind=$2 series=$3 patchname currenttime
 2000     [[ $SECURITY -eq 1 && $kind != security ]] && return 0
 2001     [[ $SKIPOPTIONAL -eq 1 && $kind == optional ]] && return 0
 2002     [[ $GENERATED -eq 0 && $kind == generated ]] && return 0
 2003     currenttime=`date +%s`
 2004     if [[ $((newbuildtime+DAYSOLDER*60*60*24)) -gt $currenttime ]] ; then
 2005         return 0
 2006     fi
 2007     [[ $((BUILDTIME+days*60*60*24)) -gt $currenttime ]] && return 0
 2008     if [[ -n $EXCLUDELIST ]] ; then
 2009         patchname=${i##*/}
 2010         if [[ $series == @($EXCLUDELIST) ]] ; then
 2011             myEcho 2 "Skipping $pkg with series $series"
 2012             return 0
 2013         fi
 2014         if [[ $patchname == @($EXCLUDELIST) ]] ; then
 2015             myEcho 2 "Skipping $pkg in patch description ${i##*/}"
 2016             return 0
 2017         fi
 2018         if [[ $pkg == @($EXCLUDELIST) ]] ; then
 2019             myEcho 2 "Skipping $pkg in patch description ${i##*/}"
 2020             return 0
 2021         fi
 2022         if [[ $pkg-$newversion == @($EXCLUDELIST) ]] ; then
 2023             myEcho 2 "Skipping $pkg in patch description ${i##*/}"
 2024             return 0
 2025         fi
 2026     fi
 2027     if [[ -n $IGNORELIST ]] &&
 2028         [[ $pkg-$newversion == @($IGNORELIST) || $pkg == @($IGNORELIST) ]]
 2029     then
 2030         # quiet and verbose are both set in automode!
 2031         # but we don't want ignore messages there
 2032         [[ $QUIET -eq 0 ]] && \
 2033             myNote 1 "\nIgnoring $pkg (matches config file directive $IGNORELIST)"
 2034         return 0
 2035     fi
 2036     if [[ $pkg-$newversion == @($REMARKLIST) || $pkg == @($REMARKLIST) ]] ; then
 2037         remarkonly=1
 2038         myEcho 2 "Remark only: $pkg"
 2039     fi
 2040     if [[ $ONLYINSTALLEDUSERRPMS -eq 1 ]] ; then
 2041         [[ $pkg == @($USERRPMS) ]] || return 0
 2042         [[ $currentversion == N/A && $kind != script && $GETALL -eq 0 ]] && return 0
 2043     fi
 2044     return 1 # package was not filtered
 2045 } # packageFiltered
 2046 
 2047 
 2048 ################################ guessVersionFromFilename
 2049 # expects $rpm (=path/name-ver-rel.somthing.rpm) in the environment,
 2050 # splits it up into its components
 2051 # modifies environment:
 2052 # newversion = ver-rel
 2053 # pkg        = name
 2054 # series     = path components after first SUSEVERSION/
 2055 function guessVersionFromFilename ()
 2056 {
 2057     local rel ver path=${rpm#*$SUSEVERSION/}
 2058     while true; do     # kind of exception handling :)
 2059         pkg=${path##*/}
 2060         series=${path%/*};
 2061         [[ $series == $path ]] && series="unknown"
 2062         rel=${pkg##*-}
 2063         [[ $rel != $pkg && $rel == [0-9]* ]] || break #no '-' found
 2064         rel=${rel%%.*}
 2065         pkg=${pkg%-*}
 2066         ver=${pkg##*-}
 2067         [[ $ver == $pkg ]] && break # no second '-' found
 2068         pkg=${pkg%-*}
 2069         newversion="$ver-$rel"
 2070         return 0
 2071     done
 2072     # only reached on error
 2073     pkg=${pkg%%.*}
 2074     return 1
 2075 } # guessVersionFromFilename
 2076 
 2077 
 2078 ################################# checkPreInstallInfo
 2079 # Handles preinstall information for the user
 2080 # parameters:
 2081 # $1: package name
 2082 # $2: patch description file containing pre install info
 2083 function checkPreInstallInfo()
 2084 {
 2085     local pkg=$1 pkgdescfile=$2 currentdir answer lang gnal
 2086     if [[ $PREINFO -eq 1 && $INTERACTIVE -eq 1 ]] ; then
 2087         myNote 0 "Package $pkg contains the following pre-install (license) information:"
 2088         currentdir=$PWD
 2089         cd "$BASEDIR"
 2090         cd "$DLPATH"
 2091         lang=$LANGUAGE gnal=$EGAUGNAL
 2092         echo -en "$COL_WHITE"
 2093         if [[ $NODOTSUSEVERSION -lt 101 ]] ; then
 2094             checkLanguage "`awk "/Preinformation.$lang:/,/$gnal.noitamrofnierp:/" $pkgdescfile`" || { lang=english gnal=Hsilgne ; }
 2095             awk "/Preinformation.$lang:/,/$gnal.noitamrofnierp:/" $pkgdescfile | grep -v -F "Preinformation.$lang" | grep -v -F "$gnal.noitamrofnierp" | fmt -$COLUMNS
 2096         else
 2097             echo "$license" | myRecode | fmt -$COLUMNS
 2098         fi
 2099         echo -en "$COL_NORM"
 2100         cd "$currentdir"
 2101         if [[ $ACCEPTPREINSTALLINFO -eq 0 ]] ; then
 2102             myRead "Perform update (yes/no)? " <&6
 2103             [[ $answer != y ]] && return 1
 2104         fi
 2105     fi
 2106     return 0
 2107 } # checkPreInstallInfo
 2108 
 2109 
 2110 ################################# getUserChoice
 2111 # ask user to perform download/update
 2112 # returns false if not updating, else true
 2113 function getUserChoice()
 2114 {
 2115     local ok=0 v descr
 2116     if [[ $INTERACTIVE -eq 1 ]] ; then
 2117         [[ $DOINSTALL -eq 1 ]] && upd="/update"
 2118         while [ $ok -ne 1 ] ; do
 2119             [[ $VERBOSE -lt 1 ]] && descr="/show [D]escription" || descr=
 2120             myRead "Perform download$upd ([Y]es/[N]o/[S]kip forever$descr)? [$LASTANSWER] " <&6
 2121             case "$answer" in
 2122                 y)
 2123                     ok=1 ;;
 2124                 n)
 2125                     ok=1 ;;
 2126                 s)
 2127                     ok=1 ;;
 2128                 d|D)
 2129                     v=$VERBOSE
 2130                     VERBOSE=1
 2131                     printUpdateInformation $i "$shortdesc"
 2132                     VERBOSE=$v
 2133                     ;;
 2134                 V)
 2135                     if [[ $VERBOSE -lt 4 ]] ; then
 2136                         VERBOSE=$((VERBOSE+1))
 2137                         echo Verbosity increased to $VERBOSE
 2138                     fi ;;
 2139                 v)
 2140                     if [[ $VERBOSE -gt 0 ]] ; then
 2141                         VERBOSE=$((VERBOSE-1))
 2142                         echo Verbosity decreased to $VERBOSE
 2143                     fi ;;
 2144                 "")
 2145                     answer=$LASTANSWER
 2146                     ok=1 ;;
 2147                 *)
 2148                     echo "Wrong input! Use y/n/s or return for last choice. Change verbosity +/- with V/v."
 2149             esac
 2150         done
 2151         LASTANSWER=$answer
 2152         if [[ $answer == s ]] ; then
 2153             myEcho 0 "${COL_YELLOW}Skipping $COL_RED$pkg-$newversion$COL_YELLOW forever ... $COL_NORM(look at skipped-patches file to enable again)" | fmt -$COLUMNS
 2154             if [[ $NODOTSUSEVERSION -lt 110 ]] ; then
 2155                 addToSkippedPatches "`basename $i`"
 2156             else
 2157                 addToSkippedPatches "$pkg-$newversion"
 2158             fi
 2159             return 1
 2160         fi
 2161         if [[ $answer != y ]] ; then
 2162             myNote 0 "Skipping $pkg from $patchfile ..."
 2163             return 1
 2164         fi
 2165     fi
 2166     return 0
 2167 } # getUserChoice
 2168 
 2169 
 2170 ################################# getRpm
 2171 # downloads a package if user permits (in interactive mode)
 2172 # parameters:
 2173 # $1: name of patch (for printing)
 2174 # $2: rpm file to download
 2175 # $3: size of rpm
 2176 # $4: URL to download
 2177 # return value: true if download went ok
 2178 function getRpm()
 2179 {
 2180     local rpm=$1 pkg=$2 size=$3 dlfile=$4 wgetopts="-q" rsyncopts="-q --progress"
 2181     [[ $VERBOSE -ge 1 ]] && wgetopts="" && rsyncopts="--progress -v"
 2182     cd "$BASEDIR"
 2183     cd "$DLPATH"
 2184     if fileExists $server $rpm && [ $FOUNDSIZE -eq $size ] ; then
 2185         myWarn 2 "Skipping download of $pkg - already complete"
 2186         return 0
 2187     fi
 2188     [[ $kind == script ]] && fileExists $server $rpm && return 0
 2189     cd "$server/$SERVERPATH"
 2190     [[ ! -d $rpmpath ]] && mkdir -p $rpmpath
 2191     cd "$rpmpath"
 2192     if [[ $DOWNLOAD -eq 1 ]] ; then
 2193         if [[ $origurl == *://* ]] ; then
 2194             [[ $QUIET -eq 0 ]] && myNote 0 "Getting $origurl"
 2195         else
 2196             [[ $QUIET -eq 0 ]] && myNote 0 "Getting $server:$rpm"
 2197         fi
 2198         if [[ $dlfile == rsync://* ]] ; then
 2199             rsync $RSYNCOPTS $rsyncopts "$dlfile" .
 2200             ret=$?
 2201             [[ $ret -eq 20 ]] && exit 8 # handle ctrl-c
 2202         else
 2203             getremotefile -b -c $AUTHOPTS $wgetopts "$dlfile"
 2204             ret=$?
 2205         fi
 2206         if [[ ! -f ${rpm##*/} ]] ; then # only abort if file doesn't exist
 2207             [[ $ret -ne 0 ]] && myError 0 "Error getting $server:$rpm: $ret"
 2208             cd "$BASEDIR"
 2209             cd "$DLPATH"
 2210             return 1 # error
 2211         fi
 2212 
 2213         if [[ $USEDELTARPMS -eq 1 ]] ; then
 2214             rpmname=`basename $rpm`
 2215             if [[ $rpmname == *.delta.rpm || $rpmname == *.drpm ]] ; then
 2216                 newrpmname=${rpmname%%.delta.rpm}
 2217                 newrpmname=${rpmname%%.drpm}
 2218                 applydeltarpm $rpmname $newrpmname.rpm
 2219             fi
 2220         fi
 2221     fi
 2222     cd "$BASEDIR"
 2223     cd "$DLPATH"
 2224     return 0 # ok
 2225 } # getRpm
 2226 
 2227 
 2228 ################################# processDownloadedRpm
 2229 # checks the downloaded rpm signature, version and installs it
 2230 # parameters:
 2231 # $1: package name
 2232 # $2: rpm file name
 2233 # $3: new version
 2234 # $4: short filename (without path)
 2235 function processDownloadedRpm()
 2236 {
 2237     local pkg=$1 rpm=$2 newversion=$3 baserpm=$4
 2238     cd "$BASEDIR"
 2239     cd "$DLPATH"
 2240     cd "${FOUNDFILE%/*}" # directory where file was found
 2241     if [[ $AUTOMODE -eq 1 ]] && [[ -z $pkg || $pkg != @($AUTOLIST) ]]; then
 2242         # package not in autolist
 2243         cd "$BASEDIR"
 2244         return
 2245     fi
 2246 
 2247     if [[ $SKIPGPG -eq 0 ]] ; then
 2248         hasGoodRpmSignature $baserpm || { FAILCOUNT=$((FAILCOUNT+1));return; }
 2249     fi
 2250 
 2251     # check version of downloaded rpm again - it may be different
 2252     dlrpminfo=(`rpm -qp $baserpm --queryformat "%{VERSION}-%{RELEASE} %{ARCH}" 2>/dev/null`)
 2253     newpkgver=${dlrpminfo[0]}
 2254     newrpmarch=${dlrpminfo[1]}
 2255     ok=0
 2256     for a in $VALIDARCHS ; do
 2257         [[ $a == $newrpmarch ]] && ok=1 && break
 2258     done
 2259     [[ $ok -eq 0 ]] && myWarn 0 "Bad arch for $pkg: $newrpmarch, skipping" && return
 2260     if [[ $newpkgver != $newversion && $currentversion != N/A ]] ; then
 2261         myWarn 0 "Warning: Downloaded RPM has version $newpkgver, but patch description says $newversion!"
 2262         if [[ $newpkgver != $currentversion ]] ; then
 2263             # compare with version
 2264             if vcmp "$newpkgver" \> "$currentversion" ; then
 2265                 echo "Using $baserpm $newpkgver anyway"
 2266             else
 2267                 myWarn 0 "Not installing $baserpm (same or newer version already installed)."
 2268                 return
 2269             fi
 2270         else
 2271             myNote 0 "Same $baserpm already installed (no installation)."
 2272             return
 2273         fi
 2274     fi
 2275 
 2276     # if pre install info is there, we can't continue (except for interactive m.)
 2277     checkPreInstallInfo $pkg $i || return
 2278 
 2279     if [[ $baserpm == *.delta.rpm || $baserpm == *.drpm ]] ; then
 2280         myEcho 1 "Applying delta RPM for $pkg ..."
 2281         [[ ! -f ${baserpm%%.delta.rpm}.rpm ]] \
 2282             && applydeltarpm $baserpm ${baserpm%%.delta.rpm}.rpm
 2283         FOUNDFILE=${FOUNDFILE%%.delta.rpm}.rpm
 2284         baserpm=$FOUNDFILE
 2285         hasGoodRpmSignature $baserpm || { FAILCOUNT=$((FAILCOUNT+1));return; }
 2286     fi
 2287 
 2288     if [[ $INSTMODE -gt 0 ]] ; then
 2289         RPMINSTLIST="$RPMINSTLIST $FOUNDFILE"
 2290         if [[ $POSTINFO -eq 1 ]] ; then      # show post installation info for
 2291             POSTINSTLIST="$POSTINSTLIST $i" # this package
 2292             POSTINFO=0
 2293         fi
 2294     else
 2295 #fixme old version is not available!
 2296         logWrite 1 "Going to install $pkg $newversion [$kind]$test"
 2297         rpmInstall $baserpm
 2298     fi
 2299     cd "$BASEDIR"
 2300     cd "$DLPATH"
 2301 } # processDownloadedRpm
 2302 
 2303 
 2304 ################################# processScript
 2305 # processes an install script
 2306 # parameters:
 2307 # $1: script name
 2308 function processScript()
 2309 {
 2310     local pkg=$1 fullname=$DLPATH/$server/$SERVERPATH/scripts/$pkg
 2311     TMPFILE=$CACHEDIR/$pkg.$PPID
 2312 
 2313     [[ -e $TMPFILE ]] && rm -f $TMPFILE
 2314     if hasGoodSignature "`gpg --no-tty -o "$TMPFILE" --decrypt "$fullname" 2>&1`" \
 2315         DSA 9C800ACA "SuSE Package Signing Key <build@suse.de>" ; then
 2316 
 2317         # if pre install info is there, we can't continue (except for interactive m.)
 2318         checkPreInstallInfo $pkg $i || return
 2319 
 2320         if [[ -n $EXPORTFILE && $EXPORT -eq 1 ]] ; then
 2321             addToRpmExportList $fullname
 2322             return 0
 2323         fi
 2324         logWrite 1 "Going to install $pkg $newversion [$kind]$test"
 2325         chmod +x "$TMPFILE"
 2326         myNote 0 "Executing script $pkg ..."
 2327         if [[ $TESTMODE -eq 0 ]] ; then
 2328             $TMPFILE
 2329             ret=$?
 2330             myEcho 0 "Script finished with code $ret"
 2331             if [[ $ret -eq 0 ]] ; then
 2332                 myEcho 0 "Adding ${i##*/} to skipped-patches"
 2333                 addToSkippedPatches ${i##*/}
 2334                 [[ $SUSECONFIG -eq 1 ]] && SUSECONFIG=2
 2335             else
 2336                 myNote 0 "Not adding $pkg to skipped-patches file because of bad return code!"
 2337             fi
 2338         else
 2339             myEcho 0 "... skipped because of testmode"
 2340         fi
 2341         rm -f $TMPFILE
 2342     else
 2343         myError 0 "Bad signature in script $pkg!"
 2344         rm -f $TMPFILE
 2345         return 1
 2346     fi
 2347 } # processScript
 2348 
 2349 
 2350 ################################# processXMLScript
 2351 # processes an install script from an XML patch description
 2352 function processXMLScript()
 2353 {
 2354     echo "executing script: $scriptcode" | myRecode
 2355 }
 2356 
 2357 
 2358 ################################# fileExists
 2359 # checks if a given package has been downloaded. All servers are checked
 2360 # and some archs for probing unknown packages
 2361 # Parameter:
 2362 # $1: primary server to search on
 2363 # $2: rpm name with path (a1/bash-2.0.4-4.i586.rpm or i586/bash-2.0.4-4.i586.rpm
 2364 function _fileExists()
 2365 {
 2366     local server=$1 rpm=$2 f arch file a rpmarch
 2367 
 2368     FOUNDFILE=$DLPATH/$server/$SERVERPATH/$rpm
 2369     [[ -f $FOUNDFILE ]] && return 0 # that was easy
 2370     rpmname=${rpm##*/}
 2371     firstpath=${rpm%%/*}
 2372     for a in $VALIDARCHS ; do
 2373         [[ $rpm == *.$a.rpm ]] && rpmarch=$a && break
 2374     done
 2375     for f in $DLPATH/*/$SERVERPATH ; do
 2376         FOUNDFILE=$f/$rpm
 2377         [[ -f $FOUNDFILE ]] && return 0 # that was relatively easy
 2378         for a in $VALIDARCHS ; do
 2379             FOUNDFILE=$f/$firstpath/$a/${rpmname//$rpmarch/$a}
 2380             [[ -f $FOUNDFILE ]] && return 0 # not so easy to find
 2381         done
 2382     done
 2383     FOUNDFILE=
 2384     return 1 # not found
 2385 } # _fileExists
 2386 
 2387 function fileExists()
 2388 {
 2389     FOUNDSIZE=0
 2390     _fileExists "$@" && FOUNDSIZE=$(find $FOUNDFILE -maxdepth 0 -printf "%s")
 2391 } # fileExists
 2392 
 2393 
 2394 ################################# showPackage
 2395 # Shows the given package to the user in a friendly way
 2396 # Parameters:
 2397 # $1: package name (short)
 2398 # $2: new version
 2399 # $3: old version
 2400 # $4: kind
 2401 # $5: size
 2402 # $6: series
 2403 # $7: remarkonly (0/1)
 2404 # Return value:
 2405 # Returns false, if the package is on remarklist. checkPackage will exit in that
 2406 # case
 2407 function showPackage()
 2408 {
 2409     # local pkg=$pkg.$series # for arch debugging only
 2410     #showPackage $pkg $newversion $currentversion $kind $size $series $remarkonly || continue
 2411     #local pkg=$1 newversion=$2 currentversion=$3 kind=$4 size=$5 series=$6
 2412     #local remarkonly=$7
 2413     local ksize=$((size/1024)) ckind # colored version of 'kind' field
 2414     local nvsize=13 cvsize=13 # size of version fields in printf
 2415     local p=" " rwidth=$RWIDTH
 2416     if [[ $VERBOSE -ge 2 ]] ; then
 2417         [[ $rpm == *.delta.rpm || $rpm == *.drpm ]] && p="*"
 2418         [[ $rpm == *.patch.rpm ]] && p="+"
 2419     fi
 2420     if fileExists $server $rpm ; then
 2421         [[ $kind == script ]] && FOUNDSIZE=$size
 2422         [[ $FOUNDSIZE == $size ]] \
 2423         && dl="$COL_GREEN[ok]$COL_NORM" \
 2424         || dl="$COL_YELLOW[d?]$COL_NORM"
 2425     else
 2426         dl="$COL_RED[dl]$COL_NORM"
 2427     fi
 2428     if [[ -n $COL_NORM ]] ; then # color support
 2429         [[ $kind = security ]] && ckind="$COL_RED"
 2430         [[ $kind = recommended ]] && ckind="$COL_CYAN"
 2431     fi
 2432     [[ ${#newversion} -ge 13 ]] && z=${#newversion} && cvsize=$((13-(z-13)))
 2433     [[ ${#currentversion} -ge 13 ]] && z=${#currentversion} && nvsize=$((13-(z-13)))
 2434     nvs=${#newversion}
 2435     cvs=${#currentversion}
 2436     [[ $((nvs+cvs)) -gt 26 ]] && z=$((nvs+cvs)) && rwidth=$((RWIDTH-(z-26) )) 
 2437     [[ $updateinfoshown -eq 0 ]] && printUpdateInformation $i "$shortdesc" && updateinfoshown=1
 2438     printf "$COL_WHITE%-"$rwidth"b $COL_GREEN%-"$nvsize"b$COL_NORM (%b%-"$cvsize"b%b)$p$dl $ckind%-12b$COL_NORM%5bkb \n" "$pkg" "$newversion" "$COL_RED" "$currentversion" "$COL_NORM" "$kind" "$ksize"
 2439     [[ $size = 0 && $series != script ]] && \
 2440         myWarn 1 "Warning: $pkg: Invalid size in patch description: 0!"
 2441     if [[ $remarkonly -eq 1 && $INTERACTIVE -eq 0 ]] ; then
 2442         echo "($pkg will not be updated because of RemarkList entry)"
 2443         return 1
 2444     fi
 2445 
 2446     if [[ $INTERACTIVE -eq 0 && $EXPORT -eq 0 ]] ; then
 2447         if [[ $series == script ]] ; then
 2448             myWarn 0 "NOTE: Script must be installed using$COL_CYAN fou4s -i --interactive:$COL_YELLOW $pkg"
 2449         elif [[ $PREINFO -eq 1 ]] ; then
 2450             myNote 0 "NOTE: Package $pkg contains pre-install information."
 2451             if [[ $ACCEPTPREINSTALLINFO -eq 0 ]] ; then
 2452                 myNote 0 "You must install it using$COL_YELLOW fou4s -i --interactive or --acceptpreinstallinfo"
 2453             fi
 2454         fi
 2455     fi
 2456     return 0
 2457 } # ShowPackage
 2458 
 2459 
 2460 ################################# checkPackage
 2461 # processes one RPM file
 2462 # parameters:
 2463 # $1: package name
 2464 # $2: path of rpm on ftp server
 2465 # $3: new version
 2466 # $4: kind of package
 2467 # $5: download size of normal rpm
 2468 # $6: download size of patch rpm
 2469 # $7: buildtime of package
 2470 # $8: series of package (optional)
 2471 # $9: filename field of patch description
 2472 # $10: short description
 2473 function checkPackage()
 2474 {
 2475     #local pkg=$1 rpm=$2 newversion=$3 kind=$4 size=$5 patchsize=$6
 2476     #local newbuildtime=$7 series=$8 filename=$9 shortdesc=${10}
 2477     local usepatchrpmnow=0 currentversion="N/A" arch curbuildtime=0 remarkonly=0
 2478     local founduserrpm=0 update=0 cacheinfo oldhdsize=0 usedeltarpmnow=0
 2479 
 2480     ALLCOUNT=$((ALLCOUNT+1)) # used for progress bar
 2481     [[ $USEPROGRESS -eq 1 ]] && showProgress $ALLCOUNT $MAXCOUNT
 2482 
 2483     # if patchsize is given, we will try to use it
 2484     [[ $patchsize -gt 0 ]] && usepatchrpmnow=1
 2485     [[ $deltasize -gt 0 ]] && usedeltarpmnow=1
 2486 
 2487     if [[ -z $pkg ]] ; then
 2488         myError 0 "Error, no package name, skipping ($# args)"
 2489         return 255
 2490     fi
 2491     if [[ $rpm != *.rpm && $NODOTSUSEVERSION -lt 81 && -z $SUSEPRODUCT ]] ; then
 2492         myError 0 "Error, invalid filename in $pkg (${i##*/}), skipping"
 2493         return 255
 2494     fi
 2495 
 2496     if [[ $newversion == fix-me ]] ; then
 2497         myWarn 0 "WARNING: No version in $pkg! Trying to construct version number from filename '${rpm##*/}' ..." | fmt -$COLUMNS
 2498         if ! guessVersionFromFilename ; then
 2499             myError 0 "ERROR No version found in filename! Skipping ..."
 2500             return
 2501         fi
 2502         echo "Using $pkg $newversion from filename ..."
 2503     fi
 2504 
 2505     myNote 2 "Checking $pkg: $newversion [$kind, ${size}b]"
 2506 
 2507     if [[ $NODOTSUSEVERSION -lt 110 ]] ; then
 2508         # don't ask me why ...
 2509         filename=${filename%%.rpm}
 2510     fi
 2511     r=${pkg//[^a-zA-Z0-9_]/_} alreadyfound=packageinfo_$r alreadyfound=(${!alreadyfound})
 2512     if [[ $founduserrpm -eq 0 ]] ; then
 2513         cacheinfo=pkg_${pkg//[^a-zA-Z0-9_]/_} cacheinfo=${!cacheinfo}
 2514         #fixme check the following if $pkg is already on the system
 2515         if [[ $pkg.rpm == @($USERRPMS) || $pkg == @($USERRPMS) ]] ; then
 2516             founduserrpm=1 currentversion=0.0.0.0-0 usepatchrpmnow=0
 2517             if [[ $NODOTSUSEVERSION -lt 101 ]] ; then
 2518                 arch=`grep "^=Pkg: $pkg " $PACKAGES81 | grep -v src$`
 2519                 arch=${arch##* }
 2520             fi
 2521             if [[ -z $arch ]] ; then
 2522                 for a in $VALIDARCHS ; do
 2523                     [[ $rpm == *.$a.rpm ]] && arch=$a && break
 2524                 done
 2525             fi
 2526             myEcho 3 "Using arch '$arch' for $pkg ($rpm)"
 2527         elif [[ $FORCEINSTALL -eq 0 && -z $cacheinfo && $GETALL -eq 0 ]] ; then
 2528             PENDINGARRAY[$PENDINGCOUNT]="$*"
 2529             PENDINGCOUNT=$((PENDINGCOUNT+1))
 2530             myEcho 3 "Added $pkg to pending list"
 2531             return # no forced install - add to pending list
 2532         fi
 2533         if [[ -z $cacheinfo ]] ; then # forced installation
 2534             # disable use of patch rpms if no installed package is found
 2535             currentversion="N/A" usepatchrpmnow=0
 2536         else
 2537             cacheinfo=($cacheinfo) # convert to array
 2538             currentversion=${cacheinfo[0]}
 2539             curbuildtime=${cacheinfo[1]}
 2540             arch=${cacheinfo[2]}
 2541             oldhdsize=${cacheinfo[3]}
 2542             if [[ $usepatchrpmnow -eq 1 ]] ; then # check PatchRpmBasedOn list
 2543                 [[ -n $patchbase ]] && usepatchrpmnow=0 && for p in $patchbase ; do
 2544                     if [[ $p = $currentversion ]] ; then
 2545                         usepatchrpmnow=1
 2546                         break
 2547                     fi
 2548                 done
 2549                 [[ -z $patchbase ]] && usepatchrpmnow=1
 2550             fi # use patch rpm
 2551         fi # empty currentversion
 2552     fi # ! GETALL
 2553     if [[ -z $arch && $NODOTSUSEVERSION -lt 101 ]] ; then
 2554         arch=`grep "^=Pkg: $pkg " $PACKAGES81 | grep -v src$`
 2555         arch=${arch##* }
 2556     fi
 2557     if [[ $NODOTSUSEVERSION -lt 110 ]] ; then
 2558         [[ $series != default && $series == @(${VALIDARCHS// /|}) ]] && myEcho 2 "Using arch $series instead of $arch for $pkg" && arch=$series # fixme does this really work?!?!
 2559     fi
 2560     if [[ $NODOTSUSEVERSION -ge 110 ]] ; then
 2561     [[ $series != $arch ]] && myEcho 2 "Arch $series for $pkg does not match original arch $arch" && return
 2562     fi
 2563     if [[ $filename != *.rpm ]] ; then
 2564         if [[ $usepatchrpmnow -eq 1 ]] ; then
 2565             filename=$filename-$newversion.$arch.patch.rpm
 2566         else
 2567             filename=$filename-$newversion.$arch.rpm
 2568         fi
 2569         myEcho 3 "Found incomplete filename $filename"
 2570     fi
 2571     if [[ $rpm == unknown ]] || [[ -z $rpm ]] ; then
 2572         if [[ -z $arch && $NODOTSUSEVERSION -lt 101 ]] ; then
 2573             arch=`grep "^=Pkg: $pkg " $PACKAGES81 | grep -v src$`
 2574             arch=${arch##* }
 2575         fi
 2576         if [[ -z $arch ]] ; then
 2577             arch=`rpm -q $pkg --queryformat "%{ARCH}" 2>/dev/null`
 2578         fi
 2579         if [[ -z $arch && $series != script ]] ; then
 2580             myError 0 "\nError: No arch for $pkg!! Fou4s can't install this package ($rpm, $i)"
 2581             # FIXME try short name and guess arch
 2582             return
 2583         fi
 2584         rpm=rpm/$arch/$filename
 2585     fi
 2586     quit=1
 2587     [[ $kind == script ]] && quit=0
 2588 
 2589     for a in $VALIDARCHS ; do
 2590         [[ $arch == $a ]] && quit=0 && break
 2591     done
 2592     [[ $quit -eq 1 ]] && myWarn 2 "Invalid arch for $pkg: $arch, skipping" && return
 2593 # fixme - does this work?
 2594     if [[ $USEFULLPATH -eq 0 || $rpm == *tp://* ]] ; then
 2595         baserpm=${rpm##*/} rpmpath=.
 2596     else
 2597         baserpm=${rpm##*/} rpmpath=${rpm%/*}
 2598         rpmpath=${rpmpath##+(/)} # strip leading slashes
 2599         rpmpath=${rpmpath##*..+(/)} # some/ugly/../../crappy/../..///path -> path
 2600         #rpm="$rpmpath/$baserpm" # build again without ../../crappy//things
 2601     fi
 2602     [[ $GETALL -eq 1 && $GETALLNEW -eq 0 ]] && update=1 # force when getting all
 2603     [[ $GETALLNEW -eq 1 && $currentversion == N/A ]] && update=1 # force when getting all
 2604     # forced because of installtrigger or updateonlyinstalled=0
 2605     [[ $FORCEINSTALL -eq 1 && $remarkonly -eq 0 ]] && update=1
 2606     # compare packages
 2607     if [[ $update -eq 0 ]] ; then
 2608         local usebuildtime=$USEBUILDTIME # can be overwritten in vcmp
 2609         if [[ $USEBUILDTIME -eq 0 ]] ; then
 2610             [[ $currentversion == $newversion ]] && return # same version
 2611             [[ -n $currentversion && $currentversion != N/A ]] && \
 2612                 vcmp "$newversion" \> "$currentversion" && update=1
 2613             [[ $currentversion == N/A ]] && update=1
 2614         fi
 2615         if [[ $usebuildtime -eq 1 && $currentversion != N/A ]] ; then
 2616             [[ -n $newbuildtime && -n $curbuildtime && \
 2617                 $newbuildtime -gt $curbuildtime ]] && update=1
 2618         fi
 2619     fi
 2620     origurl=$rpm
 2621     if [[ $rpm == *://* ]] ; then # check for absolute http/ftp links
 2622         dlfile=$rpm
 2623     else
 2624         if [[ $NODOTSUSEVERSION -lt 101 && $SERVERPATH != *$ARCH/update/$SUSEPRODUCT$SUSEVERSION* ]] ; then
 2625             dlfile=$SERVERURL/$rpm
 2626         elif [[ $NODOTSUSEVERSION -ge 101 && $SERVERPATH != *update/$SUSEPRODUCT$SUSEVERSION* ]] ; then
 2627             dlfile=$SERVERURL/$rpm
 2628         else
 2629             dlfile=$SERVERURL/$SERVERPATH/$rpm
 2630         fi
 2631     fi
 2632     rpm="$rpmpath/$baserpm" # build again without ../../crappy//things
 2633 
 2634     # try to prevent download of one package several times
 2635     # for each package we create version_<packagename> variable with the version
 2636     # that was found. if this variable exists, tha package has already been found
 2637     if [[ -n $alreadyfound ]] ; then
 2638         foundarch=packageinfo_$r
 2639         foundarch=(${!foundarch}) foundarch=${foundarch[4]}
 2640         if [[ $alreadyfound == $newversion ]] ; then
 2641             if ! betterArch "$arch" "$foundarch"; then
 2642                 myWarn 2 "Using ${rpm##*/} as alternative (same version already found)."
 2643                 eval dlfile1_$r=$dlfile
 2644                 eval server1_$r=$server
 2645                 return
 2646             fi
 2647         fi
 2648         if vcmp "$alreadyfound" \> "$newversion" ; then
 2649             myWarn 2 "Not processing ${rpm##*/} (newer version already found)."
 2650             return
 2651         fi
 2652     fi
 2653     [[ $update -eq 0 ]] && return
 2654     p=${pkgdescname//[^a-zA-Z0-9_]/_}
 2655     val="$newversion $currentversion $kind $size $series $remarkonly $rpm $dlfile $server $oldhdsize $newhdsize $i $pkgdescname $newbuildtime $PREINFO $sourcerpm $origurl $SERVERPATH $usepatchrpmnow $patchsize $SERVERURL $usedeltarpmnow $deltasize $deltarpm $patchrpm"
 2656     eval packageinfo_$r='$val'
 2657     eval package_${p}_MG_$r='$pkg'
 2658     eval shortdesc_$r='$shortdesc'
 2659     eval longdesc_$r='$longdesc'
 2660     eval license_$r='$license'
 2661     if [[ $UPDATEONLYINSTALLED -eq 0 && $COMPATIBLE -eq 1 && $PENDINGCOUNT -gt 0 ]] ; then
 2662         myWarn 3 "Forcing $PENDINGCOUNT pending packages"
 2663         FORCEINSTALL=1
 2664         count=$((PENDINGCOUNT-1)) # seq command requires this
 2665         PENDINGCOUNT=0 # recursion would fail if we leave it to some other value
 2666         for args in "${PENDINGARRAY[@]}" ; do
 2667             ALLCOUNT=$((ALLCOUNT-1)) # we check again, therefore must decrement
 2668             checkPackage $args
 2669         done
 2670     fi
 2671 } # CheckPackage
 2672 
 2673 
 2674 ################################# handleInstallTrigger
 2675 # sets FORCEINSTALL if install trigger returns true (0)
 2676 function handleInstallTrigger()
 2677 {
 2678     if [[ $SAFEPKGDESC -eq 1 ]] ; then # only signed packages!
 2679         TMPFILE=`mktemp $CACHEDIR/insttrigger.XXXXXX`
 2680         if [[ $? -eq 0 ]] ; then
 2681             while read ; do
 2682                 case "$REPLY" in
 2683                     Reggirtllatsni:)
 2684                     break ;;
 2685                 esac
 2686                 echo "$REPLY" >> $TMPFILE
 2687             done
 2688             chmod +x $TMPFILE
 2689             $TMPFILE # execute install trigger
 2690             if [[ $? -eq 0 ]] ; then
 2691                 myEcho 3 "Forcing install of $pkg because of installtrigger"
 2692                 FORCEINSTALL=1
 2693             fi
 2694             # FIXME what should we do, if install trigger returns false?
 2695             # Normal checking or ignoring this package?!?! Currently: normal check
 2696             rm -f $TMPFILE
 2697         else
 2698             myError 0 "Error creating tempfile!! Installtrigger cannot be checked!"
 2699         fi
 2700     else
 2701         myWarn 0 "WARNING: Installtrigger found in unsafe patch desc. ${i##*/} - IGNORING!"
 2702     fi
 2703 } # handleInstallTrigger
 2704 
 2705 
 2706 ################################# showRpmSummary
 2707 # shows summary of one available rpm package (fou4s -l)
 2708 function showRpmSummary
 2709 {
 2710     if packageFiltered $pkg $kind $series; then
 2711         return
 2712     fi
 2713     if [[ $VERBOSE -ge 1 && $LISTAVAILRPMS -eq 1 ]] && \
 2714         ! packageFiltered $pkg $kind $series; then
 2715         [[ $updateinfoshown -eq 0 ]] && printUpdateInformation $i "$shortdesc" && updateinfoshown=1
 2716     fi
 2717     newhdsize=0 # for correct summary
 2718     updateStatistics
 2719     size=$((size/1024))
 2720     ckind=$COL_NORM
 2721     [[ $kind == security ]] && ckind="$COL_RED"
 2722     [[ $kind == recommended ]] && ckind="$COL_CYAN"
 2723     printf "$COL_WHITE%-35b $COL_GREEN%-18b $ckind%-14b$COL_NORM %5bkb \n" "$pkg" "$newversion" "$kind" "$size"
 2724 } # showRpmSummary
 2725 
 2726 
 2727 ################################# processXMLDescRPM
 2728 # save parsed information from xml description (SuSE 10.1 .. 10.3) to internal
 2729 # variables
 2730 function processXMLDescRPM()
 2731 {
 2732     myNote 2 "processing rpm $rpm pkg $pkg version $newversion cat $kind arch $series"
 2733     if [[ $LISTAVAILRPMS -eq 1 ]] ; then # only show available rpms
 2734         showRpmSummary
 2735     else
 2736         if [[ $USECACHE -ge 1 ]] ; then
 2737             for p in pkg rpm newversion kind size newbuildtime series filename shortdesc patchbase patchsize newhdsize sourcerpm PREINFO POSTINFO UPDATEONLYINSTALLED deltasize deltarpm patchrpm longdesc license scriptcode; do
 2738                 pkg1=${pkg//[^a-zA-Z0-9_-]/}
 2739                 echo "$p='${!p//\'/\"}'" >> $cachefile.$pkg1
 2740             done
 2741         fi
 2742         checkPackage
 2743     fi
 2744 
 2745     # reset values in case that the next loop will not refill them
 2746     series=default rpm=unknown pkg=unknown filename=unknown.rpm
 2747     newversion=0.0-0 size=0 newbuildtime=0 readingPkg=0 
 2748     patchbase= patchsize=0 sourcerpm=unknown newhdsize=0 deltasize=0
 2749     deltarpm=unknown patchrpm=unknown
 2750 } 
 2751 
 2752 
 2753 ################################# processUpdateinfoRPM
 2754 # save parsed information from xml description (SuSE >= 11.0) to internal
 2755 # variables
 2756 function processUpdateinfoRPM()
 2757 {
 2758     newversion=$newversion1-$newversion2
 2759     myNote 2 "processing updateinfo rpm $filename pkg $pkg version $newversion cat $kind arch $arch in $pkgdescname"
 2760     series=$arch
 2761     # echo Needing filename $filename from pkg $pkg pkgdescname $pkgdescname kind $kind ver $newversion
 2762     data="$"
 2763     p="file_${pkg//[^a-zA-Z0-9_]/_}__${newversion//[^a-zA-Z0-9_]/_}__$arch"
 2764     # echo "fixme $p -- ${!p}"
 2765     primaryinfo=(${!p})
 2766     newversion=${primaryinfo[0]}
 2767     size=${primaryinfo[1]}
 2768     arch=${primaryinfo[2]}
 2769     rpm=${primaryinfo[3]}
 2770     server=${primaryinfo[4]}
 2771     newhdsize=${primaryinfo[5]}
 2772     newbuildtime=${primaryinfo[6]}
 2773     p="deltafile_${pkg//[^a-zA-Z0-9_]/_}__${newversion//[^a-zA-Z0-9_]/_}__$arch"
 2774     deltainfo=(${!p})
 2775     deltasize=${deltainfo[0]}
 2776     deltarpm=${deltainfo[1]}
 2777     i=$pkgdescname
 2778 
 2779     if [[ $LISTAVAILRPMS -eq 1 ]] ; then # only show available rpms
 2780         showRpmSummary
 2781     else
 2782         if [[ $USECACHE -ge 1 ]] ; then
 2783             pkg1=${pkg//[^a-zA-Z0-9_-]/}
 2784             for p in pkg rpm newversion kind size newbuildtime series filename shortdesc patchbase patchsize newhdsize sourcerpm PREINFO POSTINFO UPDATEONLYINSTALLED deltasize deltarpm patchrpm longdesc license scriptcode pkgdescname i; do
 2785                 echo "$p='${!p//\'/\"}'" >> $cachefile.$pkgdescname.$pkg1.$series
 2786             done
 2787         fi
 2788         checkPackage
 2789     fi
 2790 
 2791     # reset values in case that the next loop will not refill them
 2792     series=default rpm=unknown pkg=unknown filename=unknown.rpm
 2793     newversion=0.0-0 size=0 newbuildtime=0 readingPkg=0 
 2794     patchbase= patchsize=0 sourcerpm=unknown newhdsize=0 deltasize=0
 2795     deltarpm=unknown patchrpm=unknown PREINFO=0
 2796 } 
 2797 
 2798 
 2799 ################################# processdeltainfoRPM
 2800 # save parsed information from delta xml description (SuSE >= 11.0) to internal
 2801 # variables
 2802 function processdeltainfoRPM()
 2803 {
 2804     newversion="$newversion1-$newversion2"
 2805     myNote 2 "processing delta rpm $deltarpm pkg $pkg version $newversion arch $deltaarch deltarpm $deltarpm"
 2806     
 2807     p=${pkg//[^a-zA-Z0-9_]/_}__${newversion//[^a-zA-Z0-9_]/_}__$deltaarch
 2808     val="$deltasize $deltarpm"
 2809     eval deltafile_$p='$val'
 2810 
 2811     # reset values in case that the next loop will not refill them
 2812     series=default rpm=unknown pkg=unknown filename=unknown.rpm
 2813     newversion=0.0-0 size=0 newbuildtime=0 readingPkg=0 
 2814     patchbase= patchsize=0 sourcerpm=unknown newhdsize=0 deltasize=0
 2815     deltarpm=unknown patchrpm=unknown
 2816 } 
 2817 
 2818 
 2819 ################################# processPrimaryRPM
 2820 # save parsed information from xml description (SuSE >= 11.0) to internal
 2821 # variables
 2822 function processPrimaryRPM()
 2823 {
 2824     myNote 2 "processing primary rpm $rpm pkg $pkg version $newversion arch $series"
 2825     
 2826     p=${primaryfilename//[^a-zA-Z0-9_]/_}__${newversion//[^a-zA-Z0-9_]/_}__$arch
 2827     val="$newversion $size $arch $rpm $server $newhdsize $newbuildtime $SERVERPATH $SERVERURL"
 2828     eval file_$p='$val'
 2829     echo "file_$p='$val'" >> $cachefile.tmp
 2830 
 2831     # reset values in case that the next loop will not refill them
 2832     series=default rpm=unknown pkg=unknown filename=unknown.rpm
 2833     newversion=0.0-0 size=0 newbuildtime=0 readingPkg=0 
 2834     patchbase= patchsize=0 sourcerpm=unknown newhdsize=0 deltasize=0
 2835     deltarpm=unknown patchrpm=unknown
 2836 } 
 2837 ################################# processPrimaryXML
 2838 # cycle through primary.xml, updateinfo.xml and deltainfo.xml from openSUSE 11.0 and newer
 2839 function processPrimaryXML()
 2840 {
 2841     local rpm pkg newversion size newbuildtime filename patchbase patchsize
 2842     local sourcerpm readingPkg series updateinfoshown shortdesc newhdsize kind
 2843     local POSTINFO PREINFO FORCEINSTALL PENDINGCOUNT PENDINGARRAY
 2844     local UPDATEONLYINSTALLED SAFEPKGDESC i deltasize deltarpm first longdesc
 2845     local patchrpm license scriptcode
 2846 
 2847     myEcho 2 "Checking package information on $server"
 2848     if [[ ! -f primary.xml.gz || ! -f updateinfo.xml.gz ]] ; then
 2849         myWarn 0 "Description files (primary/deltainfo/updateinfo) are not complete for $server"
 2850         return 1
 2851     fi
 2852     [[ $USEPROGRESS -eq 1 ]] && MAXCOUNT=`zgrep "<name>" primary.xml.gz 2>/dev/null| wc -l`
 2853     [[ $MAXCOUNT == 0 ]] && MAXCOUNT=1 # otherwise div/0 would occur ...
 2854     ALLCOUNT=0 # reset progress bar
 2855     myNote 2 "########## Processing primary.xml on $server"
 2856     # [[ ! -f $i ]] && myWarn 2 "Missing patch description $i" && continue
 2857     cachefile=$CACHEDIR/.cache.$HOSTNAME/primary.$LANGUAGE.$server
 2858     newbuildtime=0
 2859     pkgdescname=UNKNOWN
 2860     rpm=unknown pkg=unknown newversion=0.0-0 size=0 newbuildtime=0 newhdsize=0
 2861     filename=unknown.rpm patchbase= patchsize=0 sourcerpm=unknown oldhdsize=0
 2862     kind=unknown
 2863     readingPkg=0 #currently (not) reading a package info from the pkgdesc file
 2864     series=default # initialisation to sane defaults
 2865     updateinfoshown=0 # indicates if update information has been shown
 2866     shortdesc= # short description
 2867     POSTINFO=0 # postinstall information present?
 2868     FORCEINSTALL=0 # force installation because of installtrigger
 2869     PREINFO=0 PENDINGCOUNT=0 PENDINGARRAY=()
 2870     UPDATEONLYINSTALLED=1 # default!!
 2871     SAFEPKGDESC=$SKIPGPG # use default from disable gpg option
 2872     deltarpm=unknown deltasize=0 first=1 longdesc= patchrpm=unknown license=
 2873     deltasize1= deltabaserel= deltabasever= currentversion= deltaseqinfo=
 2874     scriptcode= deltachecksum=0
 2875     i=UNK
 2876 
 2877     if [[ $DESCCACHE -nt primary.xml.gz && $DESCCACHE -nt deltainfo.xml.gz && $DESCCACHE -nt updateinfo.xml.gz ]] ; then
 2878         myEcho 2 "Skipping server $server"
 2879         return 0
 2880     fi
 2881     if [[ $USECACHE -ge 1 && -f $cachefile && $cachefile -nt primary.xml.gz ]] ; then
 2882         myEcho 2 "Reading primary xml cache $cachefile ($server)"
 2883         source $cachefile
 2884     else
 2885         xmlparsed=`mktemp $CACHEDIR/.cache.$HOSTNAME/xmlprim.XXXXXXXX`
 2886         finished=0
 2887         {
 2888             zcat primary.xml.gz | $XMLP > $xmlparsed
 2889         #xmlpcount=`wc -l < $xmlparsed`
 2890         #MAXCOUNT=$((MAXCOUNT+xmlpcount))
 2891         myEcho 2 "Reading primary.xml"
 2892         while read line ; do
 2893             # does not work because it is inside a subshell
 2894             ##[[ $USEPROGRESS -eq 1 ]] && showProgress $ALLCOUNT $MAXCOUNT 
 2895             ##ALLCOUNT=$((ALLCOUNT+1))
 2896             line=${line//\/metadata\/package\//}
 2897             if [[ $line == /metadata/package ]] ; then
 2898                 if [[ $first -eq 0 && readingPkg -eq 1 ]] ; then
 2899                     processPrimaryRPM
 2900                 else
 2901                     first=0
 2902                 fi
 2903                 newbuildtime=0
 2904                 rpm=unknown pkg=unknown newversion=0.0-0 size=0 newbuildtime=0 newhdsize=0
 2905                 filename=unknown.rpm 
 2906                 series=default # initialisation to sane defaults
 2907                 readingPkg=1 
 2908             fi
 2909             [[ $first -eq 0 && $readingPkg -eq 0 ]] && continue
 2910 
 2911             case $line in 
 2912             arch=*) 
 2913                 series="${line##*=}" 
 2914                 arch=$series
 2915                     [[ -n $series && $series != default && $series != @(${VALIDARCHS// /|}) ]] && readingPkg=0 && myEcho 3 Ignoring package $pkg with foreign arch $series
 2916                 ;;
 2917             location/@href=*)
 2918                 rpm=${line##*=} ;;
 2919             name=*)
 2920                 pkg=${line##*=} 
 2921                 primaryfilename="${line##*=}" 
 2922                 filename=$pkg.rpm ;;
 2923             version/@ver=*)
 2924                 newversion=${line##*=} ;;
 2925             version/@rel=*)
 2926                 newversion=$newversion-${line##*=} ;;
 2927             size/@package=*)
 2928                 size=${line##*=} ;;
 2929             size/@installed=*)
 2930                 newhdsize=${line##*=} ;;
 2931             time/@build=*)
 2932                 newbuildtime=${line##*=} ;;
 2933             esac
 2934         done < $xmlparsed
 2935         if [[ $readingPkg -eq 1 ]] ; then
 2936             processPrimaryRPM
 2937         fi
 2938         rm -f $xmlparsed
 2939         }&
 2940         if [[ $THREADS -eq 0 ]] ; then
 2941             wait
 2942         fi
 2943     fi
 2944     if [[ $USECACHE -ge 1 && $cachefile -nt deltainfo.xml.gz ]] ; then
 2945         myEcho 2 "Reading deltainfo from cache"
 2946         # source $cachefile.delta
 2947     elif [[ $USEDELTARPMS -eq 1 ]] ; then
 2948         myEcho 2 "Reading deltainfo.xml ..." # todo 2
 2949         xmlparsed=`mktemp $CACHEDIR/.cache.$HOSTNAME/xmlpdelta.XXXXXXXX`
 2950         zcat deltainfo.xml.gz | $XMLP > $xmlparsed
 2951         xmldeltacount=`wc -l < $xmlparsed`
 2952         MAXCOUNT=$((MAXCOUNT+xmldeltacount))
 2953         readingPkg=0
 2954         firstpkg=1
 2955         while read line ; do
 2956             [[ $USEPROGRESS -eq 1 ]] && [[ $USEPROGRESS -eq 1 ]] && showProgress $ALLCOUNT $MAXCOUNT 2
 2957             ALLCOUNT=$((ALLCOUNT+1))
 2958             #line=${line//\/deltainfo\/newpackage\//}
 2959             if [[ $line == /deltainfo/newpackage ]]; then
 2960                 [[ $readingPkg -eq 1 ]] && processdeltainfoRPM
 2961                 readingPkg=0
 2962                 firstpkg=0
 2963             fi
 2964             case $line in 
 2965             /deltainfo/newpackage/delta)
 2966                 if [[ $firstpkg == 1 ]] ; then
 2967                     firstpkg=0
 2968                 else
 2969                     # got one RPM from this updateinfo.xml.gz
 2970                     [[ $readingPkg -eq 1 ]] && processdeltainfoRPM
 2971                     readingPkg=0
 2972                 fi
 2973             ;;
 2974             /deltainfo/newpackage/@version=*)
 2975                 newversion1="${line##*=}" ;;
 2976             /deltainfo/newpackage/@release=*)
 2977                 newversion2="${line##*=}" ;;
 2978             /deltainfo/newpackage/@name=*)
 2979                 pkg="${line##*=}" ;;
 2980             /deltainfo/newpackage/delta/@filename=*|/deltainfo/newpackage/delta/filename=*)
 2981                 deltarpm1="${line##*=}" ;;
 2982             /deltainfo/newpackage/delta/@size=*|/deltainfo/newpackage/delta/size=*)
 2983                 deltasize1="${line##*=}" ;;
 2984             /deltainfo/newpackage/delta/@oldversion=*|delta/@ver=*)
 2985                 deltabasever=${line##*=} ;;
 2986             /deltainfo/newpackage/delta/@oldrelease=*|delta/@rel=*)
 2987                 deltabaserel=${line##*=} ;;
 2988             /deltainfo/newpackage/@arch=*)
 2989                 deltaarch=${line##*=} ;;
 2990             /deltainfo/newpackage/delta/@sequence=*)
 2991                 deltaseqinfo=`echo "$line" | sed 's/^.deltainfo.newpackage.delta..sequence=//g'` ;;
 2992             /deltainfo/newpackage/delta/sequence=*)
 2993                 deltaseqinfo=`echo "$line" | sed 's/^.deltainfo.newpackage.delta.sequence=//g'` ;;
 2994             /deltainfo/newpackage/delta/checksum=*) # dummy usage because it is the last element
 2995                 deltarpm=unknown
 2996                 cacheinfo=pkg_${pkg//[^a-zA-Z0-9_]/_} cacheinfo=(${!cacheinfo})
 2997                 currentversion=${cacheinfo[0]}
 2998                 currentarch=${cacheinfo[2]}
 2999                 
 3000                 if [[ -n $deltaseqinfo && $deltabasever-$deltabaserel == $currentversion && "$deltaarch" == "$currentarch" ]] ; then
 3001                     myEcho 2 "Checking if delta RPM $deltabasever-$deltabaserel-$deltaarch for $pkg-$currentversion-$currentarch size $deltasize1 works ... $PWD $deltarpm1"
 3002                     if [[ -f ../${deltarpm1##.delta.rpm}.rpm ]] || applydeltarpm -c -s "$deltaseqinfo" 2>/dev/null ; then
 3003                         myWarn 3 "Found delta for $pkg: $deltarpm1"
 3004                         deltachecksum=${line##*=}
 3005                         deltasize=$deltasize1
 3006                         deltarpm=$deltarpm1
 3007                         readingPkg=1
 3008                     fi
 3009                 else
 3010                     deltasize=0
 3011                     myEcho 2 "NOT Checking if delta RPM $deltabasever-$deltabaserel-$deltaarch for $pkg-$currentversion-$currentarch size $deltasize1 works ..."
 3012                 fi
 3013                 ;;
 3014             /deltainfo/newpackage/delta/@arch=*)
 3015                 arch=${line##*=}
 3016                 readingPkg=1
 3017                 [[ $arch != @(${VALIDARCHS// /|}) ]] && readingPkg=0 && myEcho 2 Ignoring package $pkg with foreign arch $arch in deltainfo
 3018                 ;;
 3019             esac
 3020         done < $xmlparsed
 3021         rm -f $xmlparsed
 3022     fi
 3023     if [[ $readingPkg -eq 1 ]] ; then
 3024         processdeltainfoRPM
 3025     fi
 3026 
 3027     #if [[ -f $cachefile-1 && $cachefile.1 -nt updateinfo.xml.gz ]] ; then
 3028     # fixme check this
 3029     if ! [[ $USECACHE -ge 1 && $LISTAVAILRPMS -eq 0 && -f $cachefile-1 \
 3030         && $cachefile-1 -nt updateinfo.xml.gz ]] ; then
 3031         myEcho 2 "Reading updateinfo.xml ..." # todo 2
 3032         xmlparsed=`mktemp $CACHEDIR/.cache.$HOSTNAME/xmlpu.XXXXXXXX`
 3033         zcat updateinfo.xml.gz | $XMLP > $xmlparsed
 3034     fi
 3035 
 3036     wait
 3037     ALLCOUNT=0
 3038     test -f $cachefile.tmp && mv $cachefile.tmp $cachefile
 3039     # read cached info from primary.xml
 3040     source $cachefile
 3041 
 3042     if [[ $USECACHE -ge 1 && $LISTAVAILRPMS -eq 0 && -f $cachefile-1 \
 3043         && $cachefile-1 -nt updateinfo.xml.gz ]] ; then
 3044         myEcho 2 "Reading updateinfo from cache ($server)"
 3045         for j in $cachefile.* ; do
 3046             test -f $j && source $j  || continue
 3047             checkPackage
 3048             # reset values in case that the next loop will not refill them
 3049             series=default rpm=unknown pkg=unknown filename=unknown.rpm
 3050             newversion=0.0-0 size=0 newbuildtime=0 readingPkg=0 
 3051             patchbase= patchsize=0 sourcerpm=unknown newhdsize=0 deltasize=0
 3052             deltarpm=unknown patchrpm=unknown PREINFO=0 deltachecksum=0
 3053         done
 3054     else
 3055         myEcho 2 "Parsing updateinfo.xml ..." # todo 2
 3056         if [ $LISTAVAILRPMS -eq 1 ] ; then
 3057             rm -f $cachefile-1
 3058         else
 3059             touch $cachefile-1
 3060         fi
 3061         firstpkg=1
 3062         firstupdate=1
 3063         while read line ; do
 3064             line=${line//\/updates\/update\//}
 3065             if [[ $line == /updates/update ]] ; then
 3066                 if [[ $readingPkg -eq 1 ]] ; then
 3067                     processUpdateinfoRPM
 3068                 fi
 3069                 firstupdate=0
 3070                 firstpkg=1
 3071                 readingPkg=0
 3072                 pkgdescname= kind= longdesc= filename=
 3073                 updateinfoshown=0
 3074             fi
 3075             # info: 
 3076             # @version, @type, id, title/@, issued/@date, description
 3077             # pkglist/collection/package/@release,@name,@arch,@version,filename=
 3078             # echo reading updateinfo line $line
 3079             case $line in 
 3080             @version=*) 
 3081                 pkgdescname="${line##*=}" i=$pkgdescname ;;
 3082             @type=*) 
 3083                 kind="${line##*=}" ;;
 3084             id=*) 
 3085                 pkg="${line##*=}" 
 3086                 pkgdescname="${line##*=}-$pkgdescname" ;;
 3087             description=*)
 3088                 longdesc=${line##*=} 
 3089                 longdesc=${longdesc%} 
 3090                 longdesc=${longdesc///=} ;;
 3091             title=*)
 3092                 shortdesc=${line##*=} 
 3093                 shortdesc=${shortdesc%} 
 3094                 shortdesc=${shortdesc///=} ;;
 3095             pkglist/collection/package)
 3096                 if [[ $firstpkg == 1 ]] ; then
 3097                     firstpkg=0
 3098                 else
 3099                     # got one RPM from this updateinfo.xml.gz
 3100                     [[ $readingPkg -eq 1 ]] && processUpdateinfoRPM
 3101                 fi
 3102             ;;
 3103             pkglist/collection/package/@version=*)
 3104                 newversion1="${line##*=}"  ;;
 3105             pkglist/collection/package/@release=*)
 3106                 newversion2="${line##*=}"  ;;
 3107             pkglist/collection/package/@name=*)
 3108                 pkg="${line##*=}"  ;;
 3109             pkglist/collection/package/filename=*)
 3110                 filename="${line##*=}"  ;;
 3111             pkglist/collection/package/reboot_suggested=*)
 3112                 line="${line##*=}"
 3113                 if [[ $line == 1 ]] ; then
 3114                     PREINFO=1
 3115                     license="A reboot is suggested after installing this update"
 3116                 fi
 3117                 ;;
 3118             pkglist/collection/package/@arch=*)
 3119                 arch=${line##*=}
 3120                 readingPkg=1
 3121                 [[ $arch != @(${VALIDARCHS// /|}) ]] && readingPkg=0 && myEcho 2 Ignoring package $pkg with foreign arch $arch in updateinfo $pkgdescname
 3122                 ;;
 3123             *)
 3124             #echo "ignoring $line in updateinfo"
 3125             ;;
 3126             esac
 3127         done < $xmlparsed
 3128         if [[ $readingPkg -eq 1 ]] ; then
 3129             processUpdateinfoRPM
 3130         fi
 3131     fi
 3132     rm -f $xmlparsed
 3133 }
 3134 
 3135 ################################# processXMLPatchDescriptions
 3136 # cycle through all XML package description files for SUSE 10.1 .. 10.3
 3137 # Parameters:
 3138 # $*: the patch description files
 3139 function processXMLPatchDescriptions()
 3140 {
 3141     local rpm pkg newversion size newbuildtime filename patchbase patchsize
 3142     local sourcerpm readingPkg series updateinfoshown shortdesc newhdsize kind
 3143     local POSTINFO PREINFO FORCEINSTALL PENDINGCOUNT PENDINGARRAY
 3144     local UPDATEONLYINSTALLED SAFEPKGDESC i deltasize deltarpm first longdesc
 3145     local patchrpm license scriptcode
 3146 
 3147     myEcho 2 "Need to check $# package information files on $server"
 3148     [[ $# -eq 0 ]] && return
 3149     [[ $USEPROGRESS -eq 1 ]] && MAXCOUNT=`grep "<name>" $* 2>/dev/null| wc -l`
 3150     [[ $MAXCOUNT == 0 ]] && MAXCOUNT=1 # otherwise div/0 would occur ...
 3151     ALLCOUNT=0 # reset progress bar
 3152     for i in $* ; do
 3153         pkgdescname=${i##*/patch-}
 3154         pkgdescname=${pkgdescname%%.xml}
 3155         myNote 3 "########## Processing XML patch description $i $pkgdescname"
 3156         [[ ! -f $i ]] && myWarn 2 "Missing patch description $i" && continue
 3157         cachefile=$CACHEDIR/.cache.$HOSTNAME/$i.$LANGUAGE
 3158         newbuildtime=0
 3159         rpm=unknown pkg=unknown newversion=0.0-0 size=0 newbuildtime=0 newhdsize=0
 3160         filename=unknown.rpm patchbase= patchsize=0 sourcerpm=unknown oldhdsize=0
 3161         kind=unknown
 3162         readingPkg=0 #currently (not) reading a package info from the pkgdesc file
 3163         series=default # initialisation to sane defaults
 3164         updateinfoshown=0 # indicates if update information has been shown
 3165         shortdesc= # short description
 3166         POSTINFO=0 # postinstall information present?
 3167         FORCEINSTALL=0 # force installation because of installtrigger
 3168         PREINFO=0 PENDINGCOUNT=0 PENDINGARRAY=()
 3169         UPDATEONLYINSTALLED=1 # default!!
 3170         SAFEPKGDESC=$SKIPGPG # use default from disable gpg option
 3171         deltarpm=unknown deltasize=0 first=1 longdesc= patchrpm=unknown license=
 3172         deltasize1= deltabaserel= deltabasever= currentversion= deltaseqinfo=
 3173         scriptcode=
 3174 
 3175         if [[ $USECACHE -ge 1 ]] ; then
 3176             if [[ -f $cachefile && $cachefile -nt $i ]] ; then
 3177                 for cf in $cachefile.* ; do
 3178                     if [[ -f $cf ]] ; then
 3179                         source $cf
 3180                         if [[ $LISTAVAILRPMS -eq 1 ]] ; then # only show available rpms
 3181                             showRpmSummary
 3182                         else
 3183                             checkPackage
 3184                         fi
 3185                     fi
 3186                 done
 3187                 continue
 3188             fi
 3189             mkdir -p ${cachefile%/*} # create directory for cache file
 3190             rm -f $cachefile*
 3191             touch $cachefile # empty dummy
 3192         fi
 3193 
 3194         xmlparsed=`mktemp $CACHEDIR/.cache.$HOSTNAME/xmlp.XXXXXXXX`
 3195         $XMLP <$i > $xmlparsed
 3196         while read line ; do
 3197             line=${line//\/patch\//}
 3198             if [[ $line == atoms/package ]] ; then
 3199                 if [[ $first -eq 0 && readingPkg -eq 1 ]] ; then
 3200                     processXMLDescRPM
 3201                 else
 3202                     first=0
 3203                 fi
 3204                 readingPkg=1 
 3205             fi
 3206             [[ $first -eq 0 && $readingPkg -eq 0 ]] && continue
 3207 
 3208             case $line in 
 3209             atoms/package/arch=*) 
 3210                 series="${line##*=}" 
 3211                 arch=$series
 3212                     [[ -n $series && $series != default && $series != @(${VALIDARCHS// /|}) ]] && readingPkg=0 && myEcho 2 Ignoring package $pkg with foreign arch $series
 3213                 ;;
 3214             category=*) 
 3215                 kind="${line##*=}" ;;
 3216             license-to-confirm=*) 
 3217                 PREINFO=1 ;;
 3218             atoms/package/location/@href=*)
 3219                 rpm=${line##*=} ;;
 3220             atoms/package/name=*)
 3221                 pkg=${line##*=} 
 3222                 filename=$pkg.rpm;;
 3223             atoms/package/version/@ver=*)
 3224                 newversion=${line##*=} ;;
 3225             atoms/package/version/@rel=*)
 3226                 newversion=$newversion-${line##*=} ;;
 3227             atoms/package/size/@package=*)
 3228                 size=${line##*=} ;;
 3229             atoms/package/size/@installed=*)
 3230                 newhdsize=${line##*=} ;;
 3231             atoms/package/time/@build=*)
 3232                 newbuildtime=${line##*=} ;;
 3233             description/@lang=en)
 3234                 read line
 3235                 [[ $line == /patch/description=* ]] && longdesc=${line##*=} 
 3236                 longdesc=${longdesc%} longdesc=${longdesc///=}
 3237                 ;;
 3238             summary/@lang=en)
 3239                 read line
 3240                 [[ $line == /patch/summary=* ]] && shortdesc=${line##*=} ;;
 3241             license-to-confirm)
 3242                 read line
 3243                 [[ $line == /patch/license-to-confirm=* ]] && PREINFO=1 license=${line##*=} || read line
 3244                 [[ $line == /patch/license-to-confirm=* ]] && PREINFO=1 license=${line##*=} 
 3245                 ;;
 3246             atoms/package/pkgfiles/patchrpm/location/@href=*)
 3247                 patchrpm=${line##*=} ;;
 3248             atoms/package/pkgfiles/patchrpm/size/@package=*)
 3249                 patchsize=${line##*=} ;;
 3250             atoms/package/pkgfiles/patchrpm/base-version/@ver=*)
 3251                 patchbase=${line##*=} ;;
 3252             atoms/package/pkgfiles/patchrpm/base-version/@rel=*)
 3253                 patchbase=$patchbase-${line##*=} ;;
 3254             atoms/package/pkgfiles/deltarpm/location/@href=*)
 3255                 deltarpm1=${line##*=} ;;
 3256             atoms/package/pkgfiles/deltarpm/size/@package=*)
 3257                 deltasize1=${line##*=} ;;
 3258             atoms/package/pkgfiles/deltarpm/base-version/@ver=*)
 3259                 deltabasever=${line##*=} ;;
 3260             atoms/package/pkgfiles/deltarpm/base-version/@rel=*)
 3261                 deltabaserel=${line##*=}
 3262                 cacheinfo=pkg_${pkg//[^a-zA-Z0-9_]/_} cacheinfo=(${!cacheinfo})
 3263                 currentversion=${cacheinfo[0]}
 3264                 myEcho 2 "Checking if delta RPM $deltabasever-$deltabaserel for $pkg-$currentversion works ..."
 3265                 if [[ -n $deltaseqinfo && $deltabasever-$deltabaserel == $currentversion ]] && applydeltarpm -c -s "$deltaseqinfo" 2>/dev/null ; then
 3266                     myWarn 3 "Found delta for $pkg: $deltarpm1"
 3267                     deltasize=$deltasize1
 3268                     deltarpm=$deltarpm1
 3269                 else
 3270                     deltasize=0
 3271                     deltarpm=unknown
 3272                 fi
 3273                 ;;
 3274             atoms/package/pkgfiles/deltarpm/base-version/@sequence_info=*)
 3275                 deltaseqinfo=${line##*=} ;;
 3276             atoms/script/do=*)
 3277                 scriptcode=${line##*=} ; scriptcode=${scriptcode///
 3278 }
 3279                 processXMLDescRPM ;;
 3280             # *) echo "line $line" ;;
 3281             esac
 3282         done < $xmlparsed
 3283         if [[ $readingPkg -eq 1 ]] ; then
 3284             processXMLDescRPM
 3285         fi
 3286         rm -f $xmlparsed
 3287     done
 3288 }
 3289 
 3290 ################################# processPatchDescriptions
 3291 # cycle through all package description files
 3292 # Parameters:
 3293 # $*: the patch description files
 3294 function processPatchDescriptions()
 3295 {
 3296     local rpm pkg newversion size newbuildtime filename patchbase patchsize
 3297     local sourcerpm readingPkg series updateinfoshown shortdesc newhdsize kind
 3298     local POSTINFO PREINFO FORCEINSTALL PENDINGCOUNT PENDINGARRAY
 3299     local UPDATEONLYINSTALLED SAFEPKGDESC i deltasize deltarpm
 3300     myEcho 2 "Need to check $# package information files on $server"
 3301     [[ $# -eq 0 ]] && return
 3302     [[ $USEPROGRESS -eq 1 ]] && MAXCOUNT=`grep ^Filename: $* 2>/dev/null| wc -l`
 3303     [[ $MAXCOUNT == 0 ]] && MAXCOUNT=1 # otherwise div/0 would occur ...
 3304     ALLCOUNT=0 # reset progress bar
 3305     for i in $* ; do
 3306         pkgdescname=${i##*/}
 3307         myNote 3 "########## Processing patch description $i"
 3308         [[ ! -f $i ]] && myWarn 2 "Missing patch description $i" && continue
 3309         cachefile=$CACHEDIR/.cache.$HOSTNAME/$i.$LANGUAGE
 3310         newbuildtime=0
 3311         rpm=unknown pkg=unknown newversion=0.0-0 size=0 newbuildtime=0 newhdsize=0
 3312         filename=unknown.rpm patchbase= patchsize=0 sourcerpm=unknown oldhdsize=0
 3313         kind=unknown
 3314         readingPkg=0 #currently (not) reading a package info from the pkgdesc file
 3315         series=default # initialisation to sane defaults
 3316         updateinfoshown=0 # indicates if update information has been shown
 3317         shortdesc= # short description
 3318         POSTINFO=0 # postinstall information present?
 3319         FORCEINSTALL=0 # force installation because of installtrigger
 3320         PREINFO=0 PENDINGCOUNT=0 PENDINGARRAY=()
 3321         UPDATEONLYINSTALLED=0 # default!!
 3322         SAFEPKGDESC=$SKIPGPG # use default from disable gpg option
 3323         deltarpm=unknown deltasize=0
 3324         if [[ $USECACHE -ge 1 ]] ; then
 3325             if [[ -f $cachefile && $cachefile -nt $i ]] ; then
 3326                 for cf in $cachefile.* ; do
 3327                     if [[ -f $cf ]] ; then
 3328                         source $cf
 3329                         if [[ $LISTAVAILRPMS -eq 1 ]] ; then # only show available rpms
 3330                             showRpmSummary
 3331                         else
 3332                             checkPackage
 3333                         fi
 3334                     fi
 3335                 done
 3336                 continue
 3337             fi
 3338             mkdir -p ${cachefile%/*} # create directory for cache file
 3339             rm -f $cachefile*
 3340             touch $cachefile # empty dummy
 3341         fi
 3342         while read tag rest; do
 3343             if [[ -z $tag && $readingPkg -eq 0 ]] ; then
 3344                 continue
 3345             fi
 3346             tag=${tag//\`/}  # kill special shell characters
 3347             tag=${tag//\$(/} # kill special shell characters
 3348             # if we are currently reading a package, it is finished with one of
 3349             # the following strings
 3350             if [[ $readingPkg -eq 1 ]] ; then
 3351                 processpkg=0
 3352                 case "$tag" in
 3353                 Segakcap:|-----BEGIN|Filename:)
 3354                     [[ $pkg != unknown && -n $pkg ]] && processpkg=1 ;;
 3355                 esac
 3356                 if [[ $processpkg -eq 1 ]] ; then
 3357                     if [[ $LISTAVAILRPMS -eq 1 ]] ; then # only show available rpms
 3358                         showRpmSummary
 3359                     else
 3360                         pkg=${pkg%%-$newversion*}
 3361                         pkg1=${pkg//[^a-zA-Z0-9_-]/}
 3362                         if [[ $USECACHE -ge 1 ]] ; then
 3363                             for p in pkg rpm newversion kind size newbuildtime series filename shortdesc patchbase patchsize newhdsize sourcerpm PREINFO POSTINFO UPDATEONLYINSTALLED deltasize deltarpm; do
 3364                                 echo "$p='${!p//\'/\"}'" >> $cachefile.$pkg1
 3365                             done
 3366                         fi
 3367                         checkPackage # "$pkg" "$rpm" "$newversion" "$kind" "$size" "$patchsize" "$newbuildtime" "$series" "$filename" "$shortdesc"
 3368                     fi
 3369                     # reset values in case that the next loop will not refill them
 3370                     series=default rpm=unknown pkg=unknown filename=unknown.rpm
 3371                     newversion=0.0-0 size=0 newbuildtime=0 readingPkg=0 shortdesc=
 3372                     patchbase= patchsize=0 sourcerpm=unknown newhdsize=0 deltasize=0
 3373                     deltarpm=unknown
 3374                 fi
 3375             fi
 3376 
 3377             case "$tag" in # get tags from patch description
 3378             Deltas:)
 3379                 [[ $readingPkg -eq 0 ]] && continue
 3380                 [[ $USEDELTARPMS -lt 0 ]] && continue
 3381                 while true ; do
 3382                     read tag rest
 3383                     [[ $tag == Satled: ]] && break
 3384                     rest=($rest) # make array
 3385                     myEcho 2 "Checking if delta RPM for $pkg works ..."
 3386                     if applydeltarpm -c -s "${rest[5]}" 2>/dev/null ; then
 3387                         # we assume that there is only one matching delta rpm
 3388                         deltasize=${rest[0]}
 3389                         deltarpm="$tag"
 3390                         myEcho 3 "Found delta for $pkg: $tag"
 3391                     fi
 3392                 done
 3393             ;;
 3394             UpdateOnlyInstalled:)
 3395                 if [[ $rest == true ]] ; then
 3396                     UPDATEONLYINSTALLED=1
 3397                 fi ;;
 3398             Filename:)
 3399                 pkg=${rest%%.rpm}
 3400                 readingPkg=1 # we have found a new package within the pkgdesc
 3401                 filename=$rest ;;
 3402             Version:)
 3403                 newversion=$rest
 3404                 if [[ -z $newversion ]] ; then
 3405                     newversion=fix-me
 3406                     [[ $VERBOSE -ge 1 ]] && \
 3407                         echo "Invalid version found in $i! Please read http://fou4s.gaugusch.at/problems.shtml and report to fou4s@gaugusch.at if it is not known." | fmt -$COLUMNS
 3408                 fi ;;
 3409             BuiltFrom:)
 3410                 sourcerpm="rpm/src/$rest" ;;
 3411             Prescript:*|Postscript:*)
 3412                 series=script
 3413                 FORCEINSTALL=1 # because we have no version comparison
 3414                 [[ -z $rest ]] && rest=${tag##Prescript:} # fix missing blank
 3415                 pkg=$rest rpm=scripts/$rest newversion=script kind=script size=0
 3416                 pkg1=$pkg
 3417                 patchsize=0 newbuildtime=0
 3418                 if [[ $USECACHE -ge 1 ]] ; then
 3419                     for p in pkg rpm newversion kind size patchsize newbuildtime series filename shortdesc patchbase newhdsize sourcerpm PREINFO POSTINFO UPDATEONLYINSTALLED FORCEINSTALL; do
 3420                         echo "$p='${!p//\'/\"}'" >> $cachefile.$pkg1
 3421                     done
 3422                 fi
 3423                 checkPackage # "$rest" "scripts/$rest" "script" "script" "0" "0" "0" "$series" "$rest" "$shortdesc"
 3424                 break ;;
 3425             Shortdescription.english:)
 3426                 [[ -z $shortdesc ]] && shortdesc=${rest//\`/\'} shortdesc=${shortdesc//$/$ } ;;  # vim syntax helper: '
 3427             Shortdescription.$LANGUAGE:)
 3428                 [[ -n $rest ]] && shortdesc=${rest//\`/\'} shortdesc=${shortdesc//$/$ } ;;  # vim syntax helper: '
 3429             InstPath:)
 3430                 rpm=$rest ;;
 3431             Kind:)
 3432                 kind=$rest ;;
 3433             Postinformation.english*|Postinformation.$LANGUAGE*)
 3434                 POSTINFO=1 ;;
 3435             Preinformation.english*|Preinformation.$LANGUAGE*)
 3436                 PREINFO=1 ;;
 3437             Series:)
 3438                 series=$rest
 3439                 if [[ $NODOTSUSEVERSION -ge 92 ]] ; then
 3440                     [[ -n $series && $series != default && $series != @(${VALIDARCHS// /|}) ]] && readingPkg=0 && myEcho 2 Ignoring package $pkg with foreign arch $series
 3441                 fi
 3442                 [[ -z $series ]] && series="default" ;;
 3443             Size:)
 3444                 [[ $readingPkg -eq 0 ]] && continue
 3445                 size=($rest) # convert to an array
 3446                 newhdsize=${size[0]}
 3447                 size=${size[1]} # get second field
 3448                 if [[ -z $size ]] ; then
 3449                     size=0
 3450                     [[ -n $newhdsize ]] && size=$newhdsize
 3451                     myEcho 2 "$pkg: Invalid size! Using $size"
 3452                 fi
 3453                 ;;
 3454             PatchRpmSize:)
 3455                 rest=($rest)
 3456                 patchsize=${rest[1]} # get second field
 3457                 ;;
 3458             PatchRpmBasedOn:)
 3459                 patchbase=$rest
 3460                 ;;
 3461             Buildtime:)
 3462                 newbuildtime=$rest ;;
 3463             Installtrigger:)
 3464                 if [[ $SAFEMODE -eq 0 && $i != *-G ]] ; then
 3465                     hasGoodSignature "`gpg --no-tty --verify "$i" 2>&1`" DSA 9C800ACA "SuSE Package Signing Key <build@suse.de>"
 3466                     ret=$?
 3467                     if [[ $ret -eq 0 ]] ; then
 3468                         SAFEPKGDESC=1
 3469                     elif [[ $ret -eq 254 ]] ; then
 3470                         myEcho 3 "No signature in patch description ${i##*/} - using safe mode!"
 3471                     else
 3472                         [[ $QUIET -eq 0 ]] && myEcho 0 "Invalid signature in patch description ${i##*/} - using safe mode!"
 3473                     fi
 3474                 fi
 3475                 handleInstallTrigger ;;
 3476             esac;
 3477         done < $i
 3478     done
 3479 } # processPatchDescriptions
 3480 
 3481 
 3482 ################################# addToSkippedPatches
 3483 # Adds one or more entries to the skipped-patches file
 3484 # parameters:
 3485 # $*: The entries to add
 3486 function addToSkippedPatches()
 3487 {
 3488     local pwd=$PWD
 3489     cd "$BASEDIR"
 3490     printf "%s\n" $* >> $SKIPPEDPATCHESFILE
 3491     cd "$pwd"
 3492 
 3493     # prevent creating cache with bogus data at end of program
 3494     [[ $USECACHE -eq 2 ]] && USECACHE=1
 3495     rm -f $DESCCACHE $AUTOSKIPPEDPATCHESFILE &>/dev/null #force creation next time
 3496 } # addToSkippedPatches
 3497 
 3498 
 3499 ################################# getOptionsFromConfigFile
 3500 # get options from config file
 3501 # Parameters:
 3502 # $1: filename
 3503 function getOptionsFromConfigFile()
 3504 {
 3505     local CONFIGFILE=$1
 3506     if [[ -f $CONFIGFILE ]] ; then
 3507         while read optval ; do
 3508             optval=${optval%%#*}
 3509             [[ -z $optval ]] && continue
 3510             key=${optval%%=*}
 3511             value=${optval#*=}
 3512             case $key in
 3513             DefaultVerbosity)
 3514                 VERBOSE=`checkOption "$value" $key $VERBOSE range 0 3` ;;
 3515             Proxy)
 3516                 export ALL_PROXY=`checkOption "$value" $key $ftp_proxy`
 3517                 export http_proxy=`checkOption "$value" $key $http_proxy`
 3518                 export https_proxy=`checkOption "$value" $key $https_proxy`
 3519                 export HTTPS_PROXY=`checkOption "$value" $key $https_proxy`
 3520                 export ftp_proxy=`checkOption "$value" $key $ftp_proxy`
 3521                 export FTP_PROXY=`checkOption "$value" $key $ftp_proxy` ;;
 3522             AcceptPreinstallInfo)
 3523                 ACCEPTPREINSTALLINFO=`checkOption "$value" $key $ACCEPTPREINSTALLINFO` ;;
 3524             Arch)
 3525                 ARCH=`checkOption "$value" $key $ARCH`
 3526                 FORCEDARCH=$ARCH ;;
 3527             Auto)
 3528                 AUTOLIST=`checkOption "$value" $key "$AUTOLIST"` ;;
 3529             Benchmark)
 3530                 BENCHMARK=`checkOption "$value" $key $BENCHMARK bool` ;;
 3531             CacheDir)
 3532                 CACHEDIR=`checkOption "$value" $key $CACHEDIR` ;;
 3533             CheckFou4s)
 3534                 CHECKFOU=`checkOption "$value" $key $CHECKFOU bool` ;;
 3535             ColorOutput)
 3536                 COLOR=`checkOption "$value" $key $COLOR bool` ;;
 3537             Compatible)
 3538                 COMPATIBLE=`checkOption "$value" $key $COMPATIBLE bool` ;;
 3539             DescriptionCache)
 3540                 USECACHE=`checkOption "$value" $key $USECACHE range 0 2` ;;
 3541             Exclude)
 3542                 EXCLUDELIST=`checkOption "$value" $key "$EXCLUDELIST"` ;;
 3543             KernelBackup)
 3544                 KERNELBACKUP=`checkOption "$value" $key "$KERNELBACKUP" bool` ;;
 3545             KernelCheck)
 3546                 KERNELCHECK=`checkOption "$value" $key "$KERNELCHECK" bool` ;;
 3547             Language)
 3548                 LANGUAGE=`checkOption "$value" $key "$LANGUAGE"` ;;
 3549             RpmDir)
 3550                 DLPATH=`checkOption "$value" $key $DLPATH` ;;
 3551             SuSEUser)
 3552                 HTTPUSER=`checkOption "$value" $key $HTTPUSER` ;;
 3553             SuSEPassword)
 3554                 HTTPPASSWD=`checkOption "$value" $key $HTTPPASSWD` ;;
 3555             TestMode)
 3556                 TESTMODE=`checkOption "$value" $key $TESTMODE bool` ;;
 3557             IgnoreList)
 3558                 IGNORELIST=`checkOption "$value" $key "$IGNORELIST"` ;;
 3559             Interactive)
 3560                 INTERACTIVE=`checkOption "$value" $key $INTERACTIVE bool` ;;
 3561             InverseColor)
 3562                 INVERSE=`checkOption "$value" $key $INVERSE bool`
 3563                 [[ $INVERSE -eq 1 ]] && BRIGHT=0 ;;
 3564             LogFile)
 3565                 LOGFILE=`checkOption "$value" $key $LOGFILE` ;;
 3566             LogLevel)
 3567                 LOGLEVEL=`checkOption "$value" $key $LOGLEVEL range 0 3` ;;
 3568             OlderThan)
 3569                 DAYSOLDER=`checkOption "$value" $key $LOGLEVEL range 0 10000` ;;
 3570             ProxyDigest)
 3571                 PROXYDIGEST=`checkOption "$value" $key $PROXYDIGEST bool` ;;
 3572             ProxyUser)
 3573                 PROXYUSER=`checkOption "$value" $key $PROXYUSER` ;;
 3574             ProxyPasswd)
 3575                 PROXYPASS=`checkOption "$value" $key $PROXYPASS` ;;
 3576             RemarkList)
 3577                 REMARKLIST=`checkOption "$value" $key "$REMARKLIST"` ;;
 3578             RemoveAfterInstall)
 3579                 REMOVE=`checkOption "$value" $key $REMOVE bool` ;;
 3580             Server)
 3581                 SERVERLIST="$SERVERLIST `checkOption "$value" $key "$SERVERLIST"`";;
 3582             SourceRpms)
 3583                 SRCRPMS="$SRCRPMS `checkOption "$value" $key "$SRCRPMS"`";;
 3584             SuSEProduct)
 3585                 SUSEPRODUCT=`checkOption "$value" $key "$SUSEPRODUCT"` ;;
 3586             SuSEVersion)
 3587                 SUSEVERSION=`checkOption "$value" $key $SUSEVERSION` ;;
 3588             UseDeltaRpms)
 3589                 USEDELTARPMS=`checkOption "$value" $key $USEDELTARPMS bool` ;;
 3590             UseCurl)
 3591                 USECURL=`checkOption "$value" $key $USECURL` ;;
 3592             UseDir)
 3593                 USEDIR=`checkOption "$value" $key $USEDIR` ;;
 3594             UsePatchRpms)
 3595                 PATCHRPMS=`checkOption "$value" $key $PATCHRPMS bool` ;;
 3596             PackageListDir|RSyncServer|GpdList|UseFullPath)
 3597                 myWarn 0 "Fou4s Warning: Please remove the obsolete option $key from $CONFIGFILE";;
 3598             *)
 3599                 myError 0 "Error: Unknown option in $CONFIGFILE: $key"
 3600                 exit 2 ;;
 3601             esac
 3602         done < $CONFIGFILE
 3603     fi
 3604 } # getOptionsFromConfigFile vim"
 3605 
 3606 
 3607 # 'compile' the lists into patterns
 3608 # need to squeeze separators first
 3609 # then introduce | as separator
 3610 function listsToPatterns()
 3611 {
 3612     local listvar tmp
 3613     set -f # no globbing
 3614     # eval because it makes extension easier
 3615     for listvar in $*; do
 3616         IFS=$' \t\n,'; tmp=(${!listvar})     # split on whitespace and comma
 3617         IFS="|"; eval $listvar="'${tmp[*]}'" # join with "|"
 3618         IFS=$' \t\n' # restore standard IFS
 3619     done
 3620     set +f
 3621 } # listsToPatterns vim"
 3622 
 3623 
 3624 ################################# revert
 3625 # Revert a text and change first letter to a capital
 3626 function revert()
 3627 {
 3628     local i j text=$1 res first
 3629     text=`echo "$text" | tr '[A-Z]' '[a-z]'`
 3630     local len=${#text}
 3631     len=$((len-1))
 3632     for i in `seq 1 $len` ; do
 3633         i=$((i-1))
 3634         j=$((i-1))
 3635         res="${text:$i:1}$res"
 3636     done
 3637     res="`echo ${text:$len:1} | tr "[a-z]" "[A-Z]"`$res"
 3638     echo $res
 3639 } # revert
 3640 
 3641 
 3642 ################################# optionPostProcessing
 3643 # updates some variables after all options and arguments have been read
 3644 function optionPostProcessing()
 3645 {
 3646     local o
 3647     [[ -x `which dcop &>/dev/null` && -n $KONSOLE_DCOP_SESSION ]] && o=`dcop $KONSOLE_DCOP_SESSION schema` && [[ $o == "" ]] && INVERSE=1
 3648     [[ $INVERSE -eq 1 ]] && BRIGHT=0
 3649     # use color if stdin is a terminal - use | less -R to get colored
 3650     # output when piping to less!
 3651     if [[ $COLOR -eq 1 && -t 0 ]]; then
 3652         COL_RED="\033[$BRIGHT;31m"
 3653         COL_GREEN="\033[$BRIGHT;32m"
 3654         COL_YELLOW="\033[$BRIGHT;33m"
 3655         COL_WHITE="\033[$BRIGHT;37m"
 3656         COL_CYAN="\033[$BRIGHT;36m"
 3657         COL_BLACK="\033[0;30m"
 3658         COL_NORM="\033[0m"
 3659         if [[ $INVERSE -eq 1 ]] ; then
 3660             COL_WHITE="\033[$BRIGHT;30m" # black
 3661             COL_YELLOW="\033[0;33m" # dark yellow
 3662             COL_CYAN="\033[$BRIGHT;34m" # blue
 3663         fi
 3664     fi
 3665     # determine suse version from filename of rpmcache when in offline mode
 3666     EGAUGNAL=`revert $LANGUAGE` # reverse string of language
 3667     if [[ $LANGUAGE != english && -f `which recode 2>&1` ]] ; then
 3668         DORECODE=1
 3669     fi
 3670     RPMVER=`rpm --version` # used for signature verification
 3671     RPMVER=${RPMVER##*version }
 3672     [[ $RPMVER == 4.0* ]] && RPMVER=30 # hack for puretec suse 8.0 with rpm v4
 3673     [[ $RPMVER == 4.4.* ]] && RPMVER=44
 3674     [[ $RPMVER == 4.7.* ]] && RPMVER=47
 3675     [[ $RPMVER == 4.8.* ]] && RPMVER=48
 3676     [[ $RPMVER == 4.9.* ]] && RPMVER=49
 3677     RPMVER=${RPMVER%%.*}
 3678     [[ -z $RPMVER ]] && RPMVER=30 # just for safety
 3679     [[ $RPMVER -lt 10 ]] && RPMVER=${RPMVER}0
 3680     if [[ -t 0 ]] ; then
 3681         COLUMNS=`stty size| cut -d " " -f 2`
 3682     fi
 3683     [[ -z $COLUMNS ]] && COLUMNS=80
 3684 
 3685     if [[ $EXPORT -eq 1 && $EXPORTFILE == *.tar ]] ; then
 3686         [[ $EXPORTFILE != /* ]] && EXPORTFILE="$PWD/${EXPORTFILE#./}"
 3687         OFFLINE=1 # don't query host if exporting for it!
 3688         SUSEVERSION="*[0-9]" # must end with a number
 3689     elif [[ $EXPORT -eq 1 && $EXPORTFILE != *.fou ]] ; then
 3690         myError 0 "The parameter --export takes either a .fou file (offline machine) or a .tar file (internet connected machine)" | fmt -$COLUMNS
 3691         exit 14
 3692     fi
 3693 
 3694 #   if [[ $MACHINEARCH == i?86 ]] ; then # don't allow i686 on i586 machines, etc
 3695 #       VALIDARCHS=noarch
 3696 #       for a in i386 i486 i586 i686 i786 ; do
 3697 #           VALIDARCHS="$VALIDARCHS $a"
 3698 #           [[ $a == $MACHINEARCH ]] && break
 3699 #       done
 3700 #   elif [[ $MACHINEARCH == x86_64 ]] ; then #amd64 also works with ix86 pkg
 3701 #       VALIDARCHS="noarch i386 i486 i586 i686 x86_64"
 3702 #   fi
 3703     RPMCACHE=$CACHEDIR/.cache.$HOSTNAME/rpmcache.$SUSEVERSION # cache file with all versions
 3704     if [[ $SUSEVERSION == \*\[0-9\] ]] ; then
 3705         SUSEVERSION=`echo $RPMCACHE` # glob filename
 3706         if [[ $SUSEVERSION == *\ * ]] ; then
 3707             myError 0 "More than one cache file was found, please check $RPMCACHE"
 3708             exit 20
 3709         fi
 3710         SUSEVERSION=${SUSEVERSION##*/} # strip path
 3711         SUSEVERSION=${SUSEVERSION#*.} # strip "rpmcache."
 3712         NODOTSUSEVERSION=${SUSEVERSION//.} # rebuild
 3713         RPMCACHE=$CACHEDIR/.cache.$HOSTNAME/rpmcache.$SUSEVERSION # rebuild
 3714     fi
 3715 
 3716     if [[ $OFFLINE -eq 1 && ! -f $RPMCACHE ]] ; then
 3717         myError 0 "RPM cache for host $HOSTNAME not found - please import with --import or don't use --offline" | fmt -$COLUMNS
 3718         myError 2 "Cachefile is $RPMCACHE"
 3719         exit 15
 3720     fi
 3721     if [[ $IMPORT -eq 1 && -f $IMPORTFILE ]] ; then
 3722         if [[ $IMPORTFILE == *.fou ]] ; then
 3723             SUSEVERSION=`zgrep '^SUSEVERSION=' "$IMPORTFILE"`
 3724             SUSEVERSION=${SUSEVERSION##SUSEVERSION=}
 3725             SUSEPRODUCT=`zgrep '^SUSEPRODUCT=' "$IMPORTFILE"`
 3726             SUSEPRODUCT=${SUSEPRODUCT##SUSEPRODUCT=}
 3727             RPMCACHEVERSION=`zgrep '^RPMCACHEVERSION=' "$IMPORTFILE"`
 3728             RPMCACHEVERSION=${RPMCACHEVERSION##RPMCACHEVERSION=}
 3729             HOSTNAME=`zgrep '^HOSTNAME=' "$IMPORTFILE"`
 3730             HOSTNAME=${HOSTNAME##HOSTNAME=}
 3731             if [[ $HOSTNAME == `hostname` ]] ; then
 3732                 myError 0 "Cannot import for localhost! Use --host to specify the host"
 3733                 exit 15
 3734             fi
 3735             if [[ $RPMCACHEVERSION != $RPMCACHEVER ]] ; then
 3736                 myError 0 "The exporting machine uses a too old version of fou4s, import failed!"
 3737                 exit 15
 3738             fi
 3739             cleanCache
 3740             RPMCACHE=$CACHEDIR/.cache.$HOSTNAME/rpmcache.$SUSEVERSION # cache file with all versions
 3741             if [[ ! -d `dirname $RPMCACHE.gz` ]] ; then
 3742                 mkdir -p `dirname $RPMCACHE.gz`
 3743             fi
 3744             cp "$IMPORTFILE" $RPMCACHE.gz && rm -f $RPMCACHE
 3745             gunzip $RPMCACHE.gz
 3746             myNote 0 "Successfully imported `basename $IMPORTFILE` (${SUSEPRODUCT:=SuSE} $SUSEVERSION) from host $HOSTNAME. Now run"
 3747             myNote 0 "fou4s -u --host $HOSTNAME --export myExport.tar"
 3748             myWarn 0 "Then copy myExport.tar to target machine and run"
 3749             myNote 0 "fou4s --import myExportfile.tar -i"
 3750             exit 0
 3751         elif [[ $IMPORTFILE == *.tar ]] ; then
 3752             myNote 0 "Importing packages ..."
 3753             if [[ $IMPORTFILE != /* ]] ; then
 3754                 IMPORTFILE=$PWD/$IMPORTFILE # relative path to fixed path conversion
 3755             fi
 3756             for SERVERURL in $SERVERLIST; do
 3757                 server=${SERVERURL#@(ftp|http|https|rsync)://} server=${server%%/*}
 3758                 server=${server##*@}
 3759                 break # only use first server
 3760             done
 3761             cd "$BASEDIR" ;
 3762             mkdir -p "$DLPATH/$server"
 3763             cd "$DLPATH/$server"
 3764             tar xf $IMPORTFILE
 3765             myNote 0 "Successfully imported `basename $IMPORTFILE`"
 3766             exit 0
 3767         else
 3768             myError 0 "Error: Importfile must be named '*.fou' or '*.tar'!"
 3769             exit 16
 3770         fi
 3771     elif [[ $IMPORT -eq 1 ]] ; then
 3772         myError 0 "Error: Importfile $IMPORTFILE does not exist!"
 3773         exit 16
 3774     fi
 3775     # diable progressbar on verbose level ge 2
 3776     [[ $VERBOSE -lt 2 ]] || USEPROGRESS=0
 3777 
 3778     if [[ $LIMIT -ne 0 ]] ; then
 3779         RSYNCOPTS="$RSYNCOPTS --bwlimit $LIMIT"
 3780         GLOBALWGETOPTS="$GLOBALWGETOPTS --limit-rate ${LIMIT}k"
 3781         GLOBALCURLOPTS="$GLOBALCURLOPTS --limit-rate ${LIMIT}k"
 3782     fi
 3783 
 3784     # NODOTSUSEVERSION=${SUSEVERSION//./} # SuSE version without dots for comparisons # removed because of SLES9 bug (C. Thiel)
 3785     SERVERLIST=${SERVERLIST//,/ } # remove "," and replace with space
 3786     #DLPATH=$CACHEDIR/packages # default path for downloaded RPMs # FIXME don't overwrite always, only if dlpath has default value
 3787     DESCCACHE=$CACHEDIR/.cache.$HOSTNAME/descriptioncache.$SUSEVERSION # cache of patch descriptions
 3788     listsToPatterns AUTOLIST EXCLUDELIST IGNORELIST REMARKLIST USERRPMS SRCRPMS
 3789 
 3790     if [[ $SERVERLIST == *rsync://* && -z `type -p rsync` ]] ; then
 3791         myError 0 "You have an rsync server configured, but rsync is not installed. Aborting!"
 3792         exit 9
 3793     fi
 3794     if [[ -z `type -p wget` ]] ; then
 3795         myEcho 2 "wget not found, falling back to curl ..."
 3796         USECURL=1
 3797     fi
 3798     # curl requires usedir (don't move into above if, because USECURL might
 3799     # be set by an option or parameter as well!)
 3800     [[ $USECURL -eq 1 ]] && USEDIR=1
 3801     [[ $NODOTSUSEVERSION -ge 101 ]] && USEDIR=1
 3802     [[ $NODOTSUSEVERSION -ge 110 ]] && PATCHRPMS=0
 3803 
 3804     # output colum sizes
 3805     [[ -n $COLUMNS && $COLUMNS -gt 86 ]] && RWIDTH=$((RWIDTH+COLUMNS-86))
 3806 
 3807     if [[ $GETSOURCE -eq 1 && $DOINSTALL -eq 1 ]] ; then
 3808         myError 0 "Source RPM's cannot be installed. Use fou4s -ed to download them and copy from $DLPATH/.../rpm/src to a directory of your choice." | fmt -$COLUMNS
 3809         exit 10
 3810     fi
 3811 
 3812     if [[ -n $SUSEPRODUCT ]] ; then
 3813         SUSEPRODUCT=$SUSEPRODUCT/  # append slash
 3814         if [[ $SERVERLIST == *ftp.gwdg.de* ]] ; then
 3815             myWarn 0 "You are using ftp.gwdg.de and a business product, this will probably not work. Set SuSEUser= and SuSEPassword= in fou4s.conf and use sdb.suse.de as update server." | fmt -$COLUMNS
 3816             echo
 3817         fi
 3818         if [[ -z $HTTPUSER && $AUTOMODE -eq 0 ]] ; then
 3819             myWarn 0 "WARNING: You are using a business product and haven't given a username."
 3820             myWarn 0 "Edit $CONFIGFILE and search for SuSEUser= and SuSEPassword="
 3821         fi
 3822     fi
 3823     if [[ -n $HTTPUSER && -n $HTTPPASSWD ]] ; then
 3824         AUTHOPTS="--user $HTTPUSER --pass $HTTPPASSWD"
 3825     elif [[ -n $HTTPUSER || -n $HTTPPASSWD ]] ; then
 3826         myWarn 0 "WARNING: You must give a password for http auth, too!"
 3827     fi
 3828 
 3829     # must be set after reading config file and checking parameter
 3830     if [[ -z $SUSEVERSION ]]; then
 3831         myError 0 "Cannot determine SuSE-Version from /etc/SuSE-release or config file"
 3832         myError 0 "Exiting..."
 3833         exit 2
 3834     fi
 3835     [[ $NODOTSUSEVERSION -ge 101 ]] && SERVERPATH=update/$SUSEPRODUCT$SUSEVERSION || SERVERPATH=$ARCH/update/$SUSEPRODUCT$SUSEVERSION
 3836     if [[ $NODOTSUSEVERSION -ge 101 && $SUSEVERSION == 10 ]] ; then
 3837          SERVERPATH=/ # for SLES 10
 3838     fi
 3839 
 3840     if [[ -n $http_proxy && $http_proxy != http://*:*/ ]] ; then
 3841         echo "Proxy must start with http:// and end with / (e.g. http://proxy:8080/)"
 3842         echo "Please check your http_proxy environment variable"
 3843         exit 11
 3844     fi
 3845     #if [[ -n $ftp_proxy ]] ; then
 3846     #   if [[ $ftp_proxy != http://*:*/ ]] ; then
 3847     #       echo "Proxy must start with http:// and end with / (e.g. http://proxy:8080/)"
 3848     #       echo "Please check your ftp_proxy environment variable"
 3849     #       exit 1
 3850     #   fi
 3851     #fi
 3852 
 3853     if [[ -n $PROXYUSER ]] ; then
 3854         GLOBALWGETOPTS="$GLOBALWGETOPTS --proxy-user=$PROXYUSER" 
 3855         if [[ $PROXYDIGEST -eq 1 ]] ; then
 3856             GLOBALCURLOPTS="$GLOBALCURLOPTS --proxy-digest -U $PROXYUSER:$PROXYPASS"
 3857             USECURL=1
 3858         else
 3859             GLOBALCURLOPTS="$GLOBALCURLOPTS --proxy-basic -U $PROXYUSER:$PROXYPASS"
 3860         fi
 3861     fi
 3862 
 3863     [[ -n $PROXYPASS ]] && GLOBALWGETOPTS="$GLOBALWGETOPTS --proxy-passwd=$PROXYPASS"
 3864 
 3865     if [[ $BENCHMARK -eq 1 ]] ; then
 3866         BSERVER="`fou4s-benchmark -q | head -1 | awk '{print $2}'`"
 3867         if [[ -n $BSERVER ]] ; then
 3868             SERVERLIST=$BSERVER
 3869             echo "Using benchmarked server $SERVERURL"
 3870         else
 3871             myError 0 "Error: No benchmark server found! Using default ..."
 3872         fi
 3873     fi
 3874 
 3875     if [[ $CHECKFOU -eq 1 && $NODOTSUSEVERSION -ge 101 ]] ; then
 3876         SERVERLIST="http://fou4s.gaugusch.at $SERVERLIST"
 3877     fi
 3878 
 3879     if [[ ! -d $CACHEDIR/.cache.$HOSTNAME ]] ; then
 3880         mkdir "$CACHEDIR/.cache.$HOSTNAME"
 3881     fi
 3882     Fou4skey=`echo $FOU4SKEY | tr "[A-Z]" "[a-z]"`
 3883 
 3884     if [[ $NODOTSUSEVERSION -lt 92 ]] || ! type -p applydeltarpm >/dev/null ; then
 3885         USEDELTARPMS=-1
 3886     fi
 3887     
 3888     if [[ $NODOTSUSEVERSION -ge 101 ]] ; then
 3889         PATCHDIR=repodata
 3890     fi
 3891     for g in "$DIRNAME/xmlp.awk" /usr/bin/xmlp.awk /usr/local/bin/xmlp.awk ; do
 3892         [[ -x $g ]] && XMLP=$g && break
 3893         g=""
 3894     done
 3895 } # optionPostProcessing
 3896 
 3897 
 3898 ################################# doStartupChecks
 3899 # performs some initial checks that are needed for running fou4s
 3900 function doStartupChecks()
 3901 {
 3902     if [[ ! -d $DLPATH ]] ; then
 3903         echo "You need to create a directory to store the downloaded packages: $DLPATH (change $CONFIGFILE for a different path)"| fmt -$COLUMNS
 3904         echo "Exiting ..."
 3905         exit 2
 3906     fi
 3907     if [[ $CHECKONLY -eq 0 && $UPDATESERVERLIST -eq 0 && $UPDATEPACKAGELIST -eq \
 3908         0 && $DOINSTALL -eq 0 && $LISTAVAILRPMS -eq 0 && $EXPORT -eq 0 && \
 3909         $IMPORT -eq 0 ]] ; then
 3910         echo "Please use one of -u, -e, -i, -l, --auto or --server!"
 3911         exit 2
 3912     fi
 3913     [[ -f $CACHEDIR/descr_packages.$SUSEVERSION ]] && PACKAGES81=$CACHEDIR/descr_packages.$SUSEVERSION
 3914     for f in $PACKAGES81 ; do
 3915         if [[ ! -f $f ]] ; then
 3916             myWarn 0 "Warning: $f can't be read. Run fou4s --fixperm to enable access for members of group fou4s or check if the 0x00000001 directory exists (create a link or rename the other one if not)." | fmt -80
 3917             myWarn 0 "Alternatively, fou4s can download the file to $CACHEDIR/descr_packages.$SUSEVERSION (fou4s --getpackagedescriptions), if you are not root." | fmt -80
 3918             # exit 1
 3919         fi
 3920     done
 3921     if [[ $SKIPGPG -eq 0 && ! -x `type -p gpg` ]] ; then
 3922         echo "GPG was not found. If you want to skip GPG signature checking, use"
 3923         echo "the -g option. It is highly recommended to install gpg!"
 3924         exit 2
 3925     fi
 3926 
 3927     if [[ $SKIPGPG -eq 0 ]] ; then
 3928         # check for gnupg directory for RPM (currently only on 8.0)
 3929         # it is used for key comparison when root installs packages.
 3930         [[ -d /usr/lib/rpm/gnupg && $EUID -eq 0 ]] && export GNUPGHOME=/usr/lib/rpm/gnupg
 3931         [[ $EUID -eq 0 && -z $HOME ]] && export HOME=/root
 3932 
 3933         gpgproxyopt="--keyserver-options honor-http-proxy"
 3934         if [[ $CHECKFOU -eq 1 ]] ; then
 3935             if [[ `gpg --with-colons --list-keys $FOU4SKEY 2>/dev/null | grep ^pub: | cut -f1,3-6,10 -d:` != pub:1024:17:0EA1932BAFB66D7C:2002-04-28:fou4s\ build\ key\ \<fou4s@gaugusch.at\> && $RPMVER -lt 40 ]] ; then
 3936                 myNote 0 "Installing fou4s public key ..."
 3937                 if [[ -f ./fou4s_public.gpg ]] ; then
 3938                     gpg --import ./fou4s_public.gpg
 3939                 elif [[ -f /usr/share/doc/packages/fou4s/fou4s_public.gpg ]] ; then
 3940                     gpg --import /usr/share/doc/packages/fou4s/fou4s_public.gpg
 3941                 else
 3942                     gpg $gpgproxyopt --keyserver wwwkeys.pgp.net --recv-keys $FOU4SKEY
 3943                 fi
 3944             fi
 3945             if [[ $UPDATESERVERLIST -eq 0 && $RPMVER -ge 40 && `rpm -qi gpg-pubkey-$Fou4skey 2>/dev/null` == package\ gpg-pubkey-$Fou4skey\ is\ not\ installed ]] ; then
 3946                 myNote 0 "Installing fou4s public key (rpm V4)..."
 3947                 if [[ -f ./fou4s_public.gpg ]] ; then
 3948                     rpm --import ./fou4s_public.gpg
 3949                 elif [[ -f /usr/share/doc/packages/fou4s/fou4s_public.gpg ]] ; then
 3950                     rpm --import /usr/share/doc/packages/fou4s/fou4s_public.gpg
 3951                 fi
 3952             fi
 3953         fi
 3954         if [[ `gpg --with-colons --list-keys 9C800ACA 2>/dev/null | grep ^pub: | cut -f1,3-6,10 -d:` != pub:1024:17:A84EDAE89C800ACA:2000-10-19:SuSE\ Package\ Signing\ Key\ \<build@suse.de\> && $RPMVER -lt 40 ]] ; then
 3955             myNote 0 "Installing SuSE build key ..."
 3956             gpg $gpgproxyopt --keyserver wwwkeys.pgp.net --recv-keys 9C800ACA
 3957         fi
 3958     fi
 3959 
 3960     if [[ -d $DLPATH/server0 ]] ; then
 3961         echo "Converting numbered to named server directories ..."
 3962         i=0
 3963         for SERVERURL in $SERVERLIST; do
 3964             if [[ ${BASH_VERSINFO[0]} -ge 3 ]] ; then
 3965                 SERVERURL=${SERVERURL//\%ARCH/$ARCH}
 3966                 SERVERURL=${SERVERURL//\%VERSION/$SUSEVERSION}
 3967             else
 3968                 SERVERURL=${SERVERURL//\\%ARCH/$ARCH}
 3969                 SERVERURL=${SERVERURL//\\%VERSION/$SUSEVERSION}
 3970             fi
 3971             server=${SERVERURL#@(ftp|http|https|rsync)://} server=${server%%/*}
 3972             server=${server##*@} # strip username part of urls
 3973             if [[ ! -d $DLPATH/$server ]] ; then
 3974                 mv -vf $DLPATH/server$i $DLPATH/$server
 3975             else # directory exists already - mv won't work
 3976                 cp -r $DLPATH/server$i/* $DLPATH/$server/
 3977                 rm -rf $DLPATH/server$i
 3978             fi
 3979             i=$((i+1))
 3980         done
 3981     fi
 3982     [[ $QUIET -eq 1 ]] && USEPROGRESS=0
 3983     [[ -t 1 ]] || USEPROGRESS=0 # test file descriptor of stdout
 3984 } # doStartupChecks
 3985 
 3986 
 3987 ################################# updateStatistics
 3988 # Updates the counters for different update types
 3989 function updateStatistics()
 3990 {
 3991     COUNTER[_ALL]=$((COUNTER[_ALL]+1))
 3992     SIZES[_ALL]=$((SIZES[_ALL]+size))
 3993     DLSIZES[_ALL]=$((DLSIZES[_ALL]+size-FOUNDSIZE))
 3994     [[ $newhdsize != 0 && $oldhdsize != 0 ]] && HDSIZES[_ALL]=$((HDSIZES[_ALL]+newhdsize-oldhdsize))
 3995     case $kind in
 3996         security)
 3997             SIZES[_SECURITY]=$((SIZES[_SECURITY]+size))
 3998             DLSIZES[_SECURITY]=$((DLSIZES[_SECURITY]+size-FOUNDSIZE))
 3999             [[ $newhdsize != 0 ]] && HDSIZES[_SECURITY]=$((HDSIZES[_SECURITY]+newhdsize-oldhdsize))
 4000             COUNTER[_SECURITY]=$((COUNTER[_SECURITY]+1)) ;;
 4001         recommended)
 4002             SIZES[_RECOMMENDED]=$((SIZES[_RECOMMENDED]+size))
 4003             DLSIZES[_RECOMMENDED]=$((DLSIZES[_RECOMMENDED]+size-FOUNDSIZE))
 4004             [[ $newhdsize != 0 ]] && HDSIZES[_RECOMMENDED]=$((HDSIZES[_RECOMMENDED]+newhdsize-oldhdsize))
 4005             COUNTER[_RECOMMENDED]=$((COUNTER[_RECOMMENDED]+1)) ;;
 4006         generated)
 4007             SIZES[_GENERATED]=$((SIZES[_GENERATED]+size))
 4008             DLSIZES[_GENERATED]=$((DLSIZES[_GENERATED]+size-FOUNDSIZE))
 4009             [[ $newhdsize != 0 ]] && HDSIZES[_GENERATED]=$((HDSIZES[_GENERATED]+newhdsize-oldhdsize))
 4010             COUNTER[_GENERATED]=$((COUNTER[_GENERATED]+1)) ;;
 4011         optional)
 4012             SIZES[_OPTIONAL]=$((SIZES[_OPTIONAL]+size))
 4013             DLSIZES[_OPTIONAL]=$((DLSIZES[_optional]+size-FOUNDSIZE))
 4014             [[ $newhdsize != 0 ]] && HDSIZES[_OPTIONAL]=$((HDSIZES[_OPTIONAL]+newhdsize-oldhdsize))
 4015             COUNTER[_OPTIONAL]=$((COUNTER[_OPTIONAL]+1)) ;;
 4016         YaST2)
 4017             SIZES[_YAST]=$((SIZES[_YAST]+size))
 4018             DLSIZES[_YAST]=$((DLSIZES[_YAST]+size-FOUNDSIZE))
 4019             [[ $newhdsize != 0 ]] && HDSIZES[_YAST]=$((HDSIZES[_YAST]+newhdsize-oldhdsize))
 4020             COUNTER[_YAST]=$((COUNTER[_YAST]+1)) ;;
 4021         script)
 4022             SIZES[_SCRIPT]=$((SIZES[_SCRIPT]+size))
 4023             COUNTER[_SCRIPT]=$((COUNTER[_SCRIPT]+1))
 4024             DLSIZES[_SCRIPT]=$((DLSIZES[_SCRIPT]+size-FOUNDSIZE))
 4025     esac
 4026     [[ $size == 0 ]] && COUNTER[_ZERO]=$((COUNTER[_ZERO]+1)) #wrong size cnt
 4027 } # updateStatistics
 4028 
 4029 
 4030 
 4031 ################################# addToRpmExportList
 4032 # If --export *.tar is given, we save all found packages to that file
 4033 function addToRpmExportList()
 4034 {
 4035     local rpm=${1##*$DLPATH/$server/}
 4036     if [[ $EXPORT -eq 1 ]] ; then
 4037         pushd "$BASEDIR">/dev/null
 4038         if [[ $rpm == /* ]] ; then # absolute path found (file from alternate server)
 4039             pushd ${rpm%%/$ARCH/update/$SUSEVERSION/*}>/dev/null # go to alternate server
 4040             rpm=$ARCH/update/${rpm##*$ARCH/update/}
 4041         else
 4042             pushd "$DLPATH/$server">/dev/null # go to current server
 4043         fi
 4044         myEcho 3 "Adding to export file $EXPORTFILE: $rpm"
 4045         [[ -f $EXPORTFILE ]] && tar -rf "$EXPORTFILE" $rpm && myNote 0 "Added to exportfile: `basename "$rpm"`" ||\
 4046         myError 0 "Could not add $rpm to export file!";
 4047         popd >/dev/null # dlpath/server
 4048         popd >/dev/null # basedir
 4049     fi
 4050     return 0
 4051 }
 4052 
 4053 
 4054 ################################# processFoundUpdates
 4055 # Processes the updates that have been found
 4056 # the information is gathered through the package_XXX variables
 4057 function processFoundUpdates()
 4058 {
 4059     local last_shown packageinfo pkg x y newversion currentversion shortdesc test
 4060     local longdesc license
 4061     for pkg in ${!package_*} ; do
 4062         cd "$BASEDIR"
 4063         cd "$DLPATH"
 4064         # package_$pkgdescfile_MG_$rpm
 4065         x=${pkg##*_MG_} #current patch name
 4066         y=${pkg##package_} y=${y%%_MG_*} #real patch description file containing pkg
 4067         pkg=${!pkg}
 4068         packageinfo=packageinfo_$x packageinfo=(${!packageinfo})
 4069         newversion=${packageinfo[0]}
 4070         currentversion=${packageinfo[1]}
 4071         kind=${packageinfo[2]}
 4072         size=${packageinfo[3]}
 4073         series=${packageinfo[4]}
 4074         remarkonly=${packageinfo[5]}
 4075         rpm=${packageinfo[6]}
 4076         dlfile=${packageinfo[7]}
 4077         server=${packageinfo[8]}
 4078         oldhdsize=${packageinfo[9]}
 4079         newhdsize=${packageinfo[10]}
 4080         i=${packageinfo[11]}
 4081         patchfile=${packageinfo[12]}
 4082         newbuildtime=${packageinfo[13]}
 4083         PREINFO=${packageinfo[14]}
 4084         sourcerpm=${packageinfo[15]}
 4085         origurl=${packageinfo[16]}
 4086         SERVERPATH=${packageinfo[17]}
 4087         usepatchrpmnow=${packageinfo[18]}
 4088         patchsize=${packageinfo[19]}
 4089         SERVERURL=${packageinfo[20]}
 4090         usedeltarpmnow=${packageinfo[21]}
 4091         deltasize=${packageinfo[22]}
 4092         deltarpm=${packageinfo[23]}
 4093         patchrpm=${packageinfo[24]}
 4094         shortdesc=shortdesc_$x shortdesc=${!shortdesc}
 4095         longdesc=longdesc_$x longdesc=${!longdesc}
 4096         license=license_$x license=${!license}
 4097 
 4098         if [[ $pkg == @($SRCRPMS) ]] ; then
 4099             rpm=$sourcerpm
 4100             dlfile=$SERVERURL/$SERVERPATH/$sourcerpm
 4101             usepatchrpmnow=0
 4102         fi
 4103 
 4104         [[ $PATCHRPMS -eq 0 ]] && usepatchrpmnow=0
 4105         [[ $USEDELTARPMS -eq 0 ]] && usedeltarpmnow=0
 4106 
 4107         if [[ $usedeltarpmnow -eq 1 ]] ; then
 4108             size=$deltasize
 4109             [[ $NODOTSUSEVERSION -lt 101 ]] && rpm=deltas/$deltarpm || rpm=$deltarpm
 4110             dlfile=$SERVERURL/$SERVERPATH/$rpm
 4111         elif [[ $usepatchrpmnow -eq 0 && $rpm == *.patch.rpm ]] ; then
 4112             rpm=${rpm%%.patch.rpm}.rpm
 4113             origurl=${origurl%%.patch.rpm}.rpm
 4114             dlfile=${dlfile%%.patch.rpm}.rpm
 4115         elif [[ $usepatchrpmnow -eq 1 && $patchsize -gt 0 && $kind != script \
 4116             && $rpm != *.patch.rpm ]] ; then
 4117             size=$patchsize
 4118             rpm=${rpm%%.rpm}.patch.rpm
 4119             origurl=${origurl%%.rpm}.patch.rpm
 4120             dlfile=${dlfile%%.rpm}.patch.rpm
 4121         elif [[ $usepatchrpmnow -eq 1 ]] ; then
 4122             [[ $NODOTSUSEVERSION -ge 101 ]] && rpm=$patchrpm
 4123             size=$patchsize
 4124         fi
 4125         if packageFiltered $pkg $kind $series; then
 4126             myEcho 4 "Skipping $pkg because of filter"
 4127             continue
 4128         fi
 4129         if [[ $NODOTSUSEVERSION -lt 110 && ! -f $i ]] ; then
 4130             myWarn 2 "Package description file $i is missing, skipping $pkg" # | fmt -$COLUMNS
 4131             continue
 4132         fi
 4133         if [[ $y != ${patchfile//[^A-Za-z0-9_]/_} && -n $patchfile ]] ; then
 4134             myWarn 2 "Skipping $pkg from $y because used $patchfile"
 4135             continue
 4136         fi
 4137         if [[ $last_shown != $patchfile ]] ; then
 4138             updateinfoshown=0
 4139             cd "$BASEDIR"
 4140             cd "$DLPATH"
 4141             if [[ -n $RPMINSTLIST && $INSTMODE -eq 1 ]] ; then
 4142                 rpmInstall $RPMINSTLIST
 4143                 RPMINSTLIST=
 4144             fi
 4145         fi
 4146         last_shown=$patchfile
 4147         showPackage || continue
 4148         updateStatistics
 4149         [[ $DOINSTALL -eq 0 && $DOWNLOAD -eq 0 ]] && continue
 4150         if [[ $DOINSTALL -eq 0 && $DOWNLOAD -eq 1 && -n $FOUNDFILE ]] ; then
 4151             if [[ $size == 0 ]] ; then
 4152                 myEcho 2 "$pkg: correct size is unknown, trying to resume download."
 4153             elif [[ $FOUNDSIZE == $size ]] ; then
 4154                 myEcho 2 "$pkg: correct size in local mirror, no need to download $rpm"
 4155                 continue
 4156             else
 4157                 myEcho 2 "$pkg: incorrect size in local mirror, trying to resume download ($FOUNDSIZE/$size)."
 4158             fi
 4159         fi
 4160         getUserChoice || continue
 4161         # download package if desired and return if it fails
 4162         rpmpath=${rpm%/*}
 4163         if [[ $DOWNLOAD -eq 1 ]] && ! getRpm "$rpm" "$pkg" "$size" "$dlfile" ; then
 4164             if ! fileExists $server $rpm ; then
 4165                 # try alternate server
 4166                 dlfile1=dlfile1_$x
 4167                 dlfile1=${!dlfile1}
 4168                 if [[ -n $dlfile1 ]] ; then
 4169                     server=server1_$x
 4170                     server=${!server}
 4171                     getRpm $rpm $pkg $size $dlfile1
 4172                 fi
 4173             fi
 4174         fi
 4175         fileExists $server $rpm || continue
 4176         [[ $INTERACTIVE -eq 0 && $PREINFO -eq 1 && $ACCEPTPREINSTALLINFO -eq 0 &&\
 4177             $EXPORT -eq 0 ]] && continue
 4178 
 4179         # update rpminstlist with pending packages (only if in you-compat mode)
 4180         [[ $CHECKONLY -eq 1 ]] && continue
 4181         if ! fileExists $server $rpm ; then
 4182             myWarn 0 "File not found: $rpm - skipping."
 4183             continue
 4184         fi
 4185         [[ $TESTMODE -eq 1 ]] && test=" (test mode)"
 4186         if [[ $series != script ]] ; then
 4187             processDownloadedRpm $pkg $rpm $newversion ${rpm##*/}
 4188         elif [[ $INTERACTIVE -eq 1 ]] ; then
 4189             processScript $pkg
 4190         fi
 4191     done # found updates
 4192 } # processFoundUpdates
 4193 
 4194 
 4195 ################################ processServerList
 4196 # Cycles through all available servers and calls processPatchDescriptions
 4197 # for each
 4198 function processServerList()
 4199 {
 4200     local nonfiles files
 4201     lastserver=
 4202     for SERVERURL in $SERVERLIST ; do
 4203         if [[ ${BASH_VERSINFO[0]} -ge 3 ]] ; then
 4204             SERVERURL=${SERVERURL//\%ARCH/$ARCH}
 4205             SERVERURL=${SERVERURL//\%VERSION/$SUSEVERSION}
 4206         else
 4207             SERVERURL=${SERVERURL//\\%ARCH/$ARCH}
 4208             SERVERURL=${SERVERURL//\\%VERSION/$SUSEVERSION}
 4209         fi
 4210         server=${SERVERURL#@(ftp|http|https|rsync)://} server=${server%%/*}
 4211         server=${server##*@} server=${server%:*}
 4212         if [[ $SERVERURL != *$ARCH/update/$SUSEPRODUCT$SUSEVERSION* ]] && \
 4213             [[ $SERVERURL == rsync://* ]] ; then
 4214             SERVERPATH=${SERVERURL#rsync://}
 4215             SERVERPATH=${SERVERPATH#*/} # customized rsync server path
 4216         else
 4217             SERVERURL=${SERVERURL%%/$ARCH*}
 4218             [[ $NODOTSUSEVERSION -ge 101 ]] && SERVERPATH=update/$SUSEVERSION || \
 4219                 SERVERPATH=$ARCH/update/$SUSEPRODUCT$SUSEVERSION
 4220             [[ $NODOTSUSEVERSION -eq 101 && $SUSEVERSION = 10 ]] && SERVERPATH=/ # for SLES10
 4221         fi
 4222         if [[ $SERVERURL == ftp://* && -n $ftp_proxy && $USEDIR -eq 0 && $USECURL -eq 0 ]] ; then
 4223             echo
 4224             myWarn 0 "WARNING: You are using an FTP server and ftp_proxy is set. Fou4s can't use the proxy, because wget makes some trouble with FTP over a proxy." | fmt -$COLUMNS
 4225             echo
 4226             unset ftp_proxy
 4227         fi
 4228         [[ $UPDATEPACKAGELIST -eq 1 ]] && updatePackagelist $server $SERVERPATH
 4229         lastserver=$server
 4230         [[ $CHECKONLY -eq 0 && $DOINSTALL -eq 0 && $LISTAVAILRPMS -eq 0 ]] && continue
 4231         # quiet and verbose are set in automode!
 4232         myEcho 2 "Processing server $SERVERURL"
 4233         if [[ ! -f $SKIPPEDPATCHESFILE ]] ; then
 4234             touch $SKIPPEDPATCHESFILE 2>/dev/null
 4235             if [[ $? -ne 0 ]] ; then
 4236                 myWarn 0 "Could not create $SKIPPEDPATCHESFILE, consider changing CacheDir in $CONFIGFILE" | fmt -$COLUMNS
 4237             fi
 4238         fi
 4239         PATCHGLOB=$PATCHDIR
 4240         if [[ $GENERATED -eq 1 ]]; then
 4241             PATCHGLOB="$PATCHGLOB/.*-[0-9G]*"
 4242         else
 4243             PATCHGLOB="$PATCHGLOB/.*-[0-9]*"
 4244         fi
 4245         if [[ $NODOTSUSEVERSION -ge 101 ]] ; then
 4246             PATCHGLOB="$PATCHDIR/patch-*.xml"
 4247         fi
 4248 
 4249         cd "$BASEDIR"
 4250         cd "$DLPATH"
 4251         PKGDESCFILES=
 4252         if [ $NODOTSUSEVERSION -lt 110 ] ; then
 4253             if [[ $USEDIR -eq 1 ]] ; then
 4254                 if [[ $NODOTSUSEVERSION -lt 101 ]] ; then
 4255                     DIRFILES=`find ./$server/$SERVERPATH -follow -regex ".*\/directory.*" 2>/dev/null`
 4256                     PKGDESCFILES=`cat $DIRFILES| sed "s#^#./$server/$SERVERPATH/$PATCHDIR/#g"| grep -v -F -f $SKIPPEDPATCHESFILE`
 4257                     [[ -z $PKGDESCFILES ]] && myEcho 3 "No directory file found on $server"
 4258                 else
 4259                     pushd "$server/$SERVERPATH/$PATCHDIR" >/dev/null
 4260                     PKGDESCFILES=`parsePatchesXML -f ./$server/$SERVERPATH/$PATCHDIR/ |\
 4261                         grep -v -F -f $SKIPPEDPATCHESFILE`
 4262                     popd >/dev/null
 4263                 fi
 4264             elif [[ -z $PKGDESCFILES ]] ; then
 4265                 PKGDESCFILES=`find ./$server/$SERVERPATH/$PATCHDIR* -follow -regex ".*$PATCHGLOB" 2>/dev/null\
 4266                 | grep -v -F -f $SKIPPEDPATCHESFILE`
 4267             fi
 4268             PKGDESCFILES=`echo $PKGDESCFILES | tr " " "\n" | sort -u`
 4269             # if --nogenerated is used, we don't want to see this message
 4270             if [[ -z $PKGDESCFILES && $GENERATED -eq 1 ]] ; then
 4271                 echo -e $COL_RED
 4272                 echo "WARNING: No update description files found for $SERVERURL" | fmt -$COLUMNS
 4273                 echo "Run fou4s with option -u to download patch descriptions!"
 4274                 echo
 4275                 echo -e "${COL_YELLOW}You may also want to check $SKIPPEDPATCHESFILE, this file contains all patch description names that will be skipped by fou4s. Make sure that it doesn't contain any blank lines!!" | fmt -$COLUMNS
 4276                 echo -e $COL_NORM
 4277                 continue
 4278             fi
 4279             ALLPKGDESCFILES="$ALLPKGDESCFILES $PKGDESCFILES"
 4280             if [[ $EXPORT -eq 1 ]] ; then
 4281                 (
 4282                 cd "$BASEDIR"
 4283                 cd "$DLPATH"
 4284                 cd $server
 4285                 for d in $ALLPKGDESCFILES ; do
 4286                     tar -rf "$EXPORTFILE" ${d##./$server/}
 4287                 done
 4288                 )
 4289             fi
 4290             if [[ $USECACHE -ge 2 && -f $AUTOSKIPPEDPATCHESFILE ]] ; then
 4291                 myNote 2 "Processing auto-skipped patches on $server"
 4292                 nonfiles="`cat $AUTOSKIPPEDPATCHESFILE`"
 4293                 listsToPatterns nonfiles
 4294                 files=$PKGDESCFILES
 4295                 PKGDESCFILES=
 4296                 INVALIDPKGDESCS=
 4297                 for f in $files ; do
 4298                     if [[ $f == @($nonfiles) && -f $f && $f -ot $DESCCACHE ]] ; then
 4299                         myEcho 3 "Skipping $f"
 4300                     else
 4301                         PKGDESCFILES="$PKGDESCFILES $f"
 4302                         myNote 3 "Using $f"
 4303                     fi
 4304                 done
 4305                 myEcho 2 "Done with auto-skipped patches on $server"
 4306             fi
 4307             if [[ $NODOTSUSEVERSION -ge 101 ]] ; then
 4308                 processXMLPatchDescriptions $PKGDESCFILES # compares versions
 4309             else
 4310                 processPatchDescriptions $PKGDESCFILES # compares versions
 4311             fi
 4312         else
 4313             pushd "$server/$SERVERPATH/$PATCHDIR" >/dev/null
 4314             processPrimaryXML
 4315         fi
 4316         [[ $USEPROGRESS -eq 1 ]] && showProgress 1 1 1 # force 100% display
 4317     done # serverlist
 4318 } # processServerList
 4319 
 4320 
 4321 #################################
 4322 ################################# main program
 4323 #################################
 4324 [[ $# -lt 1 ]] && showUsageShort
 4325 [[ $1 = --config ]] && CONFIGFILES=$2 && shift 2
 4326 for c in $CONFIGFILES ; do
 4327     [[ -f $c ]] && CONFIGFILE=$c  # the last one wins
 4328 done
 4329 
 4330 getOptionsFromConfigFile $CONFIGFILE
 4331 
 4332 PARAMETERS=`getopt -l all,allnew,arch:,auto,benchmark,buildtime,checkdeleted,\
 4333 checkfou4s,commonfuncs,config:,end,evaluate,exclude:,exportx:,fixperm,force,\
 4334 getpackagedescriptions,help,host:,import:,interactive,inversecolor,limit-rate:,\
 4335 list,nocache,nocheckdeleted,nocolor,nocompatible,nocont,nodeps,nodownload,\
 4336 nodeltarpms,nogenerated,nogpg,nopatchrpms,noprogress,noproxy,offline,only,\
 4337 product:,proxy:,proxypasswd:,proxyuser:,quiet,remove,safemode,security,server,\
 4338 source:,src:,susepasswd:,susepassword:,suseuser:,suseversion:,testmode,update,\
 4339 upgrade,verbose,version,language:,cleancache,cronserver,cronworkstation,usedir,\
 4340 install,usecurl,use-curl,proxy-digest,noresume,older-than:,acceptpreinstallinfo\
 4341  -o abcdef:ghilnoqrsuvw -n 'fou4s' -- "$@"`
 4342 [[ $? -ne 0 ]] && echo "Run fou4s --help for more information" && exit 12
 4343 eval checkParameters "$PARAMETERS" # parameter checking
 4344 
 4345 if [[ $EXPORT -eq 1 && $EXPORTFILE == *.tar ]] ; then
 4346     if [[ -f $EXPORTFILE ]] ; then
 4347         rm "$EXPORTFILE"
 4348         #myError 0 "Error: Output file already exists: $EXPORTFILE - aborting"
 4349         #exit 13
 4350     fi
 4351 fi
 4352 optionPostProcessing
 4353 
 4354 [[ $CLEANCACHE -eq 1 ]] && cleanCache && exit
 4355 
 4356 if [[ $EXPORT -eq 1 && $EXPORTFILE == *.fou ]] ; then
 4357     [[ -f $EXPORTFILE ]] && rm "$EXPORTFILE"
 4358     if [[ ! -f $RPMCACHE ]] ; then
 4359         updateRpmCache force || (myError 0 "Could not create RPM cache!";exit)
 4360     fi
 4361     RPMCACHEVERSION==`grep RPMCACHEVERSION $RPMCACHE`
 4362     if [[ $RPMCACHEVERSION != $RPMCACHEVER ]] ; then
 4363         updateRpmCache force || (myError 0 "Could not update RPM cache!";exit)
 4364     fi
 4365     cp "$RPMCACHE" "$EXPORTFILE"
 4366     gzip "$EXPORTFILE"
 4367     mv "$EXPORTFILE.gz" "$EXPORTFILE"
 4368     myWarn 0 "Successfully exported machine info to $EXPORTFILE."
 4369     myWarn 0 "Please go to internet connected machine and run the following commands there:"
 4370     myNote 0 "fou4s --import `basename "$EXPORTFILE"`"
 4371     myNote 0 "fou4s -u --host $HOSTNAME --export myExport.tar"
 4372     myWarn 0 "Then copy myExport.tar back to this machine and run "
 4373     myNote 0 "fou4s --import myExportfile.tar -i"
 4374     exit 0
 4375 fi
 4376 
 4377 [[ $TESTMODE -eq 1 ]] && myError 0 "*************** USING TEST MODE"
 4378 if [[ -n $FORCEDARCH ]] ; then
 4379     cleanCache
 4380     myEcho 3 "Forcing arch $ARCH to $FORCEDARCH"
 4381     ARCH=$FORCEDARCH
 4382 fi
 4383 updateRpmCache # for faster version comparison
 4384 
 4385 getKernelVersion
 4386 
 4387 if [[ -n $SUSEPRODUCT && $SUSEPRODUCT != */ ]]; then
 4388     SUSEPRODUCT=$SUSEPRODUCT/  # append slash
 4389 fi
 4390 if [[ $VERBOSE -ge 2 ]] ; then
 4391     cat <<- _EOF
 4392         Using fou4s version $FOUVERSION
 4393         Using config file   $CONFIGFILE
 4394         Using host          $HOSTNAME
 4395         Using Server(s)     $SERVERLIST
 4396         Using Arch          $ARCH/$MACHINEARCH
 4397         Using Valid Archs   $VALIDARCHS
 4398         Using Product       ${SUSEPRODUCT:=SuSE Linux}
 4399         Using Version       $SUSEVERSION ($NODOTSUSEVERSION)
 4400         Using Kernel        $KERNELPKG (running: $KERNELVER, installed: $SUSEKERNELVER)
 4401         Using Cache/DL-dir  $CACHEDIR $DLPATH
 4402     _EOF
 4403 fi
 4404 
 4405 if [[ $NODOTSUSEVERSION -lt 81 ]] ; then
 4406     echo
 4407     myError 0 "Sorry! SuSE versions older than 8.1 are no longer supported. Please get fou4s 0.12.6. This is the last version with support for SuSE 7.x and 8.0."| fmt -80
 4408     exit 17
 4409 fi
 4410 #if [[ $NODOTSUSEVERSION -lt 90 ]] ; then
 4411 #   echo
 4412 #   myError 0 "Sorry! SuSE versions older than 9.1 are no longer supported. Please get fou4s 0.14.0. This is the last version with support for SuSE 8.x and 9.0."| fmt -80
 4413 #   exit 17
 4414 #fi
 4415 
 4416 # only check for deleted files?
 4417 [[ $CHECKONLYDELETED -eq 1 ]] && checkDeleted && exit
 4418 
 4419 for i in /var/adm/YaST/InstSrcManager/IS_CACHE_0x000000*/DATA/descr/packages ; do
 4420     [[ -f $i ]] && PACKAGES81="$PACKAGES81 $i" && myEcho 3 "Found SuSE package description file $i"
 4421 done
 4422 # fix permissions on suse 8.1? This function will exit after being run
 4423 [[ $FIXPERMS -eq 1 ]] && fixperms
 4424 [[ $GET81PACKAGEDESCRIPTIONS -eq 1 ]] && get81packagedescriptions
 4425 [[ $CRONINST -eq 1 ]] && installCronjob
 4426 
 4427 if [[ ! -d $DLPATH ]] ; then
 4428     echo "You need to create a directory to store the patches: "
 4429     echo "$DLPATH"
 4430     echo "(Edit the config file $CONFIGFILE for a different path)"
 4431     echo "Exiting ..."
 4432     exit 2
 4433 fi
 4434 
 4435 # location of gunzipped ARCHIVES.gz
 4436 # where gpd.sh finds the ARCHIVES file, to get the package descriptions from
 4437 # exported, so get_info_from_ARCHIVES.pl sees it.
 4438 set -- $SERVERLIST
 4439 SERVERURL=$1
 4440 server=${1#@(ftp|http|https|rsync)://}
 4441 server=${server%%/*}
 4442 server=${server/:*} # strip port number
 4443 export ARCHIVES=$DLPATH/$server/$SERVERPATH/ARCHIVES
 4444 
 4445 #used by announcement2pkgdesc and gpd.sh
 4446 [[ $COMMONFUNCS -eq 1 ]] && return
 4447 doStartupChecks # some initial checks
 4448 [[ $UPDATESERVERLIST -eq 1 ]] && updateServerlist && exit
 4449 source $RPMCACHE # source the rpm cache
 4450 # source the update description cache
 4451 SKIPPEDPATCHESFILE=$CACHEDIR/skipped-patches.$HOSTNAME.$SUSEVERSION
 4452 AUTOSKIPPEDPATCHESFILE=$CACHEDIR/.cache.$HOSTNAME/skipped-patches.$HOSTNAME.$SUSEVERSION.$LANGUAGE.auto
 4453 if [[ $USECACHE -ge 2 && -f $DESCCACHE ]] ; then
 4454     myNote 3 "Sourcing description cache"
 4455     source $DESCCACHE
 4456     if [[ $DESCRIPTIONCACHE_VERSION != 1.4 || $DC_ARCH != $ARCH || \
 4457         $DC_PRODUCT != $SUSEPRODUCT || $DC_VERSION != $SUSEVERSION || \
 4458         $DC_SERVERLIST != $SERVERLIST || $DC_LANGUAGE != $LANGUAGE || \
 4459         $SKIPPEDPATCHESFILE -nt $AUTOSKIPPEDPATCHESFILE ]] ; then
 4460         myEcho 2 "Removing autoskipped-patches because description cache is invalid!"
 4461         rm -f $AUTOSKIPPEDPATCHESFILE $DESCCACHE
 4462         # unset all found packages
 4463         for i in `echo ${!longdesc_*} ${!license_*} ${!shortdesc_*} ${!packageinfo_*} ${!package_*} ${!dlfile1_*} ${!server1_*}` ; do
 4464             unset $i
 4465         done
 4466     fi
 4467 fi
 4468 if [[ $RPMCACHEVERSION != $RPMCACHEVER || $RPMCACHECOMPLETE != 1 || -z $pkg_bash ]] ; then
 4469     updateRpmCache force
 4470     myNote 3 "Sourcing RPM DB cache"
 4471     source $RPMCACHE
 4472     if [[ $RPMCACHEVERSION != $RPMCACHEVER || $RPMCACHECOMPLETE != 1 ]] ; then
 4473         myError 0 "BUG! updateRpmCache failed twice without obvious reason."
 4474         exit 13
 4475     fi
 4476 fi
 4477 [[ $INTERACTIVE -eq 1 ]] && exec 6<&0 # copy stdin
 4478 
 4479 if [[ $NODOTSUSEVERSION -ge 110 ]] && [ -f $SKIPPEDPATCHESFILE ] ; then
 4480     while read line; do
 4481         EXCLUDELIST="$EXCLUDELIST $line"
 4482     done < $SKIPPEDPATCHESFILE 
 4483     EXCLUDELIST=${EXCLUDELIST## }
 4484     listsToPatterns EXCLUDELIST
 4485 fi
 4486 
 4487 processServerList # find updates from all servers
 4488 if [ $USECACHE -ge 2 ] ; then # update cache with found updates
 4489     updateDescriptionCache
 4490     printf "%s\n" $ALLPKGDESCFILES > $AUTOSKIPPEDPATCHESFILE
 4491     # strip blank lines:
 4492     grep -v "^$" $AUTOSKIPPEDPATCHESFILE 2>/dev/null > \
 4493         $AUTOSKIPPEDPATCHESFILE.new && \
 4494         mv $AUTOSKIPPEDPATCHESFILE.new $AUTOSKIPPEDPATCHESFILE
 4495 fi
 4496 if [[ $CHECKONLY -eq 1 || $DOINSTALL -eq 1 ]] ; then
 4497     processFoundUpdates # shows them on the screen and installs
 4498 fi
 4499 cd "$BASEDIR"
 4500 cd "$DLPATH"
 4501 [[ -n $RPMINSTLIST ]] && rpmInstall $RPMINSTLIST
 4502 
 4503 if [[ $CHECKONLY -eq 1 && $QUIET -eq 0 && ${COUNTER[_ALL]} -gt 0 && $DOWNLOAD -eq 0 || $LISTAVAILRPMS -eq 1 ]] ; then
 4504     showSummary
 4505     echo This run of fou4s took $SECONDS secs. # $SECONDS is from BASH!
 4506     [[ -n $COL_BLACK && $INVERSE -eq 0 ]] && echo -e "${COL_BLACK}*** IF YOU CAN READ THIS, try fou4s --inversecolor or set InverseColor=1 ***$COL_NORM"
 4507 fi
 4508 if [[ $AUTOMODE -eq 1 && $DOWNLOAD -eq 1 ]] ; then
 4509     if [[ $((COUNTER[_ALL]-COUNTER[_INST])) -gt 0 ]] ; then
 4510     [[ $USEBUILDTIME -eq 1 ]] && b=" --buildtime" || b=
 4511         showSummary
 4512         echo
 4513         echo "Please run fou4s -i$b now, to install the downloaded packages."
 4514         echo This run of fou4s $FOUVERSION took $SECONDS secs.
 4515         logWrite 1 "Found ${COUNTER[_ALL]} update(s) (fou4s $FOUVERSION)"
 4516     elif [[ ${COUNTER[_ALL]} -gt 0 ]] ; then
 4517         echo This run of fou4s took $SECONDS secs.
 4518     fi
 4519 fi
 4520 
 4521 if [[ $EXPORT -eq 1 ]] ; then
 4522     myNote 0 "Successfully exported to `basename $EXPORTFILE`"
 4523 fi
 4524 
 4525 if [[ $DOINSTALL -eq 1 && $SUSECONFIG -eq 2 ]] ; then
 4526     [[ $TESTMODE -eq 1 ]] && myError 0 "Testmode - NOT running SuSEconfig" || \
 4527     if [[ $EUID -eq 0 ]] ; then
 4528         myWarn 0 "Running SuSEconfig ..."
 4529         sg root -c /sbin/SuSEconfig
 4530     else
 4531         myError 0 "Error: You must be root to run SuSEconfig!"
 4532     fi
 4533 fi
 4534 
 4535 # check for deleted files (by RPM) that are still in use
 4536 [[ $CHECKDELETED -eq 1 ]] && checkDeleted
 4537 
 4538 if [[ $FAILCOUNT -gt 0 ]] ; then
 4539     myWarn 0 "Warning: $FAILCOUNT updates failed. Please fix the problems and try again"
 4540 fi
 4541 exit 0
 4542 # vim: set ai ts=3 sw=3 is :