#!/bin/bash source /etc/sorcery/config function alter_alter() { if [ -z "$1" ]; then cat < /dev/stderr && return 1 alter [ -a|--alter ] [ -n|--spell spellname ] [ -v|--version version ] command [ args ... ] EOF fi if [ "$1" == "-n" -o "$1" == "--spell" ]; then SPELL="$2";shift;shift; fi if [ "$1" == "-v" -o "$1" == "--version" ]; then VERSION="$2";shift;shift; fi source /etc/sorcery/config SPELL=${SPELL:=alter} [ -z "$VERSION" ] && VERSION=$$ TMP_LOG=/tmp/$SPELL-$VERSION IW_LOG=/tmp/$SPELL-$VERSION.iw INST_LOG=$INSTALL_LOGS/$SPELL-$VERSION MD5_LOG=$MD5SUM_LOGS/$SPELL-$VERSION C_LOG=/tmp/$SPELL-$VERSION.compile.log C_FIFO=/tmp/$SPELL-$VERSION.compile.fifo C_LOG_COMP=$COMPILE_LOGS/$SPELL-$VERSION$EXTENSION CACHE_COMP=$INSTALL_CACHE/$SPELL-$VERSION-$BUILD.tar$EXTENSION rm -f "$C_LOG" 2> /dev/null touch "$C_LOG" rm -f "$C_FIFO" 2> /dev/null mkfifo "$C_FIFO" message "${MESSAGE_COLOR}Gathering metadata for ${SPELL_COLOR}$SPELL${DEFAULT_COLOR}${MESSAGE_COLOR}.${DEFAULT_COLOR}" DATA="$(gaze compile $SPELL 2> /dev/null)" && COM_DATA="$DATA" || COM_DATA="" DATA="$(gaze install $SPELL 2> /dev/null)" && INS_DATA="$DATA" || INS_DATA="" DATA="$(gaze md5sum $SPELL 2> /dev/null)" && MD5_DATA="$DATA" || MD5_DATA="" [ -n "$COM_DATA" ] && echo "$COM_DATA" > "$C_LOG" message "${MESSAGE_COLOR}Altering...${DEFAULT_COLOR}" activate_voyeur invoke_installwatch ( echo "$@" echo "$@" | bash ) > $C_FIFO 2>&1 devoke_installwatch touch $IW_LOG $MD5_LOG $C_LOG_COMP track [ -n "$MD5_DATA" ] && echo "$MD5_DATA" | cut -c35- | exists | grep -v "^$LOG_DIRECTORY" > "$TMP_LOG.2" && cat "$TMP_LOG.2" "$INST_LOG" | sort | uniq > "$TMP_LOG.3" || cp "$INST_LOG" "$TMP_LOG.3" rm "$TMP_LOG.2" 2> /dev/null mv "$TMP_LOG.3" "$INST_LOG" create_compile_log md5list $INST_LOG $MD5_LOG archive add_spell "$SPELL" installed "$VERSION" rm $C_LOG $C_FIFO report_install return 0 } function alter_md5_mend() { SINGLE= #grab a single conflict only instead of all conflicts STORE_BASE=${STORE_BASE:=/var/log/sorcery/tmp} # */tmp are often small # by default for the backup SPELL="$1" VERSION="$(gaze -q installed "$SPELL")" MD5S="$( ( echo "$MASTER_MD5S" | grep -v " $SPELL-$VERSION$" cat "$MD5SUM_LOGS/$SPELL-$VERSION" | cut -c35- | sed -e 's/.*/& -/' ) )" TOTAL=$(echo -n "$MD5S" | wc -l) message "${MESSAGE_COLOR}Checking $TOTAL files for conflicts with ${SPELL_COLOR}$SPELL-$VERSION${DEFAULT_COLOR}${MESSAGE_COLOR}...${DEFAULT_COLOR}" > /dev/stderr RESULTS="$( echo -n "$MD5S" | sort -s -k1 | sed -e 's/\(.*\) \(.*\)/\2 \1/' | ( FILE= COUNT=0 while read LINE; do if [ "${LINE:0:2}" == '- ' ]; then FILE="${LINE:2}" else if [ "${LINE#* }" == "$FILE" ]; then echo "$LINE" [ -n "$SINGLE" ] && FILE= fi fi [ "$((++COUNT))" != "${COUNT%%000}" ] && # increment and check for mod 1000 progress_bar $COUNT $TOTAL 60 > /dev/stderr done clear_line > /dev/stderr ) | sort )" if [ -n "$RESULTS" ]; then TOTAL="$(echo "$RESULTS" | wc -l)" SPELLS="$(echo "$RESULTS" | cut -d' ' -f1 | sort | uniq)" TOTSP="$(echo "$SPELLS" | wc -l)" FILES="$(echo "$RESULTS" | cut -d' ' -f2 | sort | uniq)" STORE=$STORE_BASE/$SPELL-$VERSION.$$ mkdir -p "$STORE" mkdir -p "$STORE/tmp/sorcery" message "${MESSAGE_COLOR}Cleaning $TOTAL old md5sums from $TOTSP spells and creating $SPELL-undo-$VERSION store.${DEFAULT_COLOR}" > /dev/stderr echo "$SPELLS" | ( COUNT=0 while read SPVER; do SPFLS="$(echo "$RESULTS" | grep "^$SPVER " | cut -d' ' -f2)" echo "$SPFLS" | sed -e 's/[^a-zA-Z0-9*.+]/\\&/g' | sed -e 's/.*/\\:&: d/' | sed -i -f - "$MD5SUM_LOGS/$SPVER" if [ "$COMPRESSBIN" == "tar" ]; then echo "$SPFLS" | tar -f $INSTALL_CACHE/$SPVER-*.tar \ -kx -T /dev/stdin -C "$STORE" 2> /dev/null else echo "$SPFLS" | tar --"$COMPRESSBIN" -f $INSTALL_CACHE/$SPVER-*.tar$EXTENSION \ -kx -T /dev/stdin -C "$STORE" 2> /dev/null fi progress_bar $((++COUNT)) $TOTSP 60 > /dev/stderr done clear_line > /dev/stderr ) message "${MESSAGE_COLOR}Creating ${SPELL_COLOR}$SPELL-undo${DEFAULT_COLOR}${MESSAGE_COLOR} spell for ${SPELL_COLOR}$SPELL-$VERSION${DEFAULT_COLOR}${MESSAGE_COLOR}.${DEFAULT_COLOR}" > /dev/stderr ORIGSPELL="$SPELL" SPELL="$SPELL-undo" cd "$STORE" INST_LOG="$STORE.log" mkdir -p "$STORE$MD5SUM_LOGS" MD5S_LOG="$STORE$MD5SUM_LOGS/$SPELL-$VERSION" touch "$MD5S_LOG" echo -n "$RESULTS" > "$STORE/tmp/sorcery/$SPELL-$VERSION-backup.md5" find * > "$INST_LOG" md5list "$INST_LOG" "$MD5S_LOG" # relative to STORE instead of absolute CACHE_COMP="$INSTALL_CACHE/$SPELL-$VERSION-$BUILD.tar$EXTENSION" archive # No install log nor compile cache needed or wanted since we are # only doing md5sum deletions from other spells, the undeleted # form should only restore the md5sums to the proper location. rm -rf "$STORE" return 1 else message "${MESSAGE_COLOR}No md5sum conflicts with ${SPELL_COLOR}$SPELL-$VERSION${DEFAULT_COLOR}${MESSAGE_COLOR} detected.${DEFAULT_COLOR}" > /dev/stderr return 0 fi } function alter_md5mend() { [ -z "$1" ] && echo "Please provide spells to mend as arguments" > /dev/stderr && return 1 TOTAL=$(gaze installed | wc -l) message "${MESSAGE_COLOR}Gathering md5sums from $TOTAL spells...${DEFAULT_COLOR}" > /dev/stderr MASTER_MD5S="$( ( COUNT=0 for i in $( gaze installed | cut -d: -f1,4 | tr : - ); do cat "$MD5SUM_LOGS/$i" | sed -e 's/.*/'"$i"':&/' progress_bar $((++COUNT)) $TOTAL 60 > /dev/stderr done | sed -e 's/\(.*\):\(.*\) \(.*\)/\3 \1/' clear_line > /dev/stderr ) )" for spell in $*; do alter_md5_mend "$spell" done return 0 } function alter_pre_link() { ARGS="$@" if [ ! -f "/etc/prelink.conf" ]; then message "${MESSAGE_COLOR}Gathering binary directories for prelinking (this could take a long while)...${DEFAULT_COLOR}" find / -perm +001 2> /dev/null | while read LINE; do [ ! -h "$LINE" ] && file $LINE 2> /dev/null | grep -q ELF && echo "$LINE" done | grep -v '/src/\|/lib/modules\|/root/\|/home/' | sed -e 's/[^/]*$//' | uniq | sort | uniq > /etc/prelink.conf fi alter_alter -n smgl-prelink ' /usr/sbin/prelink -v '"$ARGS"' | tee /tmp/prelink.$$.output grep "Prelinking\\|Linking" /tmp/prelink.$$.output |cut -d" " -f2 | sort | uniq | while read PRELINKED; do touch "$PRELINKED" done rm /tmp/prelink.$$.output ' } function alter_prelink { if gaze -q installed prelink | grep -q 'not installed'; then cast prelink || ( message "${MESSAGE_COLOR}Unable to statisfy prelink dependency, quitting.${DEFAULT_COLOR}" return 1 ) fi if [ -z "$1" ]; then alter_pre_link -afmR else alter_pre_link "$@" fi alter_md5mend smgl-prelink } function alter_strip_do() { ARGS="$@" if [ ! -f "/etc/prelink.conf" ]; then message "${MESSAGE_COLOR}Gathering binary directories for stripping (this could take a long while)...${DEFAULT_COLOR}" find / -perm +001 2> /dev/null | while read LINE; do [ ! -h "$LINE" ] && file $LINE 2> /dev/null | grep -q ELF && echo "$LINE" done | grep -v '/src/\|/lib/modules\|/root/\|/home/' | sed -e 's/[^/]*$//' | uniq | sort | uniq > /etc/prelink.conf fi alter_alter -n smgl-strip ' find $(cat /etc/prelink.conf) -perm +001 2> /dev/null | while read LINE; do [ ! -h "$LINE" ] && file $LINE 2> /dev/null | grep -q ELF && echo "$LINE" done | while read STRIPFILE; do cp "$STRIPFILE" /tmp/tostrip.$$ strip '"$ARGS"' /tmp/tostrip.$$ if [ "$(md5sum < /tmp/tostrip.$$)" == "$(md5sum < "$STRIPFILE")" ]; then echo "$STRIPFILE" already stripped, skipping. rm /tmp/tostrip.$$ else if [ "$(ldd /tmp/tostrip.$$ | md5sum)" == "$(ldd "$STRIPFILE" | md5sum)" ]; then echo "$STRIPFILE stripped and verified." # uncomment the following to make backups before mving stripped bins # mkdir -p "/var/log/sorcery/tmp/smgl-strip.$$/${STRIPFILE%/*}" # cp "$STRIPFILE" "/var/log/sorcery/tmp/smgl-strip.$$/$STRIPFILE" mv /tmp/tostrip.$$ "$STRIPFILE" else echo "$STRIPFILE corrupted by strip, skipping" fi fi done ' } function alter_strip { if [ -z "$1" ]; then alter_strip_do else alter_strip_do "$@" fi alter_md5mend smgl-strip } function alter_about() { cat < /dev/stderr && exit 1 alter: usage: alter [ { -a | --alter } ] # -a/--alter are ignored as this is default [ { -n | --spell } spell:=alter ] [ { -v | --version } version:= ] command [ args ... ] alter { -m | --md5mend } spell [ spell ... ] alter { -p | --prelink } [ prelink_args:=-afmR ] alter { -s | --strip } # shortcut to strip all binaries [ strip_args:= ] alter { -h | --about } # learn about alter and what it does default environment variables: STORE_BASE=/var/log/sorcery/tmp To drastically save space, turn ARCHIVE=off in /etc/sorcery/local/config To undo with ARCHIVE=on: dispel -d -undo alter -m -undo NOTE: Never directly dispel an alter with REAP=on unless ****: you want to delete everything the alter touched! ****: Use the undo archives as they have no install log. EOF case "$1" in -m|--md5mend ) shift; alter_md5mend "$@" ;; -p|--prelink ) shift; alter_prelink "$@" ;; -s|--strip ) shift; alter_strip "$@" ;; -a|--alter ) shift; alter_alter "$@" ;; -h|--about ) shift; alter_about "$@" ;; -n|--spell|-v|--version|* ) alter_alter "$@" ;; esac