Cover V03, I05
Article
Figure 1
Figure 2
Listing 1

sep94.tar


Listing 1: The mfsck script

#!/bin/sh
#
# File:         mfsck.sh (Check File Systems on multiple disks)
# Version:      @(#)mfsck       1.10 25 May 1994 1
#
# Copyright 1994 Sun Microsystems, Inc.  Permission to copy, use, distribute,
# modify and incorporate this work in Sys Admin
# in any form is hereby granted.  Readers of Sys Admin
# may copy, use, and distribute this work
# subject to the following conditions:
#
#   1) The document may be used for non-commercial purposes only; and
#   2) Any copy of this work or portion thereof must include a copy of this
#      copyright notice.
#
# This work is provided as is without warranty of any kind, either express or
# implied, including, but not limited to, the implied warranties of
# merchantability, fitness for a particular purpose, or non-infringement.
#
# This work could include technical inaccuracies or typographical errors.
# Changes are periodically added to the information herein; these changes
# will be incorporated in new additions of the publication.
#
# Sun Microsystems, Inc. may make improvements and/or changes in its products
# and/ or its programs including the program routines described in this work
# at any time.
#
# Synopsis:
# ---------
# mfsck <task file>
#
# where,
#   <task file>  is the name of a file containing the names of the disks and
#               their partitions/file systems to check.
#
# Example:
# --------
#   mfsck task_file
#
# Exits:
# ------
#   = 0,        success
#   <>0,        failure
#
# Notes:
# ------
# -<task file> Format:
#    <logical device> <partition> ... <partition>
#
#  e.g.,
#    c0t5d0     0 1 6
#
# -'CHKFile' used to verify that a process is still active.
# -'WIPFile' is a "work-in-progress" file.
#
# *****************
# *** Functions ***
# *****************
#
# ************************
# *** Function: CkExit ***
# ************************
#
# 'fsck' EXIT CODE
# ----------------
#    0         file system is okay and does not need checking
#    1         erroneous parameters are specified
#    32        file system is unmounted and needs checking  (fsck -m only)
#    33        file system is already mounted
#    34        cannot stat device
#    36        uncorrectable errors detected - terminate normally
#    37        a signal was caught during processing
#    39        uncorrectable errors detected - terminate  immediately
#    40        for root, same as 0.
#    50        removing log file
#
# Arguments:
# ----------
# 0  Exit Code
#
CkExit () {
#
case "$1" in
0) ;;
1) EMSG="Erroneous parameters are specified"
echo "$EPROMPT$EMSG"
;;
32) EMSG="File system is unmounted and needs checking  (fsck -m only)"
echo "$EPROMPT$EMSG"
;;
33) EMSG="File system is already mounted"
echo "$EPROMPT$EMSG"
;;
34) EMSG="Cannot stat device"
echo "$EPROMPT$EMSG"
;;
36) EMSG="Uncorrectable errors detected - terminate normally"
echo "$EPROMPT$EMSG"
;;
37) EMSG="A signal was caught during processing"
echo "$EPROMPT$EMSG"
;;
39) EMSG="Uncorrectable errors detected - terminate immediately"
echo "$EPROMPT$EMSG"
;;
40) EMSG="For root, same as 0"
echo "$EPROMPT$EMSG"
;;
*) EMSG="Unknown response from 'fsck'; Received: $1"
echo "$EPROMPT$EMSG"
echo "  Please Check"
;;
esac
#
}       # *** END: CkExit ***
#
# *****************
# *** Main Code ***
# *****************
#
# **********************
# *** Initialization ***
# **********************
PID=$$
#
EPROMPT="ERROR>"
PROMPT=">"
#
NARGS=`expr 1`
#
ERR_SYNTAX=`expr 50`
ERR_TFN_OF=`expr 52`    # The task file specified is NOT an ordinary file
ERR_TFN_NRD=`expr 54`   # The task file specified is NOT readable
ERR_TFN_EPTY=`expr 56`  # The task file specified is empty
ERR_CF_NZRO=`expr 60`   # The control file exists AND is a non-ZERO file
ERR_WIP_EXISTS=`expr 62` # WIP file exists as an ordinary file or a directory
ERR_WIP_CREATE=`expr 64` # creating the WIP file
ERR_CHK_EXISTS=`expr 66` # CHK file exists as an ordinary file or a directory
ERR_CHK_CREATE=`expr 68` # creating the CHK file
ERR_LOGF_EXISTS=`expr 70` # log file for partition exists
ERR_LOGF_CREATE=`expr 72` # creating log file for partition
ERR_RM_LOGFS=`expr 76`  # removing log files

