#!/bin/bash # slacksrc - wget the slackware source for a Slackware package. # B. Watson (urchlay@slackware.uk) # I thought this would be a quicky one-liner (or anyway less than 10 # lines), but it's grown into a monster. set -e DEFAULTMIRROR="http://ftp.slackware.com/pub/slackware" MIRROR="${MIRROR:-$DEFAULTMIRROR}" TMP="${TMP:-/tmp}" CACHEDIR="$HOME/.slacksrc" FILELIST="$CACHEDIR/FILE_LIST" TMPFILE="$TMP/slacksrc.$RANDOM.$$" SELF="$( echo $0 | sed 's,.*/,,' )" # everyone's favorite perl function die() { echo -n "$SELF: " 1>&2 if [ -n "$@" ]; then echo "$@" 1>&2 else echo "internal error, contact author" 1>&2 fi rm -f "$TMPFILE" exit 1 } # /etc/slackware-version sometimes contains extra stuff past the # actual version number (for Slack 9.0, it says 9.0.0, and I remember # at least one old version with a name in parentheses). So sed out # everything but major.minor. This will still be wrong on a -current # system, but anyone running -current is smart enough to read and # edit this script. SLACKVER="$( \ sed \ 's,slackware \+\([0-9]\+\.[0-9]\+\).*$,\1,i' \ /etc/slackware-version 2>/dev/null || \ echo Not-Slackware )" if [ -z "$1" ] || [ "$1" == "--help" ]; then exec perldoc $0 # This never actually runs. cat < option. Default Slackware version is determined by looking at /etc/slackware-version, if the B argument isn't given. The slack_ver argument can be any slackware from 3.3 to the present, including current (although current can't be autodetected, since /etc/slackware-version never actually says 'current'). Not all mirrors carry all old Slackware versions. If you're looking for really old sources, the mirror at ftp://ftp.heanet.ie/mirrors/ftp.slackware.com/pub/slackware/ goes all the way back to Slackware 1.0.1, although this script only works on 3.3 and newer (3.3 was the first version with FILELIST.TXT). The package name is matched against FILE_LIST from the server. If only one match is found, the source for that package is downloaded and saved in a subdirectory of the current directory (named after the package). If multiple matches are found, they are listed, but nothing is downloaded. If the package name is a full name, like bash-4.2.037-x86_64-1 (possibly with a .t?z extension), the version/build/arch/extension will be removed. Likewise if the name is a full pathname (beginning with e.g. /var/log), the directory name will be removed. For this reason, there is NO guarantee that the source will match any version number provided. Searching is done with grep, so the package name can be a regex. The list entries look like 'a/pkgname/', so you can do: a/foo - all packages in a/ series beginning with 'foo' a/foo/ - exact match, foo package in a/ series /foo/ - exact match in any series foo.*bar - any series, matching the (unanchored!) regex Because the list contains a trailing slash, you can't use $ to anchor the end of the match (just match the / instead). The environment variable MIRROR can be set to the Slackware mirror site to use. This should be the URL of the top level of the mirror. You can copy the URLs from http://mirrors.slackware.com/mirrorlist/ (only http: or ftp: mirrors though, rsync not supported). Default mirror is The FILE_LIST file is cached at I<~/.slacksrc/FILE_LIST->. There's not a lot of error checking. If things go wrong, check the contents of the cache file or just rm it and try again. If you want to mirror all the Slackware source (for all packages), this is the wrong tool for the job. Use rsync or wget instead. If you're looking for the source to a 3rd-party package (from slackbuilds.org or slacky.eu maybe), you're using the wrong tool again. =head1 AUTHOR AND COPYRIGHT This is slacksrc v0.1 by B. Watson (urchlay@slackware.uk). Released under the WTFPL: do WTF you want with this. See http://www.wtfpl.net/txt/copying/. =cut EOF exit 0 fi if [ -z "$HOME" ]; then die "HOME not set. Please fix this and try again." fi if [ "$1" = "-o" ]; then PATCHES=no shift fi if [ "$2" != "" ]; then SLACKVER="$1" shift fi if [ "$SLACKVER" = "Not-Slackware" ]; then die "This ain't Slackware, you'll have to tell me the Slack version you want" fi FILELIST="$FILELIST-$SLACKVER" PKG="$1" TOPDIR=$MIRROR/slackware-$SLACKVER SRCDIR=$TOPDIR/source if ! wget -q --spider "$TOPDIR"; then die "$TOPDIR not found on server, are you sure $SLACKVER is a valid version?" fi # Remove local dir name. Only works with absolute paths (relative # paths are assumed to be the package series, sorry) PKG="$( echo "$PKG" | sed 's,^/.*/,,' )" # Remove .tgz/txz/tar extension PKG="$( echo "$PKG" | sed 's,\.\(t.z\|tar\)$,,' )" # Remove version/arch/build. Since we can't know whether the input # *has* a version-arch-build, we can't use the standard cut|rev stuff # to remove it. So we use some heuristics that might one day need to # change (particularly, new arches might need to be added to the list). PKG="$( echo "$PKG" | sed 's,-[^-]\+-\(x86_64\|i.86\|arm\|s390\|ppc\|ppc64\)-[0-9][^-]*$,,' )" # The sed|sort below extracts only the first 2 directory name components # after the source/. Earlier slack versions didn't list directories in # FILELIST.TXT (only the files in them) or else we could simplify this. # Basically, we have something like ./source/a/less/SlackBuild, and we # keep only the a/less/ part (note the trailing slash). if [ ! -s $FILELIST ]; then mkdir -p $CACHEDIR wget -O- $TOPDIR/FILELIST.TXT | \ sed -n 's,.*\./source/\([^/]\+/[^/]\+/\).*$,\1,p' | \ sort -u > $FILELIST fi rm -f $TMPFILE # The files in $FILELIST have trailing slashes, sed them out. grep "$PKG" $FILELIST | sed 's,/$,,' > $TMPFILE LINES=$( wc -l $TMPFILE | cut -d' ' -f1 ) URL="" case "$LINES" in 0) die "Can't find any packages matching '$PKG' in $FILELIST" ;; 1) URL="$SRCDIR/$( cat $TMPFILE )/" ;; *) echo "Ambiguous match, '$PKG' matches:" echo cat $TMPFILE echo ;; esac rm -f $TMPFILE if [ -z "$URL" ]; then die "Couldn't determine source URL" fi PKGDIR=$( echo "$URL" | sed 's,.*/\([^/]\+\)/,\1,' ) if [ -e "$PKGDIR" ]; then die "Directory '$PKGDIR' already exists, move or remove it first" fi # 20200706 bkw: see if there's a patches/, use that if found. PATCHURL="$( echo "$URL" | sed "s,source/[^/]*/\([^/]*\)/,patches/source/\1/," )" #echo "Original source dir URL: $URL" #echo "Patch source dir URL: $PATCHURL" if [ "$PATCHES" = "no" ]; then echo "-o option given, not looking in /patches!" else if wget -q --spider "$PATCHURL"; then echo "Patch URL exists, using it" URL="$PATCHURL" else echo "Patch URL doesn't exist, using original source" fi fi echo $URL # Unfortunately, the Slackware mirrors don't all have the same dir # structure (/pub/slackware vs. /pub/Linux/slackware, etc). We have # to count the leading directories so we can tell wget how many dirs # to strip off. The shell isn't really suited to this, but I don't wanna # rewrite in a real language. # In English... the first sed expression removes the # proto://hostname. The 2nd removes the final directory name # (e.g. /bash/), and the third replaces the slashes in the remaining # part, with newlines (ASCII 0x0a). So we get one dir name per line, # which is exactly what "wc -l" will count for us. CUTDIRS=$( echo "$URL" | \ sed -e 's,^[a-z]\+://[^/]\+/,,' \ -e 's,/[^/]\+/$,,' \ -e 's,/,\x0a,g' | \ wc -l ) # wget will retrieve the server-generated index files (index.html??C=D;O=D # and friends), so reject them with -R. The -l10 might be overkill (it's # the recursion level limit), but it won't hurt anything. wget -q -r -l10 -nH -np -R'index.html*' --cut-dirs=$CUTDIRS "$URL" # The icing on the cake: make the SlackBuild executable. chmod 0755 $PKGDIR/*SlackBuild 2>/dev/null || true echo echo "Files saved to ./$PKGDIR:" ls -ld $PKGDIR/*