508 lines
14 KiB
Bash
508 lines
14 KiB
Bash
#! /bin/sh
|
||
#
|
||
#%Z%%M% %I% %E% SMI
|
||
#
|
||
######################################################################
|
||
# This utility facilitates the migration of build fixes from an
|
||
# integration machine to the various build machines. When a build
|
||
# problem gets fixed, the lead release engineer should:
|
||
#
|
||
# 1) login to an INTEGRATION machine
|
||
#
|
||
# 2) Create the input file '$top/$sid_dir/sidfix', which will be the
|
||
# basis for editing SIDlist on the integration machine, and
|
||
# extracting/deleting files from the source tree on the build
|
||
# machines. This file should list the sources relative to $top
|
||
# (usually /usr/src), followed by white space and SID number.
|
||
# eg:
|
||
# subdir/SCCS/s.sourcefile 1.7
|
||
# subdir/subdir2/SCCS/s.sourcefile 1.2
|
||
#
|
||
# To earmark a file for deletion, the filename should be preceded by
|
||
# *D* <<no white space!, SID# optional >> as in:
|
||
#
|
||
# *D*subdir/subdir3/SCCS/s.sourcefile
|
||
#
|
||
# 3) Execute 'patch_sid [-n] [-l]'.
|
||
# -n turns off sending mail to other RE's such as when
|
||
# lang/boot and libs are first built by one RE.
|
||
# -l creates a list of sidfix entries that show no change
|
||
# from the current SIDlist. This option is most
|
||
# useful for PSR releases where sidfix entries are
|
||
# generated based on a snapshot of entire directories
|
||
# that have been smerged. If the -l option is not
|
||
# used, the script asks for confirmation to include
|
||
# sidfix entries that haven't changed.
|
||
#
|
||
# After 'patch_sid' successfully executes on the integration machine,
|
||
# it sends mail to the release engineers, who should then
|
||
# follow these steps:
|
||
#
|
||
# 1) login to their BUILD machines
|
||
#
|
||
# 2) Create the input file '$top/$sid_dir/sidfix', by
|
||
# mousing up the contents of the received e-mail.
|
||
#
|
||
# 3) Execute 'patch_sid' to populate their source trees
|
||
# with the build fixes, or remove files deleted from SIDlist.
|
||
#
|
||
# 4) Rebuild affected directories.
|
||
#
|
||
# Since the SIDlist build philosophy requires that the SCCS_DIRECTORIES
|
||
# not be mounted when a 'make' may be running, a separate entry similar
|
||
# to this is required in the BUILD machine's fstab:
|
||
#
|
||
# For the ***4.1 BUILD MACHINES ONLY*** the entry is:
|
||
# aprime:/usr/bigsrc.41/SCCS_DIRECTORIES /mnt/41src nfs ro,bg,hard,intr 0 0
|
||
#
|
||
# In general, the script mounts/unmounts the SCCS sources as needed
|
||
# and verifies the input file data. After execution, it renames the
|
||
# input file by suffixing it with the new SID of SIDlist, thus
|
||
# providing some kind of audit trail. Each release engineer can
|
||
# check that her/his build fixes are up-to-date by looking for a complete
|
||
# set of suffixed files.
|
||
#
|
||
# The script also performs these functions, depending on where it
|
||
# is invoked:
|
||
#
|
||
# Integration Machine: edits the SIDlist using the input
|
||
# file, and checks it back into SCCS with comments entered
|
||
# on the keyboard, followed by a Control-D. To sidestep
|
||
# various internal size limits in the use of 'sed', sidfix
|
||
# files containing more than 80 lines are split up.
|
||
#
|
||
# Build Machines: extracts/removes the sources listed in
|
||
# the input file. [Options -n -l are ignored].
|
||
#
|
||
# NOTE: This script can create and delete entries to SIDlist, as well as
|
||
# change existing ones. Where a path or filename change is desired,
|
||
# create a 'delete' entry for the old and another one for the new.
|
||
# This script may have to be modified for concurrent use of one set
|
||
# of integration sources by multiple releases, as may be the
|
||
# case for 4.1 and 4.1.1.
|
||
#
|
||
#
|
||
######################################################################
|
||
|
||
PWD=`pwd`
|
||
fix=sidfix #list of modified files and deltas
|
||
bindir=/usr/release/bin
|
||
top=/usr/src
|
||
reng="austin@nova alison@gaia stub@mousetrap"
|
||
bugid='patch_sid'
|
||
|
||
usage="USAGE: $0 [-n] [-l]"
|
||
if [ $# -gt 1 ] ; then
|
||
echo "$usage" && exit 1
|
||
else
|
||
case $1 in
|
||
-n ) reng=`whoami`@`hostname`;;
|
||
-l ) list_chg=1;;
|
||
'' ) ;;
|
||
* ) echo $usage && exit 1;;
|
||
esac
|
||
fi
|
||
|
||
tmp=/tmp; sid_dir=$top/SIDlist
|
||
|
||
if [ ! -f $sid_dir/$fix ] ; then
|
||
echo "You must create '$sid_dir/$fix' by listing the modified"
|
||
echo "source files and deltas required to complete the build."
|
||
exit 1
|
||
fi
|
||
|
||
#Determine which function will be invoked
|
||
|
||
case `hostname` in
|
||
|
||
solaris)
|
||
edit_sid=1 #Integration machines
|
||
mt_dir=/usr/src/SCCS_DIRECTORIES;;
|
||
krypton|colander|godzilla)
|
||
get_files=1 #Build machines
|
||
mt_dir=/mnt/413src;;
|
||
* )
|
||
echo "`hostname` is not a known release machine!" && exit 1
|
||
esac
|
||
|
||
#Get mount state
|
||
|
||
/etc/mount | grep -s " $mt_dir " || unmounted=1
|
||
|
||
#Screen yes/no reponses
|
||
|
||
get_yn='(while read yn; do
|
||
case "$yn" in
|
||
[Yy]* ) exit 0;;
|
||
[Nn]* ) exit 1;;
|
||
* ) echo -n "Please answer y or n: ";;
|
||
esac
|
||
done)'
|
||
|
||
#Mount and unmount partitions
|
||
|
||
get_mtstat='( [ "$do_mt" = "0" ] && cmd=".mountit" || cmd="unmount"
|
||
done=""
|
||
while :
|
||
do
|
||
/etc/mount|grep -s " $mt_dir "
|
||
[ "$?" = "$do_mt" ] && exit 0
|
||
if [ "$done" ]; then
|
||
echo -n "Unable to $cmd $mt_dir! Try again? (y/n) "
|
||
eval "$get_yn" && continue || exit 1
|
||
fi
|
||
${bindir}/${cmd} $mt_dir
|
||
done=1
|
||
done )'
|
||
|
||
#Clean up before exiting
|
||
|
||
sv_errs=$tmp/patch_sid.errs; rm -f $sv_errs
|
||
nochg=$tmp/no_change; rm -f $nochg
|
||
errs=$tmp/err_$$
|
||
|
||
cleanup='( [ "$edit_sid" ] && [ -f $sid_dir/SCCS/p.${sid} ] && \
|
||
sccs unedit $sid;
|
||
if [ -s $errs ]; then
|
||
cat $errs > $sv_errs; echo "ERROR!"
|
||
echo "Errors are in $sv_errs."
|
||
fi
|
||
if [ -s $nochg ]; then
|
||
echo "Any files listed in $nochg should be investigated."
|
||
echo "They match entries already in $sid."
|
||
fi
|
||
rm -f $tmp/*$$*; cd $PWD
|
||
if [ "$unmounted" ]; then
|
||
do_mt=1
|
||
eval "$get_mtstat" && exit 0 || exit 1
|
||
fi )'
|
||
|
||
do_mt=0
|
||
eval "$get_mtstat" || exit 1
|
||
|
||
trap 'echo ABORTED!; eval "$cleanup"; exit 1' 1 2 3 15
|
||
|
||
#NOTE: Need to change this for branched releases!! <<<<<<<<<<<<<
|
||
|
||
if [ "$edit_sid" ]; then
|
||
(cd $top/sys/conf.common; sccs get -s RELEASE)
|
||
else
|
||
(cd $top/sys/conf.common
|
||
sccs get -s ${mt_dir}/sys/conf.common/RELEASE)
|
||
fi
|
||
release=`cat $top/sys/conf.common/RELEASE`
|
||
sid=${release}.SID
|
||
|
||
#Check if $sid is editable; also clean up $fix
|
||
|
||
cd $sid_dir
|
||
if [ "$edit_sid" ]; then
|
||
if [ -f SCCS/p.${sid} ]; then
|
||
echo "Writable $sid exists!"
|
||
edit_sid=""
|
||
eval "$cleanup"; exit 1
|
||
fi
|
||
sed -e '/^[ ]*$/d' \
|
||
-e "/^SIDlist\/SCCS\/s.$sid /d" $fix | sort |uniq > \
|
||
$tmp/${fix}_$$
|
||
else
|
||
sed -e '/^[ ]*$/d' $fix | sort |uniq > $tmp/${fix}_$$
|
||
fi
|
||
|
||
#Validate $fix; separately process delete/change/add
|
||
|
||
echo "Verifying '$fix' entries..."
|
||
cat $tmp/${fix}_$$ | \
|
||
awk '{ if (NF > 2 ) printf ("Too many fields: %s\n", $0) }' > $errs
|
||
|
||
egrep -v 'SCCS/s.' $tmp/${fix}_$$ > $tmp/$$
|
||
if [ -s $tmp/$$ ]; then
|
||
echo "These entries should be in 'SCCS/s.' format:" >> $errs
|
||
cat $tmp/$$ >> $errs
|
||
fi
|
||
|
||
if [ -s $errs ] ; then
|
||
eval "$cleanup"; exit 1
|
||
fi
|
||
|
||
[ "$edit_sid" ] && sccs get $sid
|
||
del=$tmp/del_$$; rest=$tmp/rest_$$; add=$tmp/add_$$; chg=$tmp/chg_$$
|
||
current=$tmp/current_$$ todo=$tmp/todo_$$
|
||
grep '^*D*' $tmp/${fix}_$$ | sed 's/*D*//g' | awk '{print $1}' > $del
|
||
grep -v '^*D*' $tmp/${fix}_$$ | awk '{print $1, $2}' > $rest
|
||
|
||
notfound='No such file: '; rm -f $errs; ask=$tmp/ask_$$
|
||
|
||
#Get entries that are the same in SIDlist-- build a list
|
||
#if '-l' option used; also verify that SID really exists.
|
||
|
||
if [ "$edit_sid" ]; then
|
||
cat $rest | while read line; do
|
||
if [ "$list_chg" ]; then
|
||
egrep "^${line}$" $sid >> $nochg && continue
|
||
else
|
||
egrep "^${line}$" $sid >> $ask && continue
|
||
fi
|
||
set $line
|
||
sccs get -g -r$2 ${mt_dir}/$1 1>> /dev/null 2>> $errs && \
|
||
echo "${line}" >> $todo && continue
|
||
done
|
||
else
|
||
cp -p $rest $todo
|
||
fi
|
||
|
||
#If '-l' not used, ask if ok to process entries that haven't changed.
|
||
|
||
if [ -s $ask ] ; then
|
||
echo "Line(s) below reflect no change from current SIDlist."
|
||
cat $ask |more
|
||
echo -n "Do you wish to process them anyway? (y/n) "
|
||
if eval "$get_yn"; then
|
||
cat $ask > $chg
|
||
else
|
||
echo "" >> $errs
|
||
echo "Remove line(s) that show no change from $sid" >> $errs
|
||
cat $ask >> $errs
|
||
echo "" >> $errs
|
||
echo "Verifying remaining entries..."
|
||
fi
|
||
fi
|
||
|
||
cat $rest| awk '{ if ($2 !~ /^[0-9]+\.[0-9]+/)
|
||
printf("Bad format: %s %s\n", $1, $2) }' >> $errs
|
||
|
||
#Get confirmation about new files to be added
|
||
|
||
if [ -s $todo ] ; then
|
||
for i in `cat $todo | awk '{print $1}'`; do
|
||
if [ "$edit_sid" ]; then #check vs. current $sid (patience!)
|
||
if egrep -s "^$i[ ]" $sid; then
|
||
egrep "^$i[ ]" $todo >> $chg; continue
|
||
fi
|
||
echo "This file is not in $sid:"
|
||
echo " $i"
|
||
echo -n "Add new entry? (y/n) "
|
||
eval "$get_yn" && egrep "^$i[ ]" $todo >> $add && continue
|
||
echo "Remove entry: $i " >> $errs
|
||
else #OK to check vs SCCS tree (faster)
|
||
[ -f ${mt_dir}/$i ] && continue
|
||
echo "$notfound $i" >> $errs
|
||
fi
|
||
done
|
||
fi
|
||
|
||
#Check deletes
|
||
|
||
if [ -s $del ] && [ "$edit_sid" ]; then
|
||
for i in `cat $del`; do
|
||
[ -f $top/$i ] && continue
|
||
egrep -s "^$i[ ]" $sid && continue
|
||
echo "$notfound $i" >> $errs
|
||
done
|
||
fi
|
||
|
||
if [ -s $errs ] || [ -s $nochg ] ; then
|
||
if [ "$edit_sid" ] ; then
|
||
ok=/tmp/patch_sid.pass; rm -f $ok
|
||
for i in $chg $del $add; do
|
||
if [ "$i" = $del ] && [ -s $del ] ; then
|
||
for j in `cat $del`; do
|
||
egrep -s "[ ]$j$" $errs && continue
|
||
echo "*D*$j" >> $ok && continue
|
||
done
|
||
else
|
||
[ -s $i ] && cat $i >> $ok
|
||
fi
|
||
done
|
||
echo ""
|
||
eval "$cleanup"
|
||
[ -s $ok ] && echo "Entries that have passed verification are in '$ok'."
|
||
exit 1
|
||
else
|
||
eval "$cleanup"; exit 1
|
||
fi
|
||
fi
|
||
|
||
#Get next SID for $sid; use it to rename $fix
|
||
|
||
if [ "$edit_sid" ]; then
|
||
comfile=$tmp/comment_$$
|
||
echo \
|
||
"Enter delta comments below; type Control-D when done:"
|
||
while read comment; do
|
||
echo "$comment">> $comfile
|
||
done
|
||
[ "$bugid" ] && echo "$bugid" >> $comfile
|
||
echo "Editing large file '$sid'... "
|
||
trap 'echo ABORTED!; eval "$cleanup"; exit 1' 1 2 3 15
|
||
if sccs edit $sid > $tmp/ed_$$ ; then
|
||
:
|
||
else
|
||
eval "$cleanup"; exit 1
|
||
fi
|
||
new_sid=`fgrep 'new delta' $tmp/ed_$$ | awk '{print $3}'`
|
||
echo "New version is $new_sid..."
|
||
else
|
||
new_sid=`fgrep "SIDlist/SCCS/s.$release.SID" $todo |\
|
||
awk '{print $2}'`
|
||
if [ ! "$new_sid" ] ; then
|
||
echo "ERROR: Input file should include $sid file."
|
||
eval "$cleanup"; exit 1
|
||
fi
|
||
fi
|
||
|
||
#$newfix shouldn't already exist; check it just the same
|
||
|
||
newfix=${sid_dir}/${fix}_${new_sid}
|
||
if [ -s $newfix ]; then
|
||
echo -n "$newfix exists; Clobber? (y/n) "
|
||
if eval "$get_yn"; then
|
||
rm -f $newfix
|
||
else
|
||
[ "$edit_sid" ] && eval "$cleanup"; exit 1
|
||
fi
|
||
fi
|
||
|
||
#If invoked on integration system, edit $sid; fix format of new files;
|
||
#split huge sedfiles to avoid overflow;
|
||
#append $bugid to sccs delta comments; Send mail
|
||
|
||
if [ "$edit_sid" ]; then
|
||
stars='********************'; sedit=$tmp/sedit_$$; sidtmp=$tmp/sid_$$
|
||
if [ -s $chg ]; then
|
||
cat $chg | \
|
||
awk '{printf ("s@^\(%s \)\(.*\)@\1%s@\n", $1, $2)}' > $sedit
|
||
fi
|
||
if [ -s $del ]; then
|
||
cat $del | \
|
||
awk '{printf ("s@^\(%s \)\(.*\)@@g\n", $1 )}' >> $sedit
|
||
echo '/^[ \t]*$/d' >> $sedit
|
||
fi
|
||
if [ -s $sedit ]; then
|
||
maxsz=80
|
||
sz=`wc -l $sedit | awk '{print $1}'`
|
||
if [ $sz -gt $maxsz ] ; then
|
||
subset=$tmp/split$$_; nu=$tmp/newcmd$$
|
||
split -$maxsz $sedit $subset
|
||
sets=`ls $subset*`; first=1
|
||
for i in $sets; do
|
||
sfx=`echo $i | sed 's@^.*_@@g'`
|
||
interm=$tmp/${sfx}_$$
|
||
if [ "$first" ]; then
|
||
echo "sed -f $i $sid 2>> $errs >> $interm" >> $nu
|
||
echo 'sync; sync' >> $nu
|
||
echo "rm -f $sid" >> $nu
|
||
first=
|
||
else
|
||
echo "sed -f $i $nextsid 2>> $errs >> $interm" \
|
||
>> $nu
|
||
echo 'sync; sync' >> $nu
|
||
echo "rm -f $nextsid" >> $nu
|
||
fi
|
||
nextsid=$interm
|
||
done
|
||
chmod +x $nu; . $nu 2>> $errs ; sync; sync
|
||
[ ! -s $errs ] && mv $interm $sidtmp 2>> $errs
|
||
else
|
||
sed -f $sedit $sid > $sidtmp 2>> $errs
|
||
fi
|
||
else
|
||
cp -p $sid $sidtmp 2>> $errs
|
||
fi
|
||
if [ -s $add ]; then
|
||
cat $add | awk '{print $1, $2}' >> $sidtmp 2>> $errs
|
||
fi
|
||
sync; sync
|
||
[ -s "$errs" ] && echo "EDIT failed!" && eval "$cleanup" && exit 1
|
||
mv $sidtmp $sid; sync; sync
|
||
trap '' 1 2 3 15
|
||
sed -e 's/$/ \\/g' $comfile | sccs delget $sid
|
||
if [ ! "$?" = 0 ] ; then
|
||
echo "^GUnable to delta $sid!"
|
||
eval "$cleanup"; exit 1
|
||
fi
|
||
rm -f ${fix}_save; mv $fix ${fix}_save
|
||
cp -p $tmp/${fix}_$$ $fix
|
||
trap 'echo ABORTED!; eval "$cleanup"; exit 1' 1 2 3 15
|
||
echo -n "Include special instructions in e-mail? (y/n) "
|
||
eval "$get_yn" && do_mesg=1
|
||
ed $tmp/${fix}_$$ > /dev/null 2>&1 << jlt
|
||
1i
|
||
Please follow these steps to populate your source tree
|
||
with the latest build fixes for $release.
|
||
|
||
1. create '$sid_dir/$fix' using the entries
|
||
below the dotted line
|
||
2. patch_sid
|
||
3. rebuild affected directories.
|
||
|
||
After extracting the SCCS files using 'patch_sid', '~/$fix'
|
||
on your build machine will be moved to '~/${fix}_$new_sid'. Please
|
||
check that we are in sync by verifying that you have the
|
||
complete set of suffixed files in $sid_dir.
|
||
|
||
`whoami`@`hostname`
|
||
---------------------cut here-------------------------
|
||
SIDlist/SCCS/s.${sid} ${new_sid}
|
||
.
|
||
w
|
||
q
|
||
jlt
|
||
mesg=$tmp/mesg_$$
|
||
if [ "$do_mesg" ] ; then
|
||
echo "${stars}SPECIAL INSTRUCTIONS${stars}
|
||
" > $mesg
|
||
echo "${stars}${stars}${stars}
|
||
">> $mesg
|
||
echo "SIDlist delta comments are:" >> $mesg
|
||
cat $comfile >> $mesg
|
||
echo "" >> $mesg
|
||
cat $tmp/${fix}_$$ >> $mesg
|
||
echo -n \
|
||
"Press <RETURN> to invoke 'vi'; your text will be prepended to usual mail: "
|
||
read return
|
||
vi +2 $mesg
|
||
else
|
||
echo "SIDlist delta comments are:" >> $mesg
|
||
cat $comfile >> $mesg
|
||
echo "" >> $mesg
|
||
cat $tmp/${fix}_$$ >> $mesg
|
||
fi
|
||
echo "Sending mail to:"
|
||
echo " $reng"
|
||
/usr/ucb/mail -s "NEW sidfix $new_sid" $reng < $mesg
|
||
mv $fix $newfix; chmod +w $newfix
|
||
fi
|
||
|
||
#If invoked from a build machine, extract/delete the sources in $fix
|
||
|
||
if [ "$get_files" ]; then
|
||
cd $top
|
||
getit=$tmp/getit_$$; bad=$tmp/bad_$$;
|
||
echo "cd $top" > $getit
|
||
cat $todo | \
|
||
sed -e 's/\/SCCS\/s\./ /g' -e 's/^SCCS\/s\./\. /g' |\
|
||
awk '{printf ("(cd %s; sccs get -r%s ${mt_dir}/%s/%s) 2>>$errs \n",\
|
||
$1, $3, $1, $2 )}' >> $getit
|
||
if [ -s $del ]; then
|
||
cat $del | \
|
||
sed -e 's/\/SCCS\/s\./ /g' -e 's/^SCCS\/s\./\. /g' |\
|
||
awk '{printf ("( [ -d %s ] && cd %s && rm -f %s ) 2>> $errs\n",\
|
||
$1, $1, $2 )}' >> $getit
|
||
fi
|
||
chmod +x $getit
|
||
trap '' 1 2 3 15
|
||
. $getit
|
||
[ -s $errs ] && grep -v 'No id keywords' $errs > $bad
|
||
if [ -s $bad ]; then
|
||
mv $bad $errs
|
||
else
|
||
rm -f $errs
|
||
mv ${sid_dir}/${fix} $newfix; chmod +w $newfix
|
||
fi
|
||
fi
|
||
|
||
[ -s $newfix ] && touch $newfix && chmod 444 $newfix
|
||
eval "$cleanup" && exit 0 || exit 1
|
||
|