#
#
# ***********************
# *** Input Arguments ***
# ***********************

if [ "$#" -ne "$NARGS" ] ; then
echo "$EPROMPT Incorrect Number of Input Parameters; Exp: $NARGS, Obs: $#"
echo "synopsis:"
echo "  mfsck <task file>"
echo "where,"
echo "  <task file>  is the name of a file containing the disks and the"
echo "               file systems to check"
echo
echo "Notes:"
echo "------"
echo "  -Syntax of the file <task file> :"
echo "     #         comment line"
echo "     <logical device> <partition> ... <partition>"
echo
echo "   Example:"
echo "   --------"
echo "     c0t5d0 0 1 6"
echo
exit $ERR_SYNTAX
fi
#
CWD=`pwd`       # *** current working directory
***
#
RES=`expr 0`
RES1=`expr 0`
RES2=`expr 0`
EXE="999"
#
SleepSec=`expr 60`
#
SP=" "
PER="."
#
ASTER="*"
SLASH="/"
PIPE="|"
BKGND="&"
SQUOTE="'"
DQUOTE='"'
CQUOTE=$SQUOTE$DQUOTE$SQUOTE
#
EQUALS="="
PERIOD="."
#
NullList=""
#
ERRLIS=""       # error list
FERRLIS=""      # 'fsck' error list
#
FSCKCMD="fsck"
#
NDSK=`expr 0`   # number of disks
CDSK=`expr 0`   # scanning number of disks
#
CNTL="cntl"
CTRLF="$FSCKCMD$PERIOD$CNTL$PERIOD$PID"
#
F_PID=`expr 0`
#
WIP="wip"
WIPFile="$CWD$SLASH$FSCKCMD$PERIOD$WIP$PERIOD$PID"
#
CHK="chk"
CHKFile="$CWD$SLASH$FSCKCMD$PERIOD$CHK$PERIOD$PID"
#
LOG="log"
LOGFile="$CWD$SLASH$FSCKCMD$PERIOD$LOG$PERIOD$PID"
#
TFN=$1          # get the task file name
#
if [ ! -f "$TFN" ] ; then
echo "$EPROMPT The task file specified ( $TFN ) is NOT an ordinary file"
echo "  Please re-check and re-start"
exit $ERR_TFN_OF
fi
#
if [ ! -r "$TFN" ] ; then
echo "$EPROMPT The task file specified ( $TFN ) is NOT readable"
echo "  Please re-check and re-start"
exit $ERR_TFN_NRD
fi
#
if [ ! -s "$TFN" ] ; then
echo "$EPROMPT The task file specified ( $TFN ) is an empty file"
echo "  Please re-check and re-start"
exit $ERR_TFN_EPTY
fi
#
# ***************************
# *** Check: Control File ***
# ***************************
# The control file should not exist.  If it does and is non-ZERO, this is an
# error.
#
if [ -s "$CTRLF" ] ; then
echo "$EPROMPT The control file $CTRLF exists AND is a non-ZERO file"
echo "  Please re-check and re-start"
exit $ERR_CF_NZRO
fi
#
rm "$CTRLF" 1>/dev/null 2>&1
touch "$CTRLF"#
# *** Identify the Current Process ID ***
echo "The Current Process ID = $PID"
echo "File name extensions will contain this as identification"
#
# ******************************************
# *** Create the "work-in-progress" file ***
# ******************************************
if [ -f "$WIPFile" -o -d "$WIPFile" ] ; then
# WIP file already exists as an ordinary file or a directory.
# This is an error condition!!!
echo "$EPROMPT WIP file already exists as an ordinary file or a directory"
echo "  Aborting....."
exit $ERR_WIP_EXISTSelse
# the following code makes sure we are starting out with a ZERO file
rm "$WIPFile" 1> /dev/null 2>&1      # delete it
touch "$WIPFile"                     # create it   RES=$?
if [ "$RES" -ne 0 ] ; then
echo "$EPROMPT($RES) Creating the file: $WIPFile"
exit $ERR_WIP_CREATE
fi
fi
#
# ************************************
# *** Create the "Check PID File " ***
# ************************************
if [ -f "$CHKFile" -o -d "$CHKFile" ] ; then
# CHK file already exists as an ordinary file or a directory.
# This is an error condition!!!
echo "$EPROMPT CHK file already exists as an ordinary file or a directory"
echo "  Aborting....."
exit $ERR_CHK_EXISTS
else
# the following code makes sure we are starting out with a ZERO file
rm "$CHKFile" 1> /dev/null 2>&1      # delete it
touch "$CHKFile"                     # create it
RES=$?
if [ "$RES" -ne 0 ] ; then
echo "$EPROMPT($RES) Creating the file: $CHKFile"
exit $ERR_CHK_CREATE
fi
fi
#
# ********************
# *** Control Loop ***
# ********************
#
exec < $TFN     # redirect standard input to the task file name
#
while true
do
read p0 p1 p2 p3 p4 p5 p6 p7 p8 REM
RES=$?
#
# *****************************
# *** Check: Any More Lines ***
# *****************************
# 'read' always returns an exit status of '0' unless an END-OF-FILE is
# encountered.
#
if [ "$RES" -ne 0 ] ; then
echo "$PROMPT Done reading from Task File: $TFN"
break
fi
#
# *** Check: Comment Line ***
if [ "$p0" = "#"  -o "$p0" = "" ] ; then
# ********************
# *** Comment Line ***
# ********************
#
# echo "$PROMPT Comment Line:"
# echo "  $p0 $p1 $REM"
#
: # NULL command
else
# *****************
# *** Data Line ***
# *****************
# -<task file> Format:
#    <logical device> [0] [1] [2] [3] [4] [5] [6] [7]
#
# echo "Device: $p0; Disk Type: $p1; Remainder: $REM"
#
DEV="/dev/rdsk/$p0"
#
# ******************************
# *** Check the File Systems ***
# ******************************
NDSK=`expr $NDSK + 1`
EXT="$NDSK$PERIOD$PID"
#
# **************************************
# *** Merge the Specified Partitions ***
# **************************************
#
case "$p1" in

