#!/usr/skunk/bin/gawk -f #!/usr/bin/awk -f # @(#) fs.awk 1.3 94/01/27 # Reports average file sizes on filesystems, # determines optimum number of inodes for filesystem given average filesize, # and determines maximum useful size of a filesystem with that average file # size. # 91/03/11 john h. dubois iii (john@armory.com) # 91/03/16 added more info to display. # 91/04/08 increased max fs size field width # 91/04/18 changed name from filesizes to fs # 91/06/30 replaced incorrect continues with nexts # 92/05/01 converted to #!awk script # 92/08/01 Remove any directory component from fs name # 92/08/22 Use space used by inode table & superblock in calculations # 93/10/17 Use total inodes, not inodes used, in calculating non-file space # 93/11/02 Try to deal with NFS garbage # 94/01/27 Added n option # 94/03/09 Use gawk so - options can be given # expects df to report in 512 byte blocks, # and expects df -i -v output to be in this format: #Mount Dir Filesystem blocks used free % used iused ifree %iused #/ /dev/root 27438 18650 8788 68% 1140 2284 33% #/usr/spool/ /dev/news 103530 57276 46254 55% 11206 1722 87% #/usr /dev/usr 80000 66974 13026 84% 3584 6416 36% #/u /dev/u 50000 35224 14776 70% 1909 4331 31% BEGIN { Name = "fs" Usage = "Usage: " Name " [-hn] [device ...]" OptList = "hn" Opts(Name,Usage,OptList,0) if ("h" in Options) { print \ Name ": report average file sizes and other information for filesystems.\n" \ Usage "\n"\ "For each mounted filesystem, " Name " prints:\n" \ "its name, its size in blocks, blocks used, % of blocks used, blocks free, \n" \ "the maximum size of a filesystem containing files with the same average\n" \ "size that this one has (given a maximum of 65535 files per filesystem),\n" \ "number of inodes in its inode list, inodes used, % of inodes used, inodes\n" \ "free, the optimum number of inodes for a filesystem of this size given the\n" \ "average size of files on it, and the average file size.\n" \ "If a list of devices is given, they are reported on instead of using the\n" \ "list of mounted filesystems.\n"\ "All block reports refer to 1 kilobyte blocks.\n" \ "Options:\n" \ "-h: print this help.\n" \ "-n: Show NFS mounts too." exit(0) } Cmd = "df -i -v" while (ARGC > 1) Cmd = Cmd " " ARGV[--ARGC] Cmd | getline # ignore header # Don't print header if df doesn't produce anything if ((ret = (Cmd | getline)) != 1) exit(1) # printf format string for both header and data lines Format = "%-6s %6s %6s %4s %6s %7s %5s %5s %4s %5s %5s %8s\n" print "Filesys ---Filesystem Space (Kbytes)--- " \ "-----------Inodes----------- Avg Size" printf(Format,"Name","Total","Used","Used","Free","Max", \ "Total","Used","Used","Free","Opt","(bytes)") #nrroot 650000 500000 100% 150000 650000 65000 15000 100% 50000 65000 100000 while (ret == 1) { # If a list of devices is given to df, it leaves mount dir field blank. # Shift fields to compensate. if (NF == 8) { for (i = 8; i >= 1; i--) $(i + 1) = $i $1 = "" } PrintLine(Format,!("n" in Options)) ret = (Cmd | getline) } } function PrintLine(Format,NoNFS, MaxInodes) { MaxInodes = 65488 MountDir = $1 FsName = $2 # filesystem name sub("^/dev/","",FsName) DivisionSize = $3 / 2 # division size in KB BlocksUsed = $4 / 2 BlocksFree = $5 / 2 BlocksPercentUsed = $6 InodesUsed = $7 InodesFree = $8 TotalInodes = InodesUsed + InodesFree InodesPercentUsed = $9 # Space used by inode table and superblock # Actual size of superblock is different for different filesys types NonFileSpace = (TotalInodes / 16 + 2) # Amount of space actually used by files FileSpaceUsed = BlocksUsed - NonFileSpace # Amount of space available to files TotalFileSpace = DivisionSize - NonFileSpace if (InodesUsed > 0) { AvgFileSize = FileSpaceUsed / InodesUsed # max useful size of fs division MaxFsSize = int(AvgFileSize * MaxInodes + MaxInodes / 16 + 2) OptimumInodes = int(TotalFileSpace / AvgFileSize) AvgFileSize = int(AvgFileSize * 1024) } else MaxFsSize = OptimumInodes = AvgFileSize = "-" # NFS automount if (FsName ~ ":") { if (NoNFS) return FsName = MountDir sub("^.*/","",FsName) FsName = "*" FsName } NameLen = length(FsName) if (NameLen > 6) FsName = substr(FsName,1,5) ">" printf(Format,FsName,int(DivisionSize),int(BlocksUsed),BlocksPercentUsed, int(BlocksFree),MaxFsSize,TotalInodes,InodesUsed,InodesPercentUsed, InodesFree,OptimumInodes,AvgFileSize) } # @(#) ProcArgs 1.1 94/01/01 # 92/02/29 john h. dubois iii # 93/07/18 Added "#" arg type # 93/09/26 Don't count -h against MinArgs # 94/01/01 Stop scanning at first non-option arg. Added '>' option type. # Removed meaning of '+' or '-' by itself. # optlist is a string which contains all of the possible command line options. # If a character is followed by a colon, # it indicates that that option takes an argument. # If a character is followed by a pound sign (#), # it indicates that that option takes an integer argument. # Strings in argv[] which begin with "-" or "+" are taken to be # strings of options, except that a string which consists solely of "-" # or "+" is taken to be a non-option string; like other non-option strings, # it stops the scanning of argv and is left in argv[]. # If an option takes an argument, the argument may either immedately # follow it or be given separately. # If an option that does not take an argument is given, # an index with its name is created in options and its value is set to "1". # If an option that does take an argument is given, # an index with its name is created in options and its value # is set to the value of the argument given for it. # Options and their arguments are deleted from argv. # Note that this means that there may be gaps left in the indices of argv[]. # If compress is nonzero, argv[] is packed by moving its elements so that # they have contiguous integer indices starting with 0. # argv[0] is not examined. # An argument of "--" or "++" stops the scanning of argv[]. # The number of arguments left in argc is returned. # If an error occurs, the string OptErr is set to an error message and -1 is # returned. function ProcArgs(argc,argv,optlist,options,compress, ArgNum,ArgsLeft,Arg,ArgLen,ArgInd,Option,Pos) { # ArgNum is the index of the argument being processed. # ArgsLeft is the number of arguments left in argv. # Arg is the argument being processed. # ArgLen is the length of the argument being processed. # ArgInd is the position of the character in Arg being processed. # Option is the character in Arg being processed. # Pos is the position in optlist of the option being processed. ArgsLeft = argc for (ArgNum = 1; ArgNum < argc; ArgNum++) { if ((Arg = argv[ArgNum]) !~ /^[-+]./) break delete argv[ArgNum] ArgsLeft-- if ((Arg == "--") || (Arg == "++")) break ArgLen = length(Arg) for (ArgInd = 2; ArgInd <= ArgLen; ArgInd++) { Option = substr(Arg,ArgInd,1) Pos = index(optlist,Option) if (!Pos) { OptErr = "Invalid option: -" Option return -1 } # If option takes a value... if ((ArgType = substr(optlist,Pos + 1,1)) ~ "[:#>]") { if (ArgInd < ArgLen) # Value is included with option options[Option] = substr(Arg,ArgInd + 1) else { # Value is the next arg after option if (ArgNum < (argc - 1)) { options[Option] = argv[++ArgNum] delete argv[ArgNum] ArgsLeft-- } else { OptErr = "Option -" Option " requires an argument" return -1 } } if (ArgType == "#" && options[Option] !~ "^-?[0-9]+$") { OptErr = \ "Option -" Option " requires an integer argument" return -1 } else if (ArgType == ">" && ( options[Option] !~ "^[0-9]+$" || options[Option] ~ "^0+$")) { OptErr = \ "Option -" Option " requires a positive integer argument" return -1 } break # Used up this option } else options[Option] = 1 } } if (compress != 0) PackArr(argv,ArgsLeft) return ArgsLeft } # Packs Arr to indices starting with 0 # Num should be the number of elements in Arr function PackArr(Arr,Num, NewInd,OldInd) { NewInd = OldInd = 0 for (; Num; Num--) { while (!(OldInd in Arr)) OldInd++ if (NewInd != OldInd) { Arr[NewInd] = Arr[OldInd] delete Arr[OldInd] } OldInd++ NewInd++ } } # Opts: Process command line arguments. # Opts processes command line arguments using ProcArgs() # and checks for errors. If an error occurs, a message is printed # and the program is exited. # # Input variables: # Name is the name of the program, for error messages. # Usage is a usage message, for error messages. # OptList the option description string, as used by ProcArgs(). # MinArgs is the minimum number of non-option arguments that this # program should have, non including ARGV[0] and +h. # If the program does not require any non-option arguments, # MinArgs should be omitted or given as 0. # Global variables: # The command line arguments are taken from ARGV[]. # The arguments that are option specifiers and values are removed from # ARGV[], leaving only ARGV[0] and the non-option arguments. # The number of elements in ARGV[] should be in ARGC. # After processing, ARGC is set to the number of elements left in ARGV[]. # The option values are put in Options[]. # On error, Err is set to 1 so it can be checked for in an END block. # Return value: The number of elements left in ARGV is returned. function Opts(Name,Usage,OptList,MinArgs, ArgsLeft) { if (MinArgs == "") MinArgs = 0 ArgsLeft = ProcArgs(ARGC,ARGV,OptList,Options,1) if ((ArgsLeft + ("h" in Options)) < (MinArgs+1)) { if (ArgsLeft != -1) OptErr = "Not enough arguments" print Name ": " OptErr ". Use -h for help." print Usage Err = 1 exit 1 } return ArgsLeft }