mjy@sdti.sdti.com (Michael J. Young) (12/07/88)
Posting-number: Volume 5, Issue 68 Submitted-by: "Michael J. Young" <mjy@sdti.sdti.com> Archive-name: fsanalyze4.1/part01 This is a completely new version of fsanalyze, which I originally posted almost a year ago. Major changes were made to port it to BSD file systems, as well to fix a number of bugs that were reported to me. Unfortunately, it is also a fair bit larger than the old version. For those who don't remember the original program, fsanalyze is a tool that measures file system fragmentation along with various other useful file system statistics. Please send comments, bug reports, fixes, and ideas for enhancements to me. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 1 (of 3)." # Contents: Changes MANIFEST Makefile Mkfile.sun Mkfile.sys5 # Mkfile.uport Mkfile.xenix README fragm.c fsanalyze.c patchlevel.h # stats.c util.c # Wrapped by mjy@sdti on Wed Nov 30 15:54:13 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f Changes -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Changes\" else echo shar: Extracting \"Changes\" \(5025 characters\) sed "s/^X//" >Changes <<'END_OF_Changes' XRevision History: X X Version 2.0 was a major rewrite of fsanalyze that added the following new X features: X - The ability to analyze individual files X - Display of the 10 most fragmented files in a file system X - Enhanced error checking on the file system argument X X Version 2.01 contains a minor modification in which fsanalyze executes X /etc/fsstat to determine the health of the file system before analyzing X it. X X Version 2.02 contains a minor modification to print out a warning message X if the file system being analyzed is currently mounted. X X Version 2.03 contains a fix for a minor bug in which the size of the X volume data block size would be printed out incorrectly for large X file systems. X X Version 2.04 incorporates the library function l3tol to access inode X block numbers. This is the first version that was posted to the net X a few months back. X X Version 3.00 contains major revisions for porting to Xenix, System X V Release 3, and the BSD fast file system, as well as fixing many X bugs and improprieties. Specific changes include: X - Sparse files are now handled correctly. Thanks to John Limpert X (johnl@gronk.uucp) for this one! X - A bug in the way indirect blocks were factored into the X fragmentation analysis was corrected. X - Fragmentation has been re-defined as cylinder-to-cylinder seeks. X Suboptimum placement within a cylinder is handled separately as X "rotational delay". This resulted from the discovery by a number X of people (thanks esp. to Steve Paddock and Dave Olson X (olson@altos86.uucp)) that block interleaving wasn't handled X correctly. After doing some experimenting with the System V mkfs, X I came to the conclusion that its algorithm for optimal record X placement is rather crude. For example, it does not take number X of heads into account. So rather than enforce an algorithm that I X couldn't duplicate very well anyway, I split it out as a separate X statistic. This decision was confirmed when I ported fsanalyze to X BSD, since the fast file system also makes the distinction between X cylinder seeks and rotation delays. X - new command-line arguments have been added to override file system X block size, interleave factor, and number of sectors per cylinder. X Normally, these numbers are derived from information in the super- X block. However, not all file systems may store the information X in a way expected by fsanalyze. Use these flags to override. X Although all of the flags are supported for the BSD port, I doubt X if they are useful. X - Some function names and variables have been renamed to X ensure uniqueness within 7 characters. Thanks to John X Limpert for catching this. X - The IS_SPECIAL macro has been rewritten. Thanks to Larry X Cipriani and Dave Olson for catching the bugs here. X - A number of new macros have been defined to make porting to X BSD file systems easier. These are described in the new file X fsconfig.h. X - The relative cost of fragmentation is now reported as the average X distance of each seek (in number of cylinders). This is reported X as an average for the entire file system, as well as for each file. X - Some files must span more than one cylinder simply because they are X too large. Single-cylinder seeks due to size are ignored in the X fragmentation calculation. X - A makefile has been created to enhance portability. The X makefile contains instructions for configuration of fsanalyze. X X Release 3.01 contains a few simple changes to enhance portability to X XENIX/286, and adds the NUMOFFEND configuration parameter, which X determines how many of the "top offender" (most fragmented) files X are reported. X X Release 3.02 changes the rotation delay algorithm slightly to more closely X reflect the BSD placement algorigthm. I still don't trust the results, X since they are non-intuitive, and always too high for what I would expect X from BSD. The other major change is the addition of a "wasted space" X metric which reports unuseable space due to partial use of the last block X of each file. X X Release 3.03 reports the total number of blocks used for indirection (and X thus unavailable for data). I also made more changes to the rotation X delay algorithm, providing a formula for BSD Opt_interleave that makes X more sense than previous versions. The results still seem a bit too X high, but they're more reasonable than before. This version also X includes a complete code re-organization which makes it easier to pack X into shell archives, and some other general cleanup in preparation for X posting to Usenet. X X Release 3.04 contains minor changes to avoid namespace conflicts in the X FS_TYPE and OS_TYPE macros. NFS support is also disassociated with the X OS_TYPE. X X Release 4.1 contains no major changes from 3.04, but resulted from X placing the code under SCCS. END_OF_Changes if test 5025 -ne `wc -c <Changes`; then echo shar: \"Changes\" unpacked with wrong size! fi # end of overwriting check fi if test -f MANIFEST -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"MANIFEST\" else echo shar: Extracting \"MANIFEST\" \(1115 characters\) sed "s/^X//" >MANIFEST <<'END_OF_MANIFEST' X File Name Archive # Description X----------------------------------------------------------- X Changes 1 Revision History X Info 2 Useful information on interpreting X results X MANIFEST 1 This file... X Makefile 1 Guess. X Mkfile.sun 1 Makefile for Suns X Mkfile.sys5 1 Makefile for generic System V X Mkfile.uport 1 Makefile for Microport System V/AT X Mkfile.xenix 1 Makefile for XENIX/286 X README 1 Useful information X chkfile.c 3 File Scanner X fragm.c 1 Fragmentation heuristics X fsanalyze.8 2 Manual page X fsanalyze.c 1 main() X fsanalyze.h 2 Global declarations X fsconfig.h 3 System-dependent declarations X init.c 2 System initialization X patchlevel.h 1 Current patch level X report.c 2 Print report X stats.c 1 Statistics maintenance X util.c 1 Inode-related utilities END_OF_MANIFEST if test 1115 -ne `wc -c <MANIFEST`; then echo shar: \"MANIFEST\" unpacked with wrong size! fi # end of overwriting check fi if test -f Makefile -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Makefile\" else echo shar: Extracting \"Makefile\" \(2425 characters\) sed "s/^X//" >Makefile <<'END_OF_Makefile' X X## X## FSANALYZE makefile X## Version : 4.1 - 88/11/16 17:27:40 X X## One of the things FSANALYZE displays is a list of the most fragmented X## files. OFFEND determines how many of those files to report. X## The report is in double column format, so the number should be divisible X## by 2. Ideally, this number should be set so that the report fits on X## a single screen. For a 24-line display, the suggested number is 10, X## which is the default. XOFFEND = 10 X X## File System type - Use the first definition for derivatives of the old X## AT&T file system, including Version 7, System III, and System V X## releases 2 and 3, and XENIX. Use the second definition for derivatives X## of the BSD Fast File system without NFS. If NFS support is also included, X## use the third definition. XFS = FS_ATT X#FS = FS_BSD X#FS = FS_BSD_NFS X X## Operating system type - This definition is used for OS-dependencies within X## a given file system. Use OS_ATT or OS_BSD if none of the other definitions X## apply. X#OS = OS_ATT X#OS = OS_BSD XOS = OS_UPORT_286 # Microport System V/AT (286-based - use _ATT for /386) X#OS = OS_XENIX_286 # XENIX/286 (use _ATT for XENIX/386) X X## Uncomment the next line if you have the fsstat(1) command. Note that if X## you are installing fsanalyze on a Microport System V/AT, this command X## should be uncommented, since the is_ok macro as defined in fsconfig.h X## will not work. XFSSTAT = -DHAVE_FSSTAT X X## Where the executable should be placed... XDESTDIR = /etc/local X X## Where the man file should be placed... XMANDIR = /usr/man/man8 X XCONFIG_FLGS = -DFS_TYPE=$(FS) -DOS_TYPE=$(OS) -DNUMOFFEND=$(OFFEND) $(FSSTAT) X X## edit as appropriate... XCFLAGS = -O $(CONFIG_FLGS) XLDFLAGS = X XOBJS = fsanalyze.o chkfile.o fragm.o init.o report.o stats.o util.o XSRCS = fsanalyze.c chkfile.c fragm.c init.c report.c stats.c util.c X Xfsanalyze: $(OBJS) X $(CC) $(LDFLAGS) -o fsanalyze $(OBJS) X Xinstall: fsanalyze manual X mv fsanalyze $(DESTDIR) X chmod 755 $(DESTDIR)/fsanalyze X Xclean: X rm *.o fsanalyze X Xlint: $(SRCS) fsconfig.h fsanalyze.h X lint -D_FS_TYPE=$(FS) -D_OS_TYPE=$(OS) $(FSSTAT) -p $(SRCS) X Xmanual: fsanalyze.8 X cp fsanalyze.8 $(MANDIR) X chmod 444 $(MANDIR)/fsanalyze.8 X Xchkfile.o : fsconfig.h fsanalyze.h Xfragm.o : fsconfig.h fsanalyze.h Xfsanalyze.o : fsconfig.h fsanalyze.h Xinit.o : fsconfig.h fsanalyze.h patchlevel.h Xreport.o : fsconfig.h fsanalyze.h Xstats.o : fsconfig.h fsanalyze.h Xutil.o : fsconfig.h fsanalyze.h END_OF_Makefile if test 2425 -ne `wc -c <Makefile`; then echo shar: \"Makefile\" unpacked with wrong size! fi # end of overwriting check fi if test -f Mkfile.sun -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Mkfile.sun\" else echo shar: Extracting \"Mkfile.sun\" \(2474 characters\) sed "s/^X//" >Mkfile.sun <<'END_OF_Mkfile.sun' X## @(#)$Id: Mkfile.sun, V4.1 88/11/16 17:27:58 $ X## X## FSANALYZE makefile X## Version : 4.1 - 88/11/16 17:27:58 X X## One of the things FSANALYZE displays is a list of the most fragmented X## files. OFFEND determines how many of those files to report. X## The report is in double column format, so the number should be divisible X## by 2. Ideally, this number should be set so that the report fits on X## a single screen. For a 24-line display, the suggested number is 10, X## which is the default. XOFFEND = 10 X X## File System type - Use the first definition for derivatives of the old X## AT&T file system, including Version 7, System III, and System V X## releases 2 and 3, and XENIX. Use the second definition for derivatives X## of the BSD Fast File system without NFS. If NFS support is also included, X## use the third definition. X#FS = FS_ATT X#FS = FS_BSD XFS = FS_BSD_NFS X X## Operating system type - This definition is used for OS-dependencies within X## a given file system. Use OS_ATT or OS_BSD if none of the other definitions X## apply. X#OS = OS_ATT XOS = OS_BSD X#OS = OS_UPORT_286 # Microport System V/AT (286-based - use _ATT for /386) X#OS = OS_XENIX_286 # XENIX/286 (use _ATT for XENIX/386) X X## Uncomment the next line if you have the fsstat(1) command. Note that if X## you are installing fsanalyze on a Microport System V/AT, this command X## should be uncommented, since the is_ok macro as defined in fsconfig.h X## will not work. X#FSSTAT = -DHAVE_FSSTAT X X## Where the executable should be placed... XDESTDIR = /etc/local X X## Where the man file should be placed... XMANDIR = /usr/man/man8 X XCONFIG_FLGS = -DFS_TYPE=$(FS) -DOS_TYPE=$(OS) -DNUMOFFEND=$(OFFEND) $(FSSTAT) X X## edit as appropriate... XCFLAGS = -O $(CONFIG_FLGS) XLDFLAGS = X XOBJS = fsanalyze.o chkfile.o fragm.o init.o report.o stats.o util.o XSRCS = fsanalyze.c chkfile.c fragm.c init.c report.c stats.c util.c X Xfsanalyze: $(OBJS) X $(CC) $(LDFLAGS) -o fsanalyze $(OBJS) X Xinstall: fsanalyze manual X mv fsanalyze $(DESTDIR) X chmod 755 $(DESTDIR)/fsanalyze X Xclean: X rm *.o fsanalyze X Xlint: $(SRCS) fsconfig.h fsanalyze.h X lint -D_FS_TYPE=$(FS) -D_OS_TYPE=$(OS) $(FSSTAT) -p $(SRCS) X Xmanual: fsanalyze.8 X cp fsanalyze.8 $(MANDIR) X chmod 444 $(MANDIR)/fsanalyze.8 X Xchkfile.o : fsconfig.h fsanalyze.h Xfragm.o : fsconfig.h fsanalyze.h Xfsanalyze.o : fsconfig.h fsanalyze.h Xinit.o : fsconfig.h fsanalyze.h patchlevel.h Xreport.o : fsconfig.h fsanalyze.h Xstats.o : fsconfig.h fsanalyze.h Xutil.o : fsconfig.h fsanalyze.h END_OF_Mkfile.sun if test 2474 -ne `wc -c <Mkfile.sun`; then echo shar: \"Mkfile.sun\" unpacked with wrong size! fi # end of overwriting check fi if test -f Mkfile.sys5 -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Mkfile.sys5\" else echo shar: Extracting \"Mkfile.sys5\" \(2474 characters\) sed "s/^X//" >Mkfile.sys5 <<'END_OF_Mkfile.sys5' X## @(#)$Id: Mkfile.sys5, V4.1 88/11/16 17:28:35 $ X## X## FSANALYZE makefile X## Version : 4.1 - 88/11/16 17:28:35 X X## One of the things FSANALYZE displays is a list of the most fragmented X## files. OFFEND determines how many of those files to report. X## The report is in double column format, so the number should be divisible X## by 2. Ideally, this number should be set so that the report fits on X## a single screen. For a 24-line display, the suggested number is 10, X## which is the default. XOFFEND = 10 X X## File System type - Use the first definition for derivatives of the old X## AT&T file system, including Version 7, System III, and System V X## releases 2 and 3, and XENIX. Use the second definition for derivatives X## of the BSD Fast File system without NFS. If NFS support is also included, X## use the third definition. XFS = FS_ATT X#FS = FS_BSD X#FS = FS_BSD_NFS X X## Operating system type - This definition is used for OS-dependencies within X## a given file system. Use OS_ATT or OS_BSD if none of the other definitions X## apply. XOS = OS_ATT X#OS = OS_BSD X#OS = OS_UPORT_286 # Microport System V/AT (286-based - use _ATT for /386) X#OS = OS_XENIX_286 # XENIX/286 (use _ATT for XENIX/386) X X## Uncomment the next line if you have the fsstat(1) command. Note that if X## you are installing fsanalyze on a Microport System V/AT, this command X## should be uncommented, since the is_ok macro as defined in fsconfig.h X## will not work. X#FSSTAT = -DHAVE_FSSTAT X X## Where the executable should be placed... XDESTDIR = /etc/local X X## Where the man file should be placed... XMANDIR = /usr/man/man8 X XCONFIG_FLGS = -DFS_TYPE=$(FS) -DOS_TYPE=$(OS) -DNUMOFFEND=$(OFFEND) $(FSSTAT) X X## edit as appropriate... XCFLAGS = -O $(CONFIG_FLGS) XLDFLAGS = X XOBJS = fsanalyze.o chkfile.o fragm.o init.o report.o stats.o util.o XSRCS = fsanalyze.c chkfile.c fragm.c init.c report.c stats.c util.c X Xfsanalyze: $(OBJS) X $(CC) $(LDFLAGS) -o fsanalyze $(OBJS) X Xinstall: fsanalyze manual X mv fsanalyze $(DESTDIR) X chmod 755 $(DESTDIR)/fsanalyze X Xclean: X rm *.o fsanalyze X Xlint: $(SRCS) fsconfig.h fsanalyze.h X lint -D_FS_TYPE=$(FS) -D_OS_TYPE=$(OS) $(FSSTAT) -p $(SRCS) X Xmanual: fsanalyze.8 X cp fsanalyze.8 $(MANDIR) X chmod 444 $(MANDIR)/fsanalyze.8 X Xchkfile.o : fsconfig.h fsanalyze.h Xfragm.o : fsconfig.h fsanalyze.h Xfsanalyze.o : fsconfig.h fsanalyze.h Xinit.o : fsconfig.h fsanalyze.h patchlevel.h Xreport.o : fsconfig.h fsanalyze.h Xstats.o : fsconfig.h fsanalyze.h Xutil.o : fsconfig.h fsanalyze.h END_OF_Mkfile.sys5 if test 2474 -ne `wc -c <Mkfile.sys5`; then echo shar: \"Mkfile.sys5\" unpacked with wrong size! fi # end of overwriting check fi if test -f Mkfile.uport -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Mkfile.uport\" else echo shar: Extracting \"Mkfile.uport\" \(2475 characters\) sed "s/^X//" >Mkfile.uport <<'END_OF_Mkfile.uport' X## @(#)$Id: Mkfile.uport, V4.1 88/11/16 17:28:47 $ X## X## FSANALYZE makefile X## Version : 4.1 - 88/11/16 17:28:47 X X## One of the things FSANALYZE displays is a list of the most fragmented X## files. OFFEND determines how many of those files to report. X## The report is in double column format, so the number should be divisible X## by 2. Ideally, this number should be set so that the report fits on X## a single screen. For a 24-line display, the suggested number is 10, X## which is the default. XOFFEND = 10 X X## File System type - Use the first definition for derivatives of the old X## AT&T file system, including Version 7, System III, and System V X## releases 2 and 3, and XENIX. Use the second definition for derivatives X## of the BSD Fast File system without NFS. If NFS support is also included, X## use the third definition. XFS = FS_ATT X#FS = FS_BSD X#FS = FS_BSD_NFS X X## Operating system type - This definition is used for OS-dependencies within X## a given file system. Use OS_ATT or OS_BSD if none of the other definitions X## apply. X#OS = OS_ATT X#OS = OS_BSD XOS = OS_UPORT_286 # Microport System V/AT (286-based - use _ATT for /386) X#OS = OS_XENIX_286 # XENIX/286 (use _ATT for XENIX/386) X X## Uncomment the next line if you have the fsstat(1) command. Note that if X## you are installing fsanalyze on a Microport System V/AT, this command X## should be uncommented, since the is_ok macro as defined in fsconfig.h X## will not work. XFSSTAT = -DHAVE_FSSTAT X X## Where the executable should be placed... XDESTDIR = /etc/local X X## Where the man file should be placed... XMANDIR = /usr/man/man8 X XCONFIG_FLGS = -DFS_TYPE=$(FS) -DOS_TYPE=$(OS) -DNUMOFFEND=$(OFFEND) $(FSSTAT) X X## edit as appropriate... XCFLAGS = -O $(CONFIG_FLGS) XLDFLAGS = X XOBJS = fsanalyze.o chkfile.o fragm.o init.o report.o stats.o util.o XSRCS = fsanalyze.c chkfile.c fragm.c init.c report.c stats.c util.c X Xfsanalyze: $(OBJS) X $(CC) $(LDFLAGS) -o fsanalyze $(OBJS) X Xinstall: fsanalyze manual X mv fsanalyze $(DESTDIR) X chmod 755 $(DESTDIR)/fsanalyze X Xclean: X rm *.o fsanalyze X Xlint: $(SRCS) fsconfig.h fsanalyze.h X lint -D_FS_TYPE=$(FS) -D_OS_TYPE=$(OS) $(FSSTAT) -p $(SRCS) X Xmanual: fsanalyze.8 X cp fsanalyze.8 $(MANDIR) X chmod 444 $(MANDIR)/fsanalyze.8 X Xchkfile.o : fsconfig.h fsanalyze.h Xfragm.o : fsconfig.h fsanalyze.h Xfsanalyze.o : fsconfig.h fsanalyze.h Xinit.o : fsconfig.h fsanalyze.h patchlevel.h Xreport.o : fsconfig.h fsanalyze.h Xstats.o : fsconfig.h fsanalyze.h Xutil.o : fsconfig.h fsanalyze.h END_OF_Mkfile.uport if test 2475 -ne `wc -c <Mkfile.uport`; then echo shar: \"Mkfile.uport\" unpacked with wrong size! fi # end of overwriting check fi if test -f Mkfile.xenix -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Mkfile.xenix\" else echo shar: Extracting \"Mkfile.xenix\" \(2476 characters\) sed "s/^X//" >Mkfile.xenix <<'END_OF_Mkfile.xenix' X## @(#)$Id: Mkfile.xenix, V4.1 88/11/16 17:29:01 $ X## X## FSANALYZE makefile X## Version : 4.1 - 88/11/16 17:29:01 X X## One of the things FSANALYZE displays is a list of the most fragmented X## files. OFFEND determines how many of those files to report. X## The report is in double column format, so the number should be divisible X## by 2. Ideally, this number should be set so that the report fits on X## a single screen. For a 24-line display, the suggested number is 10, X## which is the default. XOFFEND = 10 X X## File System type - Use the first definition for derivatives of the old X## AT&T file system, including Version 7, System III, and System V X## releases 2 and 3, and XENIX. Use the second definition for derivatives X## of the BSD Fast File system without NFS. If NFS support is also included, X## use the third definition. XFS = FS_ATT X#FS = FS_BSD X#FS = FS_BSD_NFS X X## Operating system type - This definition is used for OS-dependencies within X## a given file system. Use OS_ATT or OS_BSD if none of the other definitions X## apply. X#OS = OS_ATT X#OS = OS_BSD X#OS = OS_UPORT_286 # Microport System V/AT (286-based - use _ATT for /386) XOS = OS_XENIX_286 # XENIX/286 (use _ATT for XENIX/386) X X## Uncomment the next line if you have the fsstat(1) command. Note that if X## you are installing fsanalyze on a Microport System V/AT, this command X## should be uncommented, since the is_ok macro as defined in fsconfig.h X## will not work. X#FSSTAT = -DHAVE_FSSTAT X X## Where the executable should be placed... XDESTDIR = /etc/local X X## Where the man file should be placed... XMANDIR = /usr/man/man8 X XCONFIG_FLGS = -DFS_TYPE=$(FS) -DOS_TYPE=$(OS) -DNUMOFFEND=$(OFFEND) $(FSSTAT) X X## edit as appropriate... XCFLAGS = -O $(CONFIG_FLGS) XLDFLAGS = X XOBJS = fsanalyze.o chkfile.o fragm.o init.o report.o stats.o util.o XSRCS = fsanalyze.c chkfile.c fragm.c init.c report.c stats.c util.c X Xfsanalyze: $(OBJS) X $(CC) $(LDFLAGS) -o fsanalyze $(OBJS) X Xinstall: fsanalyze manual X mv fsanalyze $(DESTDIR) X chmod 755 $(DESTDIR)/fsanalyze X Xclean: X rm *.o fsanalyze X Xlint: $(SRCS) fsconfig.h fsanalyze.h X lint -D_FS_TYPE=$(FS) -D_OS_TYPE=$(OS) $(FSSTAT) -p $(SRCS) X Xmanual: fsanalyze.8 X cp fsanalyze.8 $(MANDIR) X chmod 444 $(MANDIR)/fsanalyze.8 X Xchkfile.o : fsconfig.h fsanalyze.h Xfragm.o : fsconfig.h fsanalyze.h Xfsanalyze.o : fsconfig.h fsanalyze.h Xinit.o : fsconfig.h fsanalyze.h patchlevel.h Xreport.o : fsconfig.h fsanalyze.h Xstats.o : fsconfig.h fsanalyze.h Xutil.o : fsconfig.h fsanalyze.h END_OF_Mkfile.xenix if test 2476 -ne `wc -c <Mkfile.xenix`; then echo shar: \"Mkfile.xenix\" unpacked with wrong size! fi # end of overwriting check fi if test -f README -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"README\" else echo shar: Extracting \"README\" \(6616 characters\) sed "s/^X//" >README <<'END_OF_README' XFSANALYZE - File System Analyzer tool XVersion : 4.1.1.2 - 88/11/30 15:53:38 X XAuthor : Michael J. Young XUSmail : Software Development Technologies, Inc. X 375 Dutton Rd X Sudbury MA 01776 XUUCP : harvard!sdti!mjy XInternet : mjy@sdti.SDTI.COM X X ========================================================================= X Note : This program has been placed in the public domain to permit X unrestricted distribution and use. I have placed no copyright on it, but X I request that you keep me informed about any enhancements and bug fixes X you make so I can keep an up-to-date copy for further distribution. X ========================================================================= X X This is a completely new version of fsanalyze which contains a number of X bug fixes, new features, and enhanced portability. This version of X fsanalyze has been ported to the BSD fast file system, and run X successfully on a Sun. It has also run successfully under Ultrix, X but some changes may be needed in the #include directives in X the file "fsanalyze.h". X X For a complete revision history, see the file called "Changes". Other X useful information may be found in the file called "Info". X XIntroduction: X Fsanalyze is a simple tool that estimates file system fragmentation. It X accomplishes this by scanning the data blocks for each i-node in the X file system, looking for block numbers that are out of sequence. In X effect, it is counting the number of disk seeks required to read the X entire file in sequence. Fragmentation is then computed as the ratio X of actual "seeks" to the potential number of "seeks" if the file were X completely fragmented. X X Fsanalyze also provides a number of other useful statistics regarding the X file system usage, including the number (and identity) of files that are X very large, sparse files, and excessively large directories (i.e., X directory files that require data block indirection, making filename X searches very inefficient). X X After the general file system statistics are displayed, fsanalyze lists X the 10 most fragmented i-nodes in the file system. The 10 most X fragmented files are listed in decreasing order of fragmentation based on X the absolute number of fragments. For example, a 100-block file that X contains 40 individual fragments is 39.39% fragmented (39 seeks / 99 X potential seeks), but is listed before a 2-block file that contains 2 X fragments (100% fragmented). Thus, larger fragmented files (which have a X greater effect on file system performance) are listed before small files. X X In my estimation fsanalyze is completely safe, since it never writes to X the file system that it is analyzing and uses only the standard I/O X library to do its work. It should be possible to run fsanalyze on a X write-protected file system, if you're worried. If anything should go X wrong, the worst you will see is fseek() errors. Be that as it may, X however, there is no express or implied warrantee as to safety or X accuracy of the results. Use at your own risk. X XInstallation: X X For most systems, installing fsanalyze should consist simply of editing X the Makefile and running make. The Makefile is self-documenting (yeah, X I know, I know!). For convenience, I've included a number of different X Makefiles that are configured for various systems. Ultrix users should X be able to use the Sun version with no changes. X X Note that for Microport System V/AT systems, HAVE_FSSTAT should be X defined, since the is_ok(fs) macro defined in fsanalyze.h will not work. X X Where fsanalyze is installed doesn't really matter, but I would recommend X placing it somewhere in the root filesystem, which is always mounted. I X typically run fsanalyze during my backup procedure, while my other X filesystems are unmounted. X X Fsanalyze is not a setuid program, so the user must have read access to X the file system to be analyzed. I run it as root for this reason, but X if you're paranoid, it would be better just run it in the same group X as the the file systems (sys on my system). X XUsage: X fsanalyze [-flags] special [file [...]] X X If the optional file arguments are missing, the entire file system X is analyzed. If present, the specified files are analyzed and reported X individually. X X [flags] include the following: X b# assume '#' bytes per logical block -- by default, this value X is calculated automatically. Supported, but not useful, for X BSD file systems. X c# assume '#' sectors per disk cylinder -- by default, X this value is determined by information in the superblock. X d display i-node numbers as they are examined. X e report file size inconsistencies - the inode numbers are reported X for files where the file size and number of data blocks are X inconsistent. X g# assume an inter-block gap of '#' sectors -- by X default this information is taken from the superblock. Not X useful, for BSD file systems. X i report double and triple indirection - the inode numbers are X reported for files that contain double and/or triple indirection. X o overrides error checking on file system. Use this flag if the X file system you are analyzing is damaged. Note that fsanalyze X may give erroneous results if used on a damaged file system, but X the file system itself will not be modified. X v Display current version number and patch level. X X Example: X fsanalyze /dev/dsk/0s2 /* analyzes an entire file system */ X fsanalyze /dev/dsk/0s2 * /* analyzes all files in the current X * directory of the file system */ X X Since fsanalyze uses the superblock info ON THE DISK, more accurate X results will be returned fsanalyze is run on an unmounted, or read-only X mounted file system. X X Since fsanalyze does its work the old fashioned way (brute-force), it X must scan through the file system inode by inode. It therefore takes X a while to finish. Be patient. X XBugs: X Please report any bugs (and possible fixes) to me, so I can keep my X source up-to-date. I'm sure there are plenty of bugs, especially in the X BSD-specific stuff. Since I don't have access to anything but my little X Microport System V/AT system, it's hard for me to find portability bugs. X X Known Bugs include: X 1. I don't trust the rotation delay statistics, especially for X BSD file systems. The numbers seem to be much too high to be X believable. END_OF_README if test 6616 -ne `wc -c <README`; then echo shar: \"README\" unpacked with wrong size! fi # end of overwriting check fi if test -f fragm.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"fragm.c\" else echo shar: Extracting \"fragm.c\" \(4443 characters\) sed "s/^X//" >fragm.c <<'END_OF_fragm.c' Xstatic char sccsid[] = "@(#)$Id: fragm.c, V4.1 88/11/16 17:29:42 $"; X X/* X * fragm.c - fragmentation analysis X * Version : 4.1 - 88/11/16 17:29:42 X * X * Author : Michael J. Young X * USmail : Software Development Technologies, Inc. X * 375 Dutton Rd X * Sudbury MA 01776 X * UUCP : harvard!sdti!mjy X * Internet : mjy@sdti.SDTI.COM X * X * ========================================================================= X * Note : This program has been placed in the public domain to permit X * unrestricted distribution and use. I have placed no copyright on it, but X * I request that you keep me informed about any enhancements and bug fixes X * you make so I can keep an up-to-date copy for further distribution. X * X * This program is being provided "as is", with no warrantee as to safety or X * accuracy of results. Use at your own risk. X * ========================================================================= X */ X X/* X * Modification History: X * X * Thu Jul 28 15:57:32 EDT 1988 - M. Young (mjy@sdti.SDTI.COM), X * Extracted from fsanalyze.c X * X * Mon Aug 08 11:27:39 EDT 1988 - M. Young (mjy@sdti.SDTI.COM), X * Revised OS_TYPE and FS_TYPE macros to avoid name-space conflicts X * X * Wed Nov 16 11:31:32 EST 1988 - M. Young (mjy@sdti.SDTI.COM), X * Placed under SCCS X */ X X/* X * Include files X */ X#include "fsconfig.h" X#include "fsanalyze.h" X X/* X * must_seek : returns true if the two data blocks reside on different X * disk cylinders. X */ Xboolean must_seek (new_block, old_block) Xdaddr_t new_block; /* next data block */ Xdaddr_t old_block; /* previous data block */ X{ X daddr_t old_cyl; /* base block of current cylinder */ X daddr_t new_cyl; /* base block of new cylinder */ X X old_cyl = cylinder (fil_sys, old_block); X new_cyl = cylinder (fil_sys, new_block); X X return (old_cyl != new_cyl); X } X X/* X * rotate_delay : returns true if the new data block is within the same X * cylinder, but is not at the optimum position within the cylinder X */ Xboolean rot_delay (new_block, old_block) Xdaddr_t new_block; /* next data block */ Xdaddr_t old_block; /* previous data block */ X{ X daddr_t old_off; /* cylinder offset of current block */ X daddr_t new_off; /* cylinder offset of next block */ X X old_off = cyl_pos (fil_sys, old_block); X new_off = cyl_pos (fil_sys, new_block); X X return ((new_off != old_off + interleave) && X (new_off != (old_off + interleave) % cyl_size) && X (new_block != old_block + 1)); X } X X/* X * seek_dist : returns the number of cylinders that must be traversed X * to get from blk2 to blk1. X */ Xlong seek_dist (blk1, blk2) Xdaddr_t blk1; /* new block */ Xdaddr_t blk2; /* previous block */ X{ X daddr_t cyl1; /* base block of current cylinder */ X daddr_t cyl2; /* base block of new cylinder */ X X cyl1 = cylinder (fil_sys, blk1); X cyl2 = cylinder (fil_sys, blk2); X X return diff (cyl1, cyl2); X } X X/* X * minimum_seeks : returns the number of cylinders that the file spans just X * by virtue of its size. Any single-cylinder seeks due to the sheer size X * of the file will be ignored in the fragmentation calculation. X */ Xlong minimum_seeks (file_size) Xoff_t file_size; /* size of file from inode entry */ X{ X off_t bytes_per_cyl; X X bytes_per_cyl = (off_t)cyl_size * DEV_BSIZE; X return (file_size / bytes_per_cyl); X } X X/* X * test_fragmentation : determines whether or not the two specified blocks X * indicate that fragmentation has occurred. Disk seeks that are required X * due to the sheer size of the file are ignored in the calculation. If X * no disk seeks are required, a heuristic is used to determine if the X * data blocks are optimally placed within the cylinder. X */ Xvoid test_fragmentation (new_pos, old_pos, data) Xdaddr_t new_pos; /* new block number */ Xdaddr_t old_pos; /* original block */ Xstruct file_data *data; /* file statistics data structure */ X{ X data->potential_seeks++; X if (must_seek (new_pos, old_pos)){ X if (data->min_cost && seek_dist (new_pos, old_pos) == 1){ X data->min_cost--; X } X else { X data->cost += seek_dist (new_pos, old_pos); X data->seeks++; X } X } X else if (rot_delay (new_pos, old_pos)){ X data->rotates++; X } X } X END_OF_fragm.c if test 4443 -ne `wc -c <fragm.c`; then echo shar: \"fragm.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f fsanalyze.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"fsanalyze.c\" else echo shar: Extracting \"fsanalyze.c\" \(6212 characters\) sed "s/^X//" >fsanalyze.c <<'END_OF_fsanalyze.c' Xstatic char sccsid[] = "@(#)$Id: fsanalyze.c, V4.1 88/11/16 17:30:08 $"; X X/* X * fsanalyze.c - file system analyzer X * Version : 4.1 - 88/11/16 17:30:08 X * X * Author : Michael J. Young X * USmail : Software Development Technologies, Inc. X * 375 Dutton Rd X * Sudbury MA 01776 X * UUCP : harvard!sdti!mjy X * Internet : mjy@sdti.SDTI.COM X * X * ========================================================================= X * Note : This program has been placed in the public domain to permit X * unrestricted distribution and use. I have placed no copyright on it, but X * I request that you keep me informed about any enhancements and bug fixes X * you make so I can keep an up-to-date copy for further distribution. X * X * This program is being provided "as is", with no warrantee as to safety or X * accuracy of results. Use at your own risk. X * ========================================================================= X */ X X/* X * Modification History: X * X * Date Author Description X * ----------- -------- ----------------------------------------------- X * 28 Jul 1987 MJY Originated X * 5 Oct 1987 MJY Capability to analyze individual files, X * Added error checking to file system argument, X * Added -o flag X * Prints out volume and file system name in summary X * 12 Oct 1987 MJY Use /etc/fsstat to do file system validity X * checking X * 9 Nov 1987 MJY print out warning if file system is mounted X * 12 Nov 1987 MJY Volume size statistics now long instead of int X * 7 Jan 1988 MJY Modified blk_no() to use l3tol() X * X * Wed Mar 9 17:51:38 EST 1988 - M. Young (mjy@sdti.SDTI.COM), X * Rewrite for portability between various versions of System V, esp. X * SCO XENIX and 5.3 systems. First (incomplete) attempt at porting X * to BSD 4.3. See README for details. X * X * Thu Apr 7 10:03:21 EDT 1988 - M. Young (mjy@sdti.SDTI.COM), X * Seeks for files that span cylinders due to their sheer size are X * ignored. Average seek distance is now reported. X * X * Wed Apr 13 17:33:03 EDT 1988 - M. Young (mjy@sdti.SDTI.COM), X * Completed port to BSD. Fixed bug in inode numbering for BSD. X * Symbolic links now handled correctly for individual files. X * X * Wed Jun 15 14:08:30 EDT 1988 - M. Young (mjy@sdti.SDTI.COM), X * Number of top offenders is now a configurable parameter via the X * NUMOFFEND macro in fsconfig.h. X * X * Fri Jun 24 16:22:10 EDT 1988 - M. Young (mjy@sdti.SDTI.COM), X * Make top offender size report consistent with anal_file reports. X * X * Tue Jul 26 15:24:30 EDT 1988 - M. Young (mjy@sdti.SDTI.COM), X * Added wasted space metric X * Modified BSD rotation delay algorithm X * X * Thu Jul 28 16:15:22 EDT 1988 - M. Young (mjy@sdti.SDTI.COM), X * Opt_interleave() formula now makes sense X * Re-organized code and general cleanup in preparation for posting. X * X * Mon Aug 08 11:27:39 EDT 1988 - M. Young (mjy@sdti.SDTI.COM), X * Revised OS_TYPE and FS_TYPE macros to avoid name-space conflicts X * X * Wed Nov 16 11:31:32 EST 1988 - M. Young (mjy@sdti.SDTI.COM), X * Placed under SCCS X */ X X/* X * Include files X */ X#include "fsconfig.h" X#include "fsanalyze.h" X X/*************************************************************************** X * Global Variables * X ***************************************************************************/ X X/* X * interface to system error messages X */ Xextern char *sys_errlist[]; Xextern int sys_nerr; X X/* X * error : performs a function similar to perror(3), but supports variable X * argument lists. Prints out a formatted error string to stderr, followed if X * possible by an appropriate system error message. Control is then X * returned to the system with an error status. This function does not X * return. X */ X/* VARARGS0 */ Xvoid error (va_alist) Xva_dcl /* varargs */ X{ X int err; /* 1st arg - error number */ X char *str; /* 2nd arg - error format string */ X va_list args; X va_start(args); X err = va_arg (args, int); X str = va_arg (args, char *); X vfprintf (stderr, str, args); X if (err <= sys_nerr && err > 0) X fprintf (stderr, "%s\n", sys_errlist[err]); X else X fprintf (stderr, "unknown error : %d\n", err); X va_end(args); X X /* X * print out partial report, if possible X */ X if (fil_sys != NULL)print_report (); X exit(1); /* exit with error status */ X } X Xmain (argc, argv) Xint argc; Xchar *argv[]; X{ X int next_param; X extern int stat (); X struct stat f_stat; X X /* X * perform various initialization functions X */ X next_param = init (argc, argv); X X if (next_param == argc){ X /* X * no individual files to check, scan entire file system X */ X printf ("Analyzing file system %s...\n", special); X X /* X * scan through all i-nodes in the file system X */ X scan(); X X /* X * print out statistics summary X */ X print_report(); X } X else { X /* X * scan individual files instead of entire file system X */ X printf (" \t Seek Wasted\n"); X printf (" Name \ti-node Fragments Size %% Dist Space\n"); X for (; next_param < argc; next_param++){ X if (stat (argv[next_param], &f_stat) != 0){ X error (errno, "error opening \"%s\"\n", X argv[next_param]); X /* NOTREACHED */ X } X else { X X /* X * make sure the inode belongs to the correct device X * (for BSD systems with symbolic links) X */ X if ((f_stat.st_dev == fs_device) && X !IS_SPECIAL (f_stat.st_mode)){ X anal_file (f_stat.st_ino, argv[next_param]); X } X } X } X } X return (0); X } END_OF_fsanalyze.c if test 6212 -ne `wc -c <fsanalyze.c`; then echo shar: \"fsanalyze.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f patchlevel.h -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"patchlevel.h\" else echo shar: Extracting \"patchlevel.h\" \(950 characters\) sed "s/^X//" >patchlevel.h <<'END_OF_patchlevel.h' X/* @(#)$Id: patchlevel.h, V4.1 88/11/16 17:55:39 $ */ X X/* X * patchlevel.h - current patch level X * Version : 4.1 - 88/11/16 17:55:39 X * X * Author : Michael J. Young X * USmail : Software Development Technologies, Inc. X * 375 Dutton Rd X * Sudbury MA 01776 X * UUCP : harvard!sdti!mjy X * Internet : mjy@sdti.SDTI.COM X * X * ========================================================================= X * Note : This program has been placed in the public domain to permit X * unrestricted distribution and use. I have placed no copyright on it, but X * I request that you keep me informed about any enhancements and bug fixes X * you make so I can keep an up-to-date copy for further distribution. X * X * This program is being provided "as is", with no warrantee as to safety or X * accuracy of results. Use at your own risk. X * ========================================================================= X */ X X#define patch_level 0 X END_OF_patchlevel.h if test 950 -ne `wc -c <patchlevel.h`; then echo shar: \"patchlevel.h\" unpacked with wrong size! fi # end of overwriting check fi if test -f stats.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"stats.c\" else echo shar: Extracting \"stats.c\" \(5581 characters\) sed "s/^X//" >stats.c <<'END_OF_stats.c' Xstatic char sccsid[] = "@(#)$Id: stats.c, V4.1 88/11/16 17:31:26 $"; X X/* X * stats.c - file system statistics X * Version : 4.1 - 88/11/16 17:31:26 X * X * Author : Michael J. Young X * USmail : Software Development Technologies, Inc. X * 375 Dutton Rd X * Sudbury MA 01776 X * UUCP : harvard!sdti!mjy X * Internet : mjy@sdti.SDTI.COM X * X * ========================================================================= X * Note : This program has been placed in the public domain to permit X * unrestricted distribution and use. I have placed no copyright on it, but X * I request that you keep me informed about any enhancements and bug fixes X * you make so I can keep an up-to-date copy for further distribution. X * X * This program is being provided "as is", with no warrantee as to safety or X * accuracy of results. Use at your own risk. X * ========================================================================= X */ X X/* X * Modification History: X * X * Thu Jul 28 16:02:51 EDT 1988 - M. Young (mjy@sdti.SDTI.COM), X * Extracted from fsanalyze.c X * X * Mon Aug 08 11:27:39 EDT 1988 - M. Young (mjy@sdti.SDTI.COM), X * Revised OS_TYPE and FS_TYPE macros to avoid name-space conflicts X * X * Wed Nov 16 11:31:32 EST 1988 - M. Young (mjy@sdti.SDTI.COM), X * Placed under SCCS X */ X X#include "fsconfig.h" X#include "fsanalyze.h" X X/* X * calculated global statistics X */ Xlong blocks = 0; /* running block count */ Xlong free_inodes = 0; /* number of unused i-nodes */ Xlong potential_seeks = 0; /* potential number of disk seeks X * during sequential access of a X * file */ Xlong seeks = 0; /* actual number of disk seeks X * required during sequential access X * of a file */ Xlong total_seek_distance = 0; /* actual distance of disk seeks X * required during sequential access X * of a file */ Xlong rotates = 0; /* number of disk rotation delays */ Xlong indirects = 0; /* number of files w/ more than X * 10 data blocks */ Xlong double_indirects = 0; /* number of files w/ more than X /* one level of indirection */ Xlong triple_indirects = 0; /* number of files w/ more than X * two levels of indirection */ Xlong ind_blks = 0; /* number of blocks used for X * indirection */ Xint big_directories = 0; /* number of directories with X * indirection */ Xint num_directories = 0; /* number of directories */ Xint num_specials = 0; /* number of special files */ Xint linked_files = 0; /* number of multiply-linked files */ Xint sparse_files = 0; /* number of sparse files */ Xint size_errors = 0; /* number of file size discrepancies */ Xlong unuseable = 0; /* unuseable bytes due to external X * fragmentation */ X Xstruct file_data file_log[NUMOFFEND] = {0}; /* worst offenders */ X X/* X * init_stats : initializes per-file statistics structure X */ Xvoid init_stats (data, inode, file_size) Xstruct file_data *data; /* file stats to init */ Xint inode; /* i-node number */ Xlong file_size; /* file size */ X{ X data->inode = inode; X data->total_blocks = data->data_blocks = 0; X data->potential_seeks = data->seeks = data->rotates = 0; X data->fragm = 0.0; X data->sparse = 0; X data->cost = 0; X data->min_cost = minimum_seeks (file_size); X data->rel_cost = 0.0; X data->wasted = 0; X } X X/* X * log_stats : updates global statistics based on the current file statistics. X * The current file is then checked to see if it qualifies as one of the X * worst offenders (i.e., most fragmented) encountered thus far. The worst X * offenders are determined based on their absolute number of disk seeks X * required to read the entire file. Such an absolute test (viz a viz a X * relative percentage test) ensures that very small, but fragmented, files X * will not clutter the output. X */ Xvoid log_stats (data) Xstruct file_data *data; /* file statistics to be X * logged */ X{ X int i, j; /* loop counters */ X X X /* X * update global statistics X */ X blocks += data->total_blocks; X ind_blks += data->total_blocks - data->data_blocks; X potential_seeks += data->potential_seeks; X seeks += data->seeks; X total_seek_distance += data->cost; X rotates += data->rotates; X data->fragm = data->potential_seeks ? (float)data->seeks/(float)data->potential_seeks : 0.0; X data->rel_cost = (data->seeks ? (float)data->cost/(float)data->seeks : 0.0); X unuseable += data->wasted; X X /* X * update worst offender array X */ X for (i = 0; i < NUMOFFEND; i++){ X if (data->seeks > file_log[i].seeks){ X for (j = NUMOFFEND-1; j > i; j--){ X file_log[j] = file_log[j-1]; X } X file_log[i] = *data; X break; X } X } X } X END_OF_stats.c if test 5581 -ne `wc -c <stats.c`; then echo shar: \"stats.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f util.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"util.c\" else echo shar: Extracting \"util.c\" \(2687 characters\) sed "s/^X//" >util.c <<'END_OF_util.c' Xstatic char sccsid[] = "@(#)$Id: util.c, V4.1 88/11/16 17:31:35 $"; X X/* X * util.c - inode utilities X * Version : 4.1 - 88/11/16 17:31:35 X * X * Author : Michael J. Young X * USmail : Software Development Technologies, Inc. X * 375 Dutton Rd X * Sudbury MA 01776 X * UUCP : harvard!sdti!mjy X * Internet : mjy@sdti.SDTI.COM X * X * ========================================================================= X * Note : This program has been placed in the public domain to permit X * unrestricted distribution and use. I have placed no copyright on it, but X * I request that you keep me informed about any enhancements and bug fixes X * you make so I can keep an up-to-date copy for further distribution. X * X * This program is being provided "as is", with no warrantee as to safety or X * accuracy of results. Use at your own risk. X * ========================================================================= X */ X X/* X * Modification History: X * X * Thu Jul 28 15:55:40 EDT 1988 - M. Young (mjy@sdti.SDTI.COM), X * Extracted from fsanalyze.c X * X * Mon Aug 08 11:27:39 EDT 1988 - M. Young (mjy@sdti.SDTI.COM), X * Revised OS_TYPE and FS_TYPE macros to avoid name-space conflicts X * X * Wed Nov 16 11:31:32 EST 1988 - M. Young (mjy@sdti.SDTI.COM), X * Placed under SCCS X */ X X#include "fsconfig.h" X#include "fsanalyze.h" X X/* X * blk_no : given a pointer to an inode block number, returns a (daddr_t) X * block number. Used to provide portable access to the direct data blocks X * of an i-node. X */ Xdaddr_t blk_no (off) Xunsigned char *off; /* 3- or 4-byte offset */ X{ X daddr_t temp = 0; X X#if FS_TYPE == FS_ATT X extern void l3tol(); X X l3tol (&temp, off, 1); X#endif X X#if FS_TYPE == FS_BSD X temp = *((daddr_t *)off); X#endif X X return temp; X } X X/* X * get_inodes : given an initial i-node number, reads a block of i-nodes X * into an i-node array. X */ Xvoid get_inodes (in, inp, num) Xint in; /* inode number */ Xint num; /* # inodes to get */ Xstruct dinode *inp; /* buffer to hold info */ X{ X daddr_t position; /* computed position of the X * first requested i-node */ X X position = (daddr_t) inode_block(fil_sys, in) * block_size + X (daddr_t) inode_offset(fil_sys, in) * sizeof(struct dinode); X if (fseek (fsys, position, 0)){ X error (errno, "\nerror seeking inode %d, pos = %ld\n", in, position); X /* NOTREACHED */ X } X else { X if (fread (inp, sizeof (struct dinode), num, fsys) != num){ X error (errno, "\nerror reading inode %d\n", in); X /* NOTREACHED */ X } X } X } X END_OF_util.c if test 2687 -ne `wc -c <util.c`; then echo shar: \"util.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of archive 1 \(of 3\). cp /dev/null ark1isdone MISSING="" for I in 1 2 3 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 3 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Mike Young Software Development Technologies, Inc., Sudbury MA Tel: +1 508 443 5779 Internet: mjy@sdti.sdti.com UUCP: {harvard,mit-eddie}!sdti!mjy