[0-7]) PART="s$p1"
SUM="$DEV$PART "
case "$p2" in
[0-7]) PART="s$p2"
SUM="$SUM $DEV$PART "
#
case "$p3" in
[0-7]) PART="s$p3"
SUM="$SUM $DEV$PART "
#
case "$p4" in
[0-7]) PART="s$p4"
SUM="$SUM $DEV$PART "
#
case "$p5" in
[0-7]) PART="s$p5"
SUM="$SUM $DEV$PART "
#
case "$p6" in
[0-7]) PART="s$p6"
SUM="$SUM $DEV$PART "
#
case "$p7" in
[0-7]) PART="s$p7"
SUM="$SUM $DEV$PART "
#
case "$p8" in
[0-7]) PART="s$p8"
SUM="$SUM $DEV$PART "
#
;;
*) ;;
#
esac
#
;;
*) ;;
#
esac
#
;;
*) ;;
#
esac
#
;;
*) ;;
#
esac
#
;;
*) ;;
#
esac
#
;;
#
*) ;;
#
esac

#
;;
#
*) ;;
esac
#
# *********************************************
# *** Create the "log" file for this device ***
# *********************************************
LF="$LOGFile$PERIOD$NDSK"
#
if [ -f "$LF" -o -d "$LF" ] ; then
# Log file already exists as an ordinary file or a directory.
# This is an error condition!!!
echo "$EPROMPT Log file already exists as an ordinary file or a directory"
echo "  File:  $LF"
echo "  Aborting....."
exit $ERR_LOGF_EXISTS
else
# the following code makes sure we are starting out with a ZERO file
rm "$LF" 1> /dev/null 2>&1      # delete it
#
MSG="Creating Log File: $LF"
echo "$PROMPT$MSG"
#
touch "$LF"                     # create it
RES=$?
if [ "$RES" -ne 0 ] ; then
echo "$EPROMPT($RES) Creating the file: $LF"
exit $ERR_LOGF_CREATE
fi
fi
#
echo "Device:  $DEV" > $LF
date >> $LF
#
# *******************************
# *** Check: Partition Exists ***
# *******************************
CMD="prtvtoc $SUM"
echo "Checking:  $SUM exists"
eval "$CMD" > /dev/null      # execute the command
RES2=$?
if [ "$RES2" -ne 0 ] ; then
# ****************************
# *** Partition is Missing ***
# ****************************
EMSG="$SUM is missing"
ERRLIST="$ERRLIST $EMSG ;"
echo "$EPROMPT$EMSG"
echo
echo "$EPROMPT$EMSG" >> $LF
echo >> $LF
continue
fi
#
# *********************************
# *** Check: Mounted Partitions ***
# *********************************
CMD="mount $PIPE grep $SUM"

