#!/bin/sh # #============================================================================ # Before installing anything, be sure to read the WARNING below! # For the latest version visit: http://staff.washington.edu/corey/tools.html #============================================================================ # # Given the URL (or path) to a directory of available patches (default provided) # Find those which are upgrades to packages already installed and # Emit URLs (or paths) for them so the bold may run this script: # # rpm -Fvh `new-patches [url]` # # Sometimes, patches have dependencies on packages which aren't installed # To test for this condition before installing, run: # # rpm -Fvh --test `new-patches [url]` # # If there are "failed dependencies:", you must first manually install # the needed packages, or manually remove (from the output of this script) # the URLs for those patches which have unsatisfied dependencies: # # new-patches > new-patches.out # # manually remove from new-patches.out those lines to not install # rpm -Fvh `cat new-patches.out` # # This script works on RedHat 7.0, 6.2 and it works on RedHat 6.1 if you're # running a new enough version of rpm. It should also work on newer versions # and may work on older versions. # #============================================================================ #==== WARNING =========== WARNING =========== WARNING =========== WARNING === #============================================================================ # # You may find that kernel upgrades don't always work without some tinkering # (such as manually running lilo, or editing the lilo.conf file). If one # of the updates is a new kernel, make sure you have a current boot floppy # BEFORE installing it! Run mkbootdisk to make one. # # I've noticed that sometimes patches intended for both 6.2 and 6.1 aren't # copied into the redhat 6.1 updates directory. If you're running 6.1, you # may still need to run this against the 6.2 updates directory and manually # see what may-or-may-not be relevant. # # Packages are sometimes renamed, so you may not notice that a new package # is relevant to your installation. In these cases, it is left to you to # discover that these new packages exist. One place to keep up-to-date on # such things is http://www.redhat.com/errata # #============================================================================ # COMMAND-LINE OPTIONS #============================================================================ # # If you don't specify a URL or path to a directory of updates this script # will attempt to deduce your RH version and use an appropriate default URL. # Use -v #.# to override the RH version number in that default URL. # # Use -m to use the usually busy MAIN site and NOT use a mirror site. # The chosen mirror may or may not be better... best to choose your own. # # Use -p to toggle ftp "passive" mode if you're firewalled and the invocation # of ftp in this script did not manage to turn it on for you. # # Use -e to disable the complicated "newness" test and just compute which # packages aren't the exact same version as what you have installed. # # Use -o to reverse the "newness" test so you can, for example, test against # your initial CDROM and see which packages are older on the CDROM. # # Use -i to print the installed package's version instead of the one found # to be newer (or older if -o is used). Useful to document which packages # you will be replacing (in case you need to revert) or with -o as above # to show which patches you already have installed. # # Use -b to print bare rpm filenames (without an initial URL or path) # # Use -u to list packages at path or URL which are not installed on your system. # # Use -h to emit this initial usage message (there is also a real manpage) # # Use -a i686 or -a noarch to test for RPMs for specific other "architectures" # # Author: Corey Satten, corey @ cac.washington.edu, 06/26/03, release 1.8 # # Before installing anything, be sure to read the WARNING above! # Usage: new-patches [-h] [-p] [-d] [-e] [-o] [-i] [-b] [-u] [-v #] [-a arch] [path] # For the latest version visit: http://staff.washington.edu/corey/tools.html #============================================================================ # Try to help people figure out if/when this file has DOS line terminators # Chances are the initial #!/bin/sh will fail with a cryptic "not found" msg # If someone tries to debug it by feeding it to sh manually, this should help: NL= case "$NL" in '');; *) # echo "ERROR: $0 was improperly saved with CR-LF newlines." 1>&2 # echo "Please try again after restoring Unix-style (LF) newlines" 1>&2 # exit 1 ;; # esac # VERSION=`awk ' /^Red Hat Linux release [0-9.]+/ {print $5} /^Fedora Core release [0-9.]+/ {print $4}' /etc/redhat-release` case "$VERSION" in '') VERSION=6.2;; esac # find installed RH version for i in $*; do case "$1" in -a) ARCH="$2"; shift;shift;; # override default arch -v) VERSION="$2"; shift;shift;; # override default version -p) PASSIVE=passive; shift;; # toggle ftp PASSIVE mode -d) DEBUG=1; shift;; # debug newness comparisons -e) EFLAG=1; shift;; # "newer" just means not equal -o) OFLAG=1; shift;; # "newer" means older -i) IFLAG=1; shift;; # print installed packages -b) BFLAG=1; shift;; # emit bare package names -h) HFLAG=1; shift;; # emit usage message to stdout -u) UFLAG=1; shift;; # list uninstalled packages -m) MFLAG=1; shift;; # dont use mirror site -*) HFLAG=2; shift;; # emit usage summary to stderr *) break;; esac done ARCH=${ARCH-i386} case "$HFLAG" in 1) sed -n '3,/^$/p' $0; exit 0;; # use initial comments as help 2) sed -n '/^# Usage/,/http/s/^# //p' $0 1>&2; exit 1;; esac # official URLs (often slow and only HTTP) FEDORA=http://download.fedora.redhat.com/pub/fedora/linux/core LEGACY=http://download.fedoralegacy.org/redhat FCORE1=http://download.fedoralegacy.org/fedora # hopefully faster FTP mirrors from the mirrors list at: # http://fedora.redhat.com/download/mirrors.html # http://fedoralegacy.org/download/fedoralegacy-mirrors.php case "$MFLAG" in 1);; *) FEDORA=ftp://limestone.uoregon.edu/fedora LEGACY=ftp://linux21.fnal.gov/linux/legacy/redhat esac # if no default REDHAT_UPDATES URL given in the environment, use this one case "$REDHAT_UPDATES$1" in '') case $VERSION in 1*)REDHAT_UPDATES="$FCORE1/$VERSION/updates/$ARCH";BRAND="Fedora Core";; [789]*)REDHAT_UPDATES="$LEGACY/$VERSION/updates/$ARCH";BRAND="Red Hat Linux";; *)REDHAT_UPDATES="$FEDORA/updates/$VERSION/$ARCH";BRAND="Fedora Core";; esac echo "Patches for $BRAND $VERSION (use -v #.# to override)" 1>&2 ;; esac # To compare a system against a standard distribution, try these URLs: # ftp://redhat.cac/redhat/linux/6.1/en/os/i386/RedHat/RPMS # ftp://redhat.cac/redhat/linux/6.2/en/os/i386/RedHat/RPMS # ftp://redhat.cac/redhat/linux/7.0/en/os/i386/RedHat/RPMS SRC=${1-$REDHAT_UPDATES} case "$SRC" in */);; *) SRC=$SRC/;; esac # URL must end in slash NEWER=' # Function newer: # Return 1 if second arg is "newer" than the first arg, else return 0. # # Because extra dotted fields before a hyphen are more significant # than those after a hyphen, first split on hyphens, then loop over # dotted fields passing the hard alphanumerics to function "compare" # for further splitting and comparing. # # eg. older bind-utils-8.2.2_P5-9 and older gzip-1.2.4-14 # newer bind-utils-8.2.2_P7-0.6.2 and newer gzip-1.2.4a-2 # # older apmd-3.0beta9-3 and older rmt-0.4b4-11 # newer apmd-3.0final-2 and newer rmt-0.4b19-5.6x function newer(a, b, na1, nb1, na, nb, minn, i, j) { if ('"${DEBUG-0}"') \ printf("newer called with %s %s\n", a, b)>"/dev/stderr" if ('"${EFLAG-0}"') return a!=b if (O) {na=a; a=b; b=na} na1 = split(a, A1, /-/) nb1 = split(b, B1, /-/) if (na1 != nb1) { printf "unsure about %s and %s\n", a, b > "/dev/stderr" return 1 } for (j=1; j<=na1; ++j) { na = split(A1[j], A, /\./) nb = split(B1[j], B, /\./) minn = na < nb ? na : nb for (i=1; i<=minn; ++i) { if ('"${DEBUG-0}"') \ printf(" newer%d comparing %s %s\n", i, A[i], B[i])>"/dev/stderr" if ((A[i] B[i]) ~ /^[0-9]+$/) { if (A[i]+0 < B[i]+0) return 1 if (A[i]+0 > B[i]+0) return 0 } else if (A[i] "" != B[i] "") return compare(A[i], B[i]) } if (nb > na) return 1 if (nb < na) return 0 } return 0 } # Function compare (called only by function newer): # Return 1 if second arg is "newer" than the first arg, else return 0. # # This is harder than it looks: consider "v9" vs "v10a", etc. # split out and compare alternating fields of numeric and non-numeric function compare (a, b, xa, xb) { if ('"${DEBUG-0}"') \ printf(" compare called with %s %s\n", a, b) >"/dev/stderr" while (length(a) && length(b)) { if (a ~ /^[0-9]/) { match(a, /^[0-9]+/) xa = substr(a, 1, RLENGTH); a = substr(a, RLENGTH+1) } else { match(a, /^[^0-9]+/) xa = substr(a, 1, RLENGTH); a = substr(a, RLENGTH+1) } if (b ~ /^[0-9]/) { match(b, /^[0-9]+/) xb = substr(b, 1, RLENGTH); b = substr(b, RLENGTH+1) } else { match(b, /^[^0-9]+/) xb = substr(b, 1, RLENGTH); b = substr(b, RLENGTH+1) } if ('"${DEBUG-0}"') \ printf(" compare2 %s %s <%s> <%s>\n", xa, xb, a, b)>"/dev/stderr" if ( (xa xb) ~ /^[0-9]+$/) { if (xa+0 < xb+0) return 1 if (xa+0 > xb+0) return 0 } else { if (xa "" < xb "") return 1 if (xa "" > xb "") return 0 } } if (length(b)) return 1 else return 0 } ' #------------------------------------------------------------------------------- # # Find all redhat patches available # # lynx -dump $SRC | awk '$4 == "rpm" {print $5}' | sed 's/^\[[0-9]*\]//' TMP=/tmp/ftp$RANDOM$$ trap "rm -f $TMP" 0 1 2 13 15 if [ -d $SRC ] ;then # local directory (cd $SRC && ls -l) else # ftp directory case "$SRC" in ftp://*) PATH=/usr/bin:$PATH # aim for /usr/bin/ftp HST=`echo "$SRC" | sed "s,^ftp://,,; s,/.*,,"` DIR=`echo "$SRC" | sed "s,^ftp://$HST/,,"` rm -f $TMP ( echo user ftp $USER@ echo cd $DIR echo $PASSIVE echo dir -L) | ftp -p -n $HST | grep '\.rpm$' > $TMP # wouldn't need TMP if ftp returned an error code on failure if [ ! -s $TMP ] ;then echo "`basename $0`: ftp failed on $SRC" 1>&2 echo " Try the -p flag and/or use a URL to a mirror site" 1>&2 exit 1 fi cat $TMP ;; http://*) lynx -dump $SRC | sed -n 's,^[ 0-9.]*http://.*/,-& ,p';; esac fi | sed -n '/\.src\.rpm$/d; /\.rpm$/s/^-.* //p' | #------------------------------------------------------------------------------- # # Find all installed packages with patches # ( rpm -qa echo ==-== case "${EFLAG}${OFLAG}${UFLAG}" in '') awk "$NEWER"' # omit all but newest of multiple available patches { L0=R0; L1=R1; L2=R2 R0=$0 R1=$0; sub(/\.[^.]+\.rpm$/,"",R1) # pkg name+version R2=$0; sub(/-[^-]+-[^-]+$/, "",R2) # pkg name-version if ((R2 == L2) && newer(R1, L1)) {R0=L0; R1=L1} if ((R2 != L2) && L0) {print L0} } END { print R0 }';; *) cat -;; esac ) | awk "$NEWER"' BEGIN { O='"${OFLAG-0}"'; I='"${IFLAG-0}"'; U='"${UFLAG-0}"' } /^==-==$/ { state = 1+U; next } { R1=$0; sub(/\.[^.]+\.rpm$/,"",R1) } # pkg name+version { R2=$0; sub(/-[^-]+-[^-]+$/, "",R2) } # pkg name-version state == 0 { p[R2] = R1; next } state == 1 { if (p[R2] && newer(p[R2], R1)) print (I ? p[R2] : $0); next } state == 2 { if (!p[R2]) print (I ? R0 : $0); next}# uninstalled pkgs ' | sort -u | #------------------------------------------------------------------------------- # # create URLs to install case "$IFLAG$BFLAG" in 1*) cat ;; *) sed "s|.*|$SRC&|" ;; esac #cgi customized for : off campus