home *** CD-ROM | disk | FTP | other *** search
/ Jason Aller Floppy Collection / 204.img / SC386BN1.TD0 / etc / custom < prev    next >
Encoding:
Text File  |  1988-08-11  |  25.6 KB  |  1,000 lines

  1. :
  2. #    @(#) custom.sh 3.15 88/05/05 
  3. #
  4. #    Copyright (C) The Santa Cruz Operation, 1985, 1986, 1987.
  5. #    This Module contains Proprietary Information of
  6. #    The Santa Cruz Operation and is Confidential.
  7. #
  8. # CUSTOM - Xenix System V installation tool
  9. #
  10. # Executable dependencies:
  11. #    awk cat comm cpio df env expr find fixperm fsck getopt
  12. #    mount mv pr rm rmdir sed sh sort tr tar umount
  13. #
  14. PATH=/bin:/usr/bin:/etc
  15. # Return codes for init, prep and rmv scripts
  16. : ${OK=0} ${FAIL=1} ${STOP=10} ${HALT=11}
  17.  
  18. # export variables that may be used in init scripts
  19. export mnt prd rdev bdev rel vol typ
  20.  
  21. # root directory, must be non-null, must work w/ xnx-net (// -> mch name) 
  22. # and w/ # directory names (e.g., /mnt)
  23. case $CUSTOMROOT in
  24.     //*)    echo "Invalid root directory." >&2 ; exit $FAIL    ;;
  25.     */)        ;;                # ok
  26.     "")        CUSTOMROOT=/                    ;;
  27.     *)        CUSTOMROOT=$CUSTOMROOT/                ;;
  28. esac
  29. # home of init scripts, may be null
  30. : ${CUSTOMINIT="${CUSTOMROOT}tmp/init.*[!%]"}
  31. # home of prep scripts, may be null
  32. : ${CUSTOMPREP="${CUSTOMROOT}tmp/perms/prep.*[!%]"}
  33.  
  34. # set defaults - all paths are relative to CUSTOMROOT
  35. last=4    lst=4            # last item on set menu
  36. quit=quit            # q option printed by prompt
  37. tmp=${CUSTOMROOT}tmp/cus$$    # temporary file name prefix
  38. defdev=${CUSTOMROOT}dev/install    # default device for mounting filesystems
  39. defrdev=${CUSTOMROOT}dev/rinstall # default device for extracting tar volumes
  40. defmnt=N01            # default list of mountable volumes
  41. null=${CUSTOMROOT}dev/null    # bit sink for unwanted error messages
  42. lib=${CUSTOMROOT}usr/lib/custom    # home of removal scripts
  43. pfx=./tmp/_lbl            # software label prefix
  44. ser="${CUSTOMROOT}tmp/*.ser"    # serialization files created by init scripts
  45. retn="\007\nand press <RETURN> " # common in prompts
  46.  
  47. # must be at root
  48. cd $CUSTOMROOT
  49.  
  50. # known permlist names
  51. perms="*/\*|*/inst|*/rts|*/ext|*/dsmd|*/soft|*/tpmd|*/text"
  52.  
  53. (set -h) 2> $null || {
  54.     echo "$0: must be invoked with System V shell" >&2
  55.     exit 1
  56. }
  57. # Remember functions as they are defined
  58. set -h
  59.  
  60. # Print error message
  61. error() {
  62.     echo "\nError: $*" >&2
  63.     return 1
  64. }
  65.  
  66. warngetyn() {
  67.     echo "\nWarning: $*\nDo you wish to continue? (y/n) \c" >&2
  68.     getyn
  69. }
  70.  
  71. # Remove temp files and exit w/ argument as status
  72. cleanup() {
  73.     trap '' 1 2 3 15
  74.     rm -f $CUSTOMINIT $CUSTOMPREP $tmp* $ser
  75.     exit $1
  76. }
  77.  
  78. # Initialize list of packages in current set
  79. getsetlist() {
  80.     [ "$notty" ] && return 0
  81.     echo > $tmp.$sid "
  82.     Name    Inst    Size    $set packages
  83.     --------------------------------------------------------------------"
  84.     fixperm -iv $ignorepkgs $perm |
  85.     sed "s/^\(.*\)    .*$/s:^#!\1[     ][     ]*:    &    :p/" > $tmp.fl
  86.     sed -n -f $tmp.fl $perm >> $tmp.$sid
  87. }
  88.  
  89. # Update package list after installation or removal
  90. # Can't use $ignorepkgs here (much as I'd like to) since fixperm considers
  91. # having a -u AND a -d a fatal error, so I've got $lpkgs which indicates 
  92. # exactly those things pertinent to the report of "No, Part, All" status
  93. updatesetlist() {
  94.     [ "$notty" -o ! -f $tmp.$sid ] && return 0
  95.     fixperm -iv $lpkgs $perm |
  96.         sed "s/^\(.*\)    .*$/s:\1    [^     ]*:&:/" > $tmp.fl
  97.     sed -f $tmp.fl $tmp.$sid > $tmp.tl
  98.     mv $tmp.tl $tmp.$sid
  99. }
  100.  
  101. # Usage:  logit [status]
  102. # Add a record to the system installation history file
  103. # Argument overrides current status variable
  104. logit() {
  105.     trap 'intr=true' 1 2 3 15
  106.     echo "date=\"`date`\" \\
  107. prd=$prd rel=$rel upd=$upd typ=$typ set=\"$set\" \\
  108. action=$action status=\"${*:-${status:-"Successful"}}\" \\
  109. pkgs=\"$spkgs\"\n" >> $lib/history
  110.     status=
  111.     [ "$intr" = true ] && cleanup 1
  112.     trap 'cleanup 1' 1 2 3 15
  113. }
  114.  
  115. # Usage: addstat status
  116. # Add argument to current status variable
  117. addstat() {
  118.     [ "$status" ] && status="$status, $*" || status="Failed: $*"
  119. }
  120.  
  121. # Set trap to log interrupts along w/status info (spkgs are pkgs for status log)
  122. setlogtrap() {
  123.     action=        # action (Installation or Removal)
  124.     status=        # status of action
  125.     spkgs=        # pkgs/files being manipulated
  126.     intr=        # flag for interrupts during logit exec
  127.     trap 'addstat Interrupted; logit; cleanup 1' 1 2 3 15
  128. }
  129.  
  130. # Prompt with arguments, return non-zero on q
  131. #     -x and +x toggle debug mode
  132. #     ! gets shell escape (can modify current shell)
  133. #     anything else is returned in $cmd
  134. prompt() {
  135.     while    echo "\n${*}or enter q to $quit: \c" >&2
  136.         read cmd
  137.     do    case $cmd in
  138.         +x|-x)    set $cmd            ;;
  139.         Q|q)    return 1            ;;
  140.         !*)    eval `expr "$cmd" : "!\(.*\)"`    ;;
  141.         *)    return 0            ;;
  142.         esac
  143.     done
  144. }
  145.  
  146. # Mount a filesystem and clean if necessary
  147. # Returns non-zero on failure
  148. mntvol() {
  149.     until    mount -r $dev /mnt 2> $null
  150.     do    [ $? = 2 ] && fsck -y $dev || {
  151.             addstat Extract
  152.             error "corrupted or non-filesystem volume"
  153.             return 1
  154.         }
  155.     done
  156. }
  157.  
  158. # Usage: getsetvals sid [vkey|perm]
  159. # Set all values needed for specified set - called frequently.
  160. # Can be used to associate a permlist with a keyletter and vice-versa.
  161. # Default keyletter (vkey) will be used for os, ds, or tp if not specified.
  162. # Update permlists must be named $prd.$upd where upd=$vkey to work properly.
  163. getsetvals() {
  164.     # clear all values
  165.     set= perm= lbl= vkey= typ= ver= prd= upd= rel=
  166.     # these values have reasonable defaults
  167.     mnt=$defmnt dev=$defdev rdev=$defrdev
  168.     ignorepkgs="-uINIT -uPERM"
  169.     case $1 in
  170.     0)    eval $k0 perm=$k0perm
  171.         ;;
  172.     1)    set="Operating System" prd=xos
  173.         ignorepkgs="-uINIT -uPERM -uSER1 -uSER2 -uSER3 -uSER4 -uFD48\
  174.             -uFD96 -uHD1 -uHD1AD -uHD1WD -uHD2 -uHD3"
  175.         N=./etc/inst.perms B=./etc/rts.perms X=./etc/ext.perms
  176.         perm="$N $B $X $k1perm" lbl=$set
  177.         case $2 in
  178.         $N|N|"")    vkey=N
  179.                 lbl="$set (Installation)"    ;;
  180.         $B|B)        vkey=B
  181.                 lbl="$set (Basic Utilities)"    ;;
  182.         $X|X)        vkey=X
  183.                 lbl="$set (Extended Utilities)"    ;;
  184.         *U*)        updtvkey $2
  185.                 lbl="$set (Update)"        ;;
  186.         esac
  187.         eval eval \$k1$vkey
  188.         ;;
  189.     2)    set="Development System" prd=xds
  190.         N=./etc/dsmd.perms D=./etc/soft.perms
  191.         perm="$N $D $k2perm" lbl=$set
  192.         case $2 in
  193.         $N|N)        vkey=N
  194.                 lbl="Operating System (Installation)"    ;;
  195.         $D|D|"")    vkey=D                    ;;
  196.         *U*)        updtvkey $2
  197.                 lbl="$set (Update)"            ;;
  198.         esac
  199.         eval eval \$k2$vkey
  200.         ;;
  201.     3)    set="Text Processing System" prd=xtp
  202.         N=./etc/tpmd.perms T=./etc/text.perms
  203.         perm="$N $T $k3perm" lbl=$set
  204.         case $2 in
  205.         $N|N)        vkey=N
  206.                 lbl="Operating System (Installation)"    ;;
  207.         $T|T|"")    vkey=T                    ;;
  208.         *U*)        updtvkey $2
  209.                 lbl="$set (Update)"            ;;
  210.         esac
  211.         eval eval \$k3$vkey
  212.         ;;
  213.     4)    # New add-on products have permlist in ./tmp/perms
  214.         set="distribution" perm="./tmp/perms"
  215.         lbl=$set
  216.         ;;
  217.     [4-$lst]|[$tens][$ones])
  218.         # Supported products already installed
  219.         savid=$1
  220.         case $2 in
  221.         *U*)        updtvkey $2                ;;
  222.         esac
  223.         eval eval \$k$savid$vkey
  224.         eval perm=\$k${savid}perm
  225.         unset savid
  226.         lbl=$set
  227.         ;;
  228.     *)    return 1
  229.         ;;
  230.     esac
  231.     return 0
  232. }
  233.  
  234. # Usage: getperms
  235. # $perm should be set on entry to this routine.
  236. # If any member of $perm is not found then try to install it.
  237. # Return non-zero on errors or failure to install a permlist.
  238. getperms() {
  239.     for h in $perm
  240.     do    [ -f $h ] && continue
  241.         # getsetvals finds vkey
  242.         getsetvals $sid $h
  243.         echo "\nInstalling custom data files ... \c" >&2
  244.         vol=${vkey}01
  245.         until    prompt "\nInsert $lbl volume ${vkey}1$retn" || return 1
  246.             chkswlabel noperm
  247.         do    case $? in
  248.             1)    continue            ;;
  249.             4)    echo "\nThis volume is not custom installable."
  250.                 echo "Please consult your installation notes."
  251.                 return 1            ;;
  252.             *)    error "getperms $?"
  253.                 return 1            ;;
  254.             esac
  255.         done
  256.         extract $h || return 1
  257.         # $h might be a directory for new products
  258.         [ -d $h ] && return 0
  259.         fixperm -c -dPERM $h
  260.     done
  261. }
  262.  
  263. # Check for release, version, etc. in permlists
  264. # sid must be set on entry
  265. checkperms() {
  266.     # getsetvals finds permlist names
  267.     getsetvals $sid
  268.     for i in $perm
  269.     do    # getsetvals finds vkey
  270.         getsetvals $sid $i
  271.         eval k$sid$vkey='`getpermvals $i`'
  272.     done
  273. }
  274.  
  275. # Usage: getpermvals files
  276. # Extract lines beginning w/ #name=value and print name=value pair on stdout
  277. getpermvals() {
  278.     sed -n '/^#set=/s/#//p
  279.         /^#prd=/s/#//p
  280.         /^#ver=/s/#//p
  281.         /^#typ=/s/#//p
  282.         /^#rel=/s/#//p
  283.         /^#mnt=/s/#//p
  284.         /^#dev=/s/#//p
  285.         /^#rdev=/s/#//p
  286.         /^#lbl=/s/#//p
  287.         /^#upd=/s/#//p' $*
  288. }
  289.  
  290. # Set values from label as local variables; ignore errors.
  291. getswlabel() {
  292.     # clear all values
  293.     _prd= _ver= _upd= _typ= _rel= _vol=
  294.     eval 'case $vol in
  295.     '${mnt:-!}')    mntvol || return 1
  296.         eval `find /mnt/$pfx -type f -print | pathtovals`
  297.         umount $dev                        ;;
  298.     *)    eval `tar tqnf $rdev $pfx 2> $null | pathtovals`    ;;
  299.     esac'
  300. }
  301.  
  302. # Convert a path of the form ./tmp/_lbl/name=val/name=val ...
  303. # to shell variables w/ leading underscores and print on stdout.
  304. pathtovals() {
  305.     sed -n "s|^.*$pfx||
  306.         s|/| _|gp"
  307. }
  308.  
  309. # Check volume number, release, and version; returns:
  310. # 1 - wrong volume
  311. # 2 - update needed but not wanted 
  312. # 3 - update attempted
  313. # 4 - missing volume label
  314. chkswlabel() {
  315.     noperm=$1
  316.     # get set/vkey specific values from permlist
  317.     getsetvals $sid $vkey
  318.     # set values from the label
  319.     getswlabel || return 1
  320.     # if no permlist present, assume values are correct
  321.     [ "$noperm" ] && prd=$_prd ver=$_ver typ=$_typ rel=$_rel
  322.     # compare permlist and label values
  323.     case $_prd in
  324.     $prd)    # product matches
  325.                 ;;
  326.     xnxsv)    # forever correcting for our youth ...
  327.         case $prd in
  328.         xos|xds|xtp)    : installing 2.1 vols    ;;
  329.         *)    error "incorrect product in drive"
  330.             return 1            ;;
  331.         esac        ;;
  332.     xos|xds|xtp)    # more youthful corrections ...
  333.         case $prd in
  334.         xnxsv)    : updating from 2.1 to 2.2    ;;
  335.         *)    error "incorrect product in drive"
  336.             return 1            ;;
  337.         esac        ;;
  338.     "")    error "volume label not found"
  339.         return 4    ;;
  340.     *)    error "incorrect product in drive"
  341.         return 1    ;;
  342.     esac
  343.  
  344.     for i in $_typ $_ver
  345.     do    case $i in
  346.         $typ|$ver) # type and/or version matches
  347.             break        ;;
  348.         *)    warngetyn "product type in drive (${_typ:-$_ver}) is
  349. different than previously installed type (${typ:-$ver})." && break
  350.             return 1    ;;
  351.         esac
  352.     done
  353.  
  354.     case $_vol in
  355.     $vol|$_upd$vol)    : volume number matches    ;;
  356.     *)        error "incorrect volume in drive"
  357.             return 1        ;;
  358.     esac
  359.  
  360.     [ "$rel" = "$_rel" ] && return 0
  361.     # || there is a permlist from an old release, vkey is correct,
  362.     # and noperm is not a consideration.
  363.     # Do not proceed if we are updating the release.
  364.     [ "$nest" = y ] && {
  365.         error "volume ${vkey}1 must be Release $rel"
  366.         return 1
  367.     }
  368.     nest=y
  369.     echo "\nUpdating custom data files ... \c" >&2
  370.     # Permlists always on volume ?01
  371.     [ "$_vol" != "${vkey}01" ] && {
  372.         # Volume containing permlist must be new release
  373.         eval k$sid$vkey="rel=$_rel\ \$k$sid$vkey"
  374.         vol=${vkey}01
  375.         until    prompt "\nInsert $lbl volume ${vkey}1$retn" || {
  376.                 nest=
  377.                 return 2
  378.             }
  379.             chkswlabel
  380.         do    case $? in
  381.             [14])    continue        ;;
  382.             [!2])    error "chkswlabel $?"    ;;
  383.             esac
  384.             nest=
  385.             return 2
  386.         done
  387.     }
  388.     nest=
  389.     if [ "$sid" -lt 4 ]; then
  390.         # only extract perms matching vkey
  391.         eval extract \$$vkey || return 2
  392.         eval fixperm -c -dPERM \$$vkey
  393.     else
  394.         # add on product perms live in the directory ./tmp/perms
  395.         rm -rf ./tmp/perms
  396.         extract ./tmp/perms && execinit $CUSTOMPREP &&
  397.             countperms ./tmp/perms/* || return 2
  398.         mv ./tmp/perms/* $perm
  399.         rm -rf ./tmp/perms
  400.     fi
  401.     echo >&2
  402.     # spkgs is not applicable when only the permlist was updated.
  403.     # spkgs gets reset using $save in the calling function.
  404.     spkgs=
  405.     logit "Updated custom datafiles"
  406.     return 3
  407. }
  408.  
  409. # Usage: execinit files
  410. # Move files to unique names and execute them.
  411. # This is trickier than it seems.  We cannot simply append our pid
  412. # since children must remove all files matching init.* except these.
  413. # Returns exit status of last file executed.
  414. # Scripts are passed the argument "-c" to indicate that they were
  415. # invoked by custom.  Execute with "sh -c" because they may be binaries,
  416. # but we have space problems if scripts are executed in the current shell.
  417. execinit() {
  418.     [ -x $lib/execinit ] && {
  419.         $lib/execinit $*
  420.         return $?
  421.     }
  422.     # append % to scripts prevent children from removing them
  423.     for i do [ -x $i ] && mv $i $i% && ilist="$ilist $i"; done
  424.     j=0
  425.     for i in $ilist
  426.     do    sh -c "$i% -c"; j=$?
  427.         case $j in
  428.         $OK)    : All is well                    ;;
  429.         $STOP)    logit "Stopped by Init/Prep Script"
  430.             unset ilist; return $STOP            ;;
  431.         $HALT)    error "haltsys not supported"            ;;
  432.         $FAIL)    addstat "Init/Prep Script"; error "$i failed"    ;;
  433.         esac
  434.         rm -f $i%
  435.     done
  436.     unset ilist
  437.     return $j
  438. }
  439.  
  440. # Prompt for yes or no answer - returns non-zero for no
  441. getyn() {
  442.     while    read yn
  443.     do    case $yn in
  444.         [yY])    return 0             ;;
  445.         [nN])    return 1            ;;
  446.         *)    error "enter either y or n"     ;;
  447.         esac
  448.     done
  449. }
  450.  
  451. # Extract a list of files - returns non-zero on failure
  452. extract() {
  453.     case $1 in
  454.     -F)    shift; flags=F    ;;
  455.     *)    flags=        ;;
  456.     esac
  457.     filelist=$*
  458.     eval 'case $vol in
  459.     '${mnt:-!}')    mntvol || return 1
  460.         until    (cd /mnt; tar cf$flags - $filelist) | tar xf -
  461.         do    error "extraction failed: try again? (y/n) \c"
  462.             getyn && continue
  463.             umount $dev
  464.             return 1
  465.         done
  466.         umount $dev    ;;
  467.     *)    until    tar xnf$flags $rdev $filelist
  468.         do    error "extraction failed: try again? (y/n) \c"
  469.             getyn || return 1
  470.         done
  471.     esac'
  472.     unset filelist flags
  473. }
  474.  
  475. # Usage: updtvkey [vkey|permlist]
  476. # Get vkey corresponding to an update for a supported product
  477. # vkey is set to either the suffix of the argument (ie vkey=UA
  478. # for lyrix.UA), or the entire argument if no suffix exists.
  479. updtvkey() {
  480.     ifs=$IFS; IFS=.
  481.     set -- ${*?}
  482.     IFS=$ifs; unset ifs
  483.     eval vkey=\$$#
  484. }
  485.  
  486. # Get vkey from 1st letter of argument and create pvol
  487. # pvol has leading zero stripped and is for prompts only
  488. # (can't take multiple arguments, so always uses first arg for safety)
  489. getvkey() {
  490.     vkey=`expr $1 : "\(.*\).."`
  491.     pvol=$vkey`expr $1 : "${vkey}0*\(.*\)"`
  492. }
  493.  
  494. # countperms - passed a list of permlists as arguments
  495. # returns ok if only one is found
  496. countperms() {
  497.     case $# in
  498.     0)    error "missing custom data files"    ;;
  499.     1)    [ -f $1 ] && return 0            ;;
  500.     *)    error "multiple custom data files"    ;;
  501.     esac
  502.     return 1
  503. }
  504.  
  505. # convert the argument passed in from a set name to a set id
  506. # returns either the sid or zero if no legal conversion can be made
  507. nametosid() {
  508.     j=$1
  509.     for i in 1 2 3  5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
  510.     do    getsetvals $i || return 0
  511.         [ "$j" = "$prd" ] && return $i
  512.     done
  513.     error "nametosid search overrun"
  514. }
  515.  
  516. # check ./etc/perms for new set to add to menu
  517. # returns zero if no new sets were found, otherwise returns
  518. # the sid of the last new set found.
  519. chkfornewsets() {
  520.     stat=0
  521.     # only check if forced (-f) or if no check done yet
  522.     [ "$setchkdone" = y -a "$1" != -f ] && return $stat
  523.     for h in ./etc/perms/*
  524.     do    eval "case $h in $perms) continue; esac"
  525.         # add perm to known list and get values from it
  526.         perms="$perms|$h" k0perm=$h
  527.         k0=`getpermvals $k0perm`
  528.         # are the required values all there?
  529.         getsetvals 0
  530.         [ "$set" -a "$prd" -a "$rel" ] || {
  531.             error "invalid custom data file: $k0perm"
  532.             continue
  533.         }
  534.         # new sets are added to menu, but updates are not
  535.         if [ "$upd" ]; then
  536.             # allow product it updates to be different from
  537.             # "#prd=" in the permlist, as in case of files in
  538.             # tpmd and dsmd
  539.             case $k0perm in
  540.             *.$upd)    prdname=`expr $k0perm : "\./etc/perms/\(.*\)\.$upd"`
  541.                 ;;
  542.             *)    prdname=$prd
  543.                 ;;
  544.             esac
  545.             # find the sid of the product it updates
  546.             if nametosid $prdname; then
  547.                 error "update for unknown product: $k0perm"
  548.             else    # save sid and reset to update values
  549.                 stat=$?; getsetvals 0
  550.                 # add to product $perm and save update values
  551.                 eval k${stat}perm="\$k${stat}perm\ $k0perm" \
  552.                     k${stat}$upd='$k0'
  553.             fi
  554.         else
  555.             last=`expr $last + 1`
  556.             eval k$last='$k0' k${last}perm=$k0perm
  557.             lst=$last newsets="$newsets$last. $set\n\t"
  558.             stat=$last
  559.         fi
  560.     done
  561.     # allow for more than ten sets to be added
  562.     [ $last -gt 9 ] && {
  563.         tens="1-`expr $last / 10`"
  564.         ones="0-`expr $last % 10`"
  565.         lst=9
  566.     }
  567.     setchkdone=y
  568.     return $stat
  569. }
  570.  
  571. listpkgs() {
  572.     cat $tmp.$sid
  573.     echo "\nPress <RETURN> to continue \c" >&2
  574.     read i
  575. }
  576.  
  577. printhelp() {
  578.     pr -ptl24 $lib/help
  579.     echo "\nPress <RETURN> to continue \c" >&2
  580.     read i
  581. }
  582.  
  583. installpkgs() {
  584.     action=Installation
  585.     cmd=$*
  586.     [ "$cmd" ] || {
  587.         cat $tmp.$sid
  588.         prompt "Enter the package(s) to install\n" || return 1
  589.     }
  590.     pkgs=    regx=    not=    save=$cmd    lpkgs=
  591.     for i in `echo $cmd | tr "[a-z]" "[A-Z]"`
  592.     do    case $i in
  593.         RTS|INST) if [ $CUSTOMROOT = / ]; then
  594.                 error "Re-installing $i is not supported"
  595.             else    # allow RTS installation on alternate root
  596.                 pkgs="$pkgs -d$i" regx=${regx}${regx:+"|"}$i
  597.                 lpkgs="$pkgs"
  598.                 spkgs="$spkgs${spkgs:+' '}$i"
  599.             fi            ;;
  600.         ALL)    pkgs="-uRTS -uPERM -uINIT -uINST -uSER1 -uSER2 -uSER3 \
  601.                 -uSER4 -uFD48 -uFD96 -uHD1 -uHD1AD -uHD1WD -uHD2 -uHD3"
  602.             regx=$i
  603.             # subtract size of RTS, INST and PERM from ALL
  604.             not='$1 ~ /^#!(RTS|INST|PERM)$/ { s -= $2 }'
  605.             lpkgs="-uPERM -uINIT -uSER1 -uSER2 -uSER3 -uSER4 \
  606.                 -uFD48 -uFD96 -uHD1 -uHD1AD -uHD1WD -uHD2 -uHD3" 
  607.             spkgs=ALL
  608.             break            ;;
  609.         *)    pkgs="$pkgs -d$i" regx=${regx}${regx:+"|"}$i    
  610.             lpkgs="$pkgs"
  611.             spkgs="$spkgs${spkgs:+' '}$i"    ;;
  612.         esac
  613.     done
  614.     [ "$pkgs" ] || return 1
  615.  
  616.     # put the contents list for each volume into a separate file
  617.     > $tmp.fl; > $tmp.tl; > $tmp.ul
  618.     fixperm -fw $pkgs $perm |
  619.       sort -u +1 +0 |
  620.         awk '$2 <= 0    { next } # missing or zero vol field
  621.          $2 != vol    { if (vol) print "EOF" vol
  622.                    vol = $2
  623.                     print "cat>" t vol "<<\EOF" vol
  624.                   # put N and upgrade volumes in separate files
  625.                   if (vol ~ /N+/)
  626.                     print vol >> (t "tl")
  627.                   else if (vol ~ /U+/)
  628.                     print vol >> (t "ul")
  629.                   else
  630.                     print vol >> (t "fl")
  631.                 }
  632.                 { print $1 }
  633.         ' t=$tmp. - |
  634.           sh || { addstat "Fixperm/File List"; return 0; }
  635.  
  636.     [ -s $tmp.fl -o -s $tmp.tl -o -s $tmp.ul ] || {
  637.         error "$set has no package(s) named $cmd"
  638.         return 1
  639.     }
  640.  
  641.     size=`awk "\\$1 ~ /^#!($regx)$/ { s += \\$2 }
  642.         $not
  643.         END { print s+0 }" $perm`
  644.     set -- `df /dev/root` # third arg is free space
  645.     [ "$size" -gt "$3" ] && {
  646.         warngetyn "$size blocks are required and only
  647. $3 blocks are available on the root filesystem." || return 1
  648.     }
  649.     unset size
  650.     rm -f $CUSTOMINIT
  651.     # extract generic, then non-generic (N), then update (U) volumes
  652.     for vol in `cat $tmp.fl $tmp.tl $tmp.ul`
  653.     do    getvkey $vol
  654.         # get lbl string for prompt
  655.         getsetvals $sid $vkey
  656.         until    prompt "Insert $lbl volume $pvol$retn" || {
  657.                 addstat "Quit at vol $pvol"
  658.                 return 0
  659.             }
  660.             chkswlabel
  661.         do    case $? in
  662.             1|4)    continue    ;;
  663.             2)    addstat "Improper Data File"
  664.                 return 0    ;;
  665.             3)    # evaluate new permlist and redo cmd
  666.                 checkperms; installpkgs $save; getsetlist
  667.                 return 0    ;;
  668.             esac
  669.         done
  670.         echo "Extracting files ... \c" >&2
  671.         extract -F $tmp.$vol || addstat Extract
  672.         echo >&2
  673.         execinit $CUSTOMINIT || { [ $? = $STOP ] && break; }
  674.     done
  675.     echo "Checking file permissions ... \c" >&2
  676.     fixperm -c $pkgs $perm || addstat Fixperm
  677.     updatesetlist
  678.     echo >&2
  679. }
  680.  
  681. removepkgs() {
  682.     action=Removal
  683.     cmd=$*
  684.     [ "$cmd" ] || {
  685.         cat $tmp.$sid
  686.         prompt "Enter the package(s) to remove\n" || return 1
  687.     }
  688.     pkgs=    upkgs= rmvp=
  689.     for i in `echo $cmd | tr "[a-z]" "[A-Z]"`
  690.     do    case $i in
  691.         RTS|PERM|INST)    error "cannot remove $i package";;
  692.         ALL)    pkgs="-uRTS -uPERM -uINIT -uINST -uSER1 -uSER2 -uSER3 \
  693.                 -uSER4 -uFD48 -uFD96 -uHD1 -uHD1AD -uHD1WD -uHD2 -uHD3" 
  694.              upkgs="-dRTS -dINST -dPERM"
  695.             lpkgs="-uPERM -uINIT -uSER1 -uSER2 -uSER3 -uSER4 \
  696.                 -uFD48 -uFD96 -uHD1 -uHD1AD -uHD1WD -uHD2 -uHD3" 
  697.             spkgs=ALL
  698.             rmvp=ALL
  699.             break                    ;;
  700.         *)    pkgs="$pkgs -d$i"
  701.             lpkgs="$pkgs"
  702.             upkgs="$upkgs -u$i"
  703.             spkgs="$spkgs${spkgs:+' '}$i"
  704.             rmvp="$rmvp $i"                ;;
  705.         esac
  706.     done
  707.     [ "$pkgs" ] || return 1
  708.     fixperm -fg $pkgs $perm | sort > $tmp.fl
  709.     [ -s $tmp.fl ] || {
  710.         error "$set has no package(s) named $cmd"
  711.         return 1
  712.     }
  713.     # make sure that $prd is set!
  714.     getsetvals $sid
  715.     # execute product specific removal scripts (may be keyed)
  716.     for i in $lib/$prd.rmv $lib/$prd[A-Z].rmv $lib/$prd[A-Z][A-Z].rmv
  717.     do    [ -x $i ] || continue
  718.         sh -c "$i $rmvp" 
  719.         case $? in
  720.             $OK)                    ;;
  721.             $STOP)    addstat "Remove Script"
  722.                 error "$rmvp removal aborted"
  723.                 return 0            ;;
  724.             $HALT)    error "haltsys not supported "    ;;
  725.             *)    addstat "Remove Script"
  726.                 error "$rmvp removal failed"    ;;
  727.         esac
  728.     done
  729.     # create list of files not to be removed since they exist in 
  730.     # packages not being removed
  731.     # if removing "ALL", then don't need to weed out UPD.$upd files
  732.     # from this list 
  733.     [ "$rmvp" = "ALL" ] || {
  734.         for i in $perm
  735.         do    updtvkey $i        # set vkey to perm suffix
  736.             case $vkey in        # add only if an update
  737.             U*)    upkgs="$upkgs -uUPD.$vkey"    ;; 
  738.             esac
  739.         done
  740.     }
  741.     fixperm -fg $upkgs $perm > $tmp.tl
  742.     unset rmvp
  743.     # check all installed perms since some files cross set boundaries
  744.     for i in 1 2 3  5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
  745.     do    getsetvals $i || break
  746.         [ $i != $sid ] && cat -s $perm
  747.     done | fixperm -fg - >> $tmp.tl
  748.     # reset values to real sid
  749.     getsetvals $sid
  750.  
  751.     # remove the files that are not in more than one package
  752.     #   but do not exceed max argument list size
  753.     sort -y $tmp.tl |
  754.         comm -23 $tmp.fl - |
  755.         awk 'BEGIN  {   ORS=" "; print "/bin/rm -f"; }
  756.                 {   if ((argsiz += length) > 2500) {
  757.                     print ";/bin/rm -f", $0
  758.                     argsiz = length
  759.                 } else print
  760.                 }' |
  761.             env - HZ=$HZ sh || addstat Removal
  762.     # remove empty directories, if any
  763.     rmdir `fixperm -D $pkgs $perm | sort -r` 2> $null
  764.     updatesetlist
  765.     return 0
  766. }
  767.  
  768. listfiles() {
  769.     cmd=$*
  770.     [ "$cmd" ] || {
  771.         cat $tmp.$sid
  772.         prompt "Enter the package(s) to list\n" || return
  773.     }
  774.     pkgs=
  775.     for i in `echo $cmd | tr "[a-z]" "[A-Z]"`
  776.     do    case $i in
  777.         ALL)    pkgs="-uINST"; break    ;;
  778.         *)    pkgs="$pkgs -d$i"    ;;
  779.         esac
  780.     done
  781.     [ "$pkgs" ] || continue
  782.     [ -t ] && echo "\nPress <RETURN> each time the bell rings\n" >&2
  783.     fixperm -l $pkgs $perm | pr -2ptl12 ||
  784.         error "$set has no package(s) named $cmd"
  785. }
  786.  
  787.  
  788. installfile() {
  789.     action=Installation
  790.     cmd=$1            # single file only supported
  791.     [ "$cmd" ] || {
  792.         prompt "Enter the pathname of the file to install\n" || return 1
  793.     }
  794.     set -- "$cmd"    # quotes allow null $cmd
  795.     cmd=$1        # single file only supported
  796.     case $cmd in
  797.     "")    return         ;;
  798.     ./*)    file=$cmd    ;;
  799.     /*)    file=.$cmd    ;;
  800.     *)    file=./$cmd    ;;
  801.     esac
  802.     spkgs="$file"
  803.     > $tmp.vol
  804.     fixperm -fw $perm | sed -n "s!^$file[     ][     ]*!!p" | 
  805.       sort -u -r |    while read vol            # sort -r:  U before N
  806.             do    
  807.                 echo $vol > $tmp.vol
  808.                 case $vol in        # will keep looping
  809.                 U*|N*)    break ;;    # until finds U, or N
  810.                 esac            # or end of list
  811.             done
  812.  
  813.     read vol < /tmp/cus$$.vol
  814.     [ "$vol" ] || {
  815.         error "$set has no file named $file"
  816.         return 1
  817.     }
  818.     rm -f $tmp.vol
  819.     getvkey $vol
  820.     until    prompt "Insert $lbl volume $pvol$retn" || return 1
  821.         chkswlabel
  822.     do    case $? in
  823.         1|4)    continue                 ;;
  824.         2)    addstat "Improper Data File"
  825.              return 0                ;;
  826.         3)    # evaluate new permlist after completing cmd
  827.             checkperms; installfile $file; getsetlist
  828.             return 0                ;;
  829.         esac
  830.     done
  831.     echo "Extracting $file ... \c" >&2
  832.     extract $file || addstat Extract
  833.     echo >&2
  834.     unset file
  835. }
  836.  
  837. diskusage() {
  838.     bar="------------------------------------------------------"
  839.     echo "\n\t\tCurrent Disk Usage\n$bar\n`df -v`\n$bar" >&2
  840.     unset bar
  841. }
  842.  
  843. # select a new set by menu
  844. # returns non-zero on q
  845. setmenu() {
  846.     # save old set id in case user quits without selecting new one
  847.     save=$sid
  848.     chkfornewsets
  849.     while    :
  850.     do    prompt "
  851.     1. Operating System
  852.     2. Development System
  853.     3. Text Processing System
  854.     4. Add a Supported Product
  855.     $newsets\nSelect a set to customize "
  856.         case $cmd in
  857.         [1-$lst]|[$tens][$ones])
  858.             setselect $cmd || continue
  859.             [ -f $tmp.$sid ] || getsetlist
  860.             return 0                ;;
  861.         [qQ])    [ "$save" ] && setselect $save
  862.             return 1                ;;
  863.         *)    error "enter 1 through $last or q"    ;;
  864.         esac
  865.     done
  866. }
  867.  
  868.  
  869. # usage: setselect sid
  870. # The global set id (sid) is set argument.
  871. # sid can only be reset in this routine.
  872. setselect() {
  873.     sid=$1
  874.     case $sid in
  875.     [1-3])    # builtin sets
  876.         chkfornewsets
  877.         getsetvals $sid
  878.         getperms && checkperms
  879.         ;;
  880.     4)    # add a supported product
  881.         chkfornewsets
  882.         getsetvals $sid
  883.         rm -rf $perm
  884.         getperms && execinit $CUSTOMPREP || return 1
  885.         countperms $perm/* || return 1
  886.         i=`cd $perm; echo *`
  887.         [ -f ./etc/perms/$i ] && {
  888.             error "./etc/perms/$i already exists"
  889.             return 1 
  890.         }
  891.         mv $perm/$i ./etc/perms/$i
  892.         rm -rf $perm
  893.         # chkfornewsets prints an error if perm is invalid
  894.         chkfornewsets -f && return 1 || sid=$?
  895.         [ "$upd" ] && {
  896.             # ensure all perms in set are installed
  897.             getsetvals $sid $upd
  898.             getperms && checkperms
  899.             # install entire update
  900.             installpkgs UPD.$upd && logit || return 1
  901.             # cause list of packages to be regenerated
  902.             rm -f $tmp.$sid
  903.         }
  904.         getsetvals $sid
  905.         ;;
  906.     [0-9]*)    chkfornewsets
  907.         getsetvals $sid || error "invalid set number: $sid"
  908.         ;;
  909.     *)    # set was specified by name
  910.         chkfornewsets
  911.         nametosid $sid && error "unknown set name: $sid" || sid=$?
  912.         ;;
  913.     esac
  914.     return $?
  915. }
  916.  
  917.  
  918. # main()
  919.  
  920. # Initialize variables
  921. perm=    arg=    vkey=    set=    setflg=    cmdflg=    setchkdone=    tens=z
  922. sid=    nest=    save=    cmd=    pvol=    argflg=    notty=        ones=z
  923. ignorepkgs=
  924.  
  925. # (already at root)
  926. # evaluate arguments
  927. [ $# != 0 ] && {
  928.     set -- `getopt odtirlfs:m: $*` || {
  929.         echo "Usage: custom [-s set] [-ilr [pkgs]] [-f [file]] [-m rdev]" >&2
  930.         exit 1
  931.     }
  932.     while    case $1 in
  933.         -o)    setflg=1                    ;;
  934.         -d)    setflg=2                     ;;
  935.         -t)    setflg=3                    ;;
  936.         -s)    setflg=$2; shift                ;;
  937.         -i)    cmdflg='setlogtrap;installpkgs $arglst && logit';;
  938.         -r)    cmdflg='setlogtrap;removepkgs $arglst && logit'    ;;
  939.         -l)    cmdflg='listfiles $arglst'            ;;
  940.         -f)    cmdflg='setlogtrap;installfile $arglst && logit';;
  941.         -m)    defdev=$CUSTOMROOT`echo $2 | sed "s:^/*::"`
  942.             [ -c $defdev -o -b $defdev ] || {
  943.                 error "$defdev not a valid device"
  944.                 exit $FAIL
  945.             }
  946.             defrdev=$defdev
  947.             shift                        ;;
  948.         --)    shift;    break                    ;;
  949.         esac
  950.     do    shift
  951.     done
  952.     arglst="$*"
  953. }
  954. trap 'cleanup 1' 1 2 3 15
  955.  
  956. # is everything here?  if so we are fully non-interactive
  957. [ "$setflg" -a "$cmdflg" -a "$arglst" ] && {
  958.     notty=y
  959.     setselect $setflg || exit 1
  960.     eval $cmdflg
  961.     cleanup $?
  962. }
  963.  
  964. # if a valid set was given, generate a list of pkgs,
  965. # otherwise user must select a valid set now
  966. [ "$setflg" ] && setselect $setflg && getsetlist || setmenu || cleanup 0
  967.  
  968. # if a cmd was given, execute it 
  969. eval $cmdflg
  970.  
  971. unset setflg cmdflg arglst
  972. quit="return to the menu"
  973.  
  974. # central processing loop
  975. while    echo "
  976.     1. Install one or more packages
  977.     2. Remove one or more packages
  978.     3. List the available packages
  979.     4. List the files in a package
  980.     5. Install a single file
  981.     6. Select a new set to customize
  982.     7. Display current disk usage
  983.     8. Help
  984.  
  985. Select an option or enter q to quit: \c" >&2
  986. do    read cmd arg
  987.     case $cmd in
  988.     1)    setlogtrap; installpkgs $arg && logit    ;;
  989.     2)    setlogtrap; removepkgs $arg && logit    ;;
  990.     3)    listpkgs                 ;;
  991.     4)    listfiles $arg                ;;
  992.     5)    setlogtrap; installfile $arg && logit    ;;
  993.     6)    setmenu $arg                ;;
  994.     7)    diskusage                ;;
  995.     8)    printhelp                ;;
  996.     Q|q)    cleanup 0                ;;
  997.     *)    error "enter 1 through 8 or q"        ;;
  998.     esac
  999. done
  1000.