echo "Checking:  $SUM has mounted partitions"
eval "$CMD" > /dev/null      # execute the command
RES2=$?
#
if [ "$RES2" -eq 0 ] ; then
# ***********************************
# *** Disk has mounted partitions ***
# ***********************************
EMSG="$SUM has mounted partitions"
ERRLIST="$ERRLIST $EMSG ;"
echo "$EPROMPT$EMSG"
echo
echo "$EPROMPT$EMSG" >> $LF
echo >> $LF
continue
fi
#
# ************************
# *** Partition Exists ***
# ************************
#
CMD="$FSCKCMD $SUM >> $LF &"
echo "Executing Command:"
echo "  $CMD"
echo "Executing Command:" >> $LF
echo "  $CMD" >> $LF
eval "$CMD" # execute the command in the background
RES1=$?
F_PID=$!       # get the background process ID
#
echo "$F_PID $p0" >> "$WIPFile"  # update the WIP file
#
if [ "$RES1" -ne 0 ] ; then
EMSG="Checking File Systems Using the Command:"
echo "$EPROMPT($RES1) $EMSG"
echo "  $CMD"
CkExit $RES1
echo "  Ignoring this disk ($p0)............."
#
# *** Update the 'fsck' error list ***
FERRLIST="$FERRLIST $DEV"
else
echo "$PROMPT Background Process ID $F_PID Started"
# *** Update the Control File ***
echo "$p0 $p1 $F_PID" >> $CTRLF
#
fi
#
;;
#
*) echo "Argument 1 not valid"
;;
esac
#
MSG="Device: $DEV has started"
echo "  $MSG"
#
# **************************************
# *** END: Processing Current Recond ***
# **************************************

#
fi
#
done    # END: WHILE
#
exec < /dev/tty         # redirect standard input
#
# *************
# *** Notes ***
# *************
# -Done reading the file with the devices.  Now monitor the processes doing the
#  checking.
#
# ********************
# *** Control Loop ***
# ********************
#
echo "> > > Waiting For ALL Processes to Complete < < <"
DoneF=`expr 0`  # Done Flag (=0, NO; <> 0, YES)
#
while true
do
#
# ***********************
# *** Check: WIP File ***
# ***********************
exec < $WIPFile      # redirect standard input
#
Tmp1=`expr 0`        # temp flag (=0, no process active; <> 0, YES)
#
while true
do
# *** Get A Line ***
# Format:
#   <PID>   <raw device>
#
read p0 p1 REM
RES=$?
# *****************************
# *** Check: Any More Lines ***
# *****************************
# 'read' always returns an exit status of '0' unless an END-OF-FILE is
# encountered.
if [ "$RES" -ne 0 ] ; then
# **********************************
# *** At the end of the WIP file ***
# **********************************
break
fi
#
# ***********************************
# *** Check: Process Still Active ***
# ***********************************
eval ps -ae $PIPE grep $p0 > $CHKFile
CkRes=$?
if [ -s "$CHKFile" ] ; then
Tmp1=`expr 1`  # indicate some process active
echo "$p0 still active on $p1"         # notify user
fi
#
done
#
exec < /dev/tty         # redirect standard input
#
# *********************************
# *** Check: Any Process Active ***
# *********************************
if [ "$Tmp1" -eq 0 ] ; then
echo "All recorded background processes have completed"
break
fi
#
# **********************************
# *** Wait Before Checking Again ***
# **********************************
sleep $SleepSec
#
echo "> > > Checking for Active Processes < < <"
#
done
#
# *********************************************
# *** Scan the Log Files for Error Messages ***
# *********************************************
# -This code will scan all file with "$LOGFile$PERIOD" in the file name.
# -If a partition can't be found, a "Can't Stat" message will be placed
#  in a log file.echo "Scanning for partitions that were not found; unable to check"
# echo "-log files will contain message:  Can\'t stat <raw partition>"
CMD="grep \"Can\'t stat\" $LOGFile$ASTER "
echo "Partitions NOT found if entries follow:"
eval "$CMD"      # execute the command
#
# Notes:
# ------
# -No checking is performed on this command.  Deemed non-critical.
#
# ***************************
# *** Display Error Lists ***
# ***************************
if [ ! "$ERRLIST" = "$NullList" ] ; then
echo
echo "Found Startup Problems With:"
echo "  $ERRLIST"
fi
if [ ! "$FERRLIST" = "$NullList" ] ; then
echo
echo "Found 'fsck' Problems With:"
echo "  $FERRLIST"
fi
#
# ******************************
# *** Remove Temporary Files ***
# ******************************
rm $CHKFile 1> /dev/null 2>&1
rm $WIPFile 1> /dev/null 2>&1
#
echo
MSG="Do You Want to Remove all Log Files"
echo "$PROMPT$MSG"
MSG="This will delete all files with 'log' in the file name"
echo "$PROMPT$MSG"
MSG="Proceed (Y/N) ?"
echo "$PROMPT$MSG"
#
read ans rem
if [ "$ans" = "y" -o "$ans" = "Y" -o "$ans" =
"yes" -o "$ans" = "Yes" -o "$ans" = "YES" ] ; then
# ****************************
# *** Remove All Log Files ***
# ****************************
#
MSG="Removing Log Files"
echo "$PROMPT$MSG"
CMD="rm *\.log\.* 1> /dev/null 2>&1"
eval "$CMD"
RES=$?
if [ "$RES" -ne 0 ] ; then
EMSG="Removing Log Files"
echo "$EPROMPT$EMSG"
echo "  Response: $RES"
exit $ERR_RM_LOGFS
fi
#
fi
#
# *****************************************
# *** Remove all Work-In-Progress Files ***
# *****************************************
#
MSG="Removing all Work-In-Progress Files"
echo "$PROMPT$MSG"
#
CMD="rm *\.wip\.* 1> /dev/null 2>&1"
eval "$CMD"
#
# ******************************
# *** Remove all Check Files ***
# ******************************
#
MSG="Removing all Check Files"
echo "$PROMPT$MSG"
#
CMD="rm *\.chk\.* 1> /dev/null 2>&1"
eval "$CMD"
#
# **************************************************
# *** Remove the Control File ONLY if successful ***
# **************************************************
#
MSG="Removing the Control File: $CTRLF"
echo "$PROMPT$MSG"
#
CMD="rm $CTRLF 1> /dev/null 2>&1"
eval "$CMD"
RES=$?
if [ "$RES" -ne 0 ] ; then
EMSG="Removing Control File"
echo "$EPROMPT$EMSG"
echo "  Response: $RES"
fi
#
exit 0
#
#
# ***********
# *** END ***
# ***********