11.2. Command-Line InterfaceIn this section, we explain tools with which you access kstat information with shell scripts. Included are a few examples to introduce the kstat(1m) program and the Perl language module it uses to extract kernel statistics. The Solaris 8 OS introduced a new method to access kstat information from the command line or in custom-written scripts. You can use the command-line tool /usr/ bin/kstat interactively to print all or selected kstat information from a system. This program is written in the Perl language, and you can use the Perl XS extension module to write your own custom Perl programs. Both facilities are documented in the pages of the online manual. 11.2.1. The kstat CommandYou can invoke the kstat command on the command line or within shell scripts to selectively extract kernel statistics. Like many other Solaris OS commands, kstat takes optional interval and count arguments for repetitive, periodic output. Its command options are quite flexible. The first form follows standard UNIX command-line syntax, and the second form provides a way to pass some of the arguments as colon-separated fields. Both forms offer the same functionality. Each of the module, instance, name, or statistic specifiers may be a shell glob pattern or a Perl regular expression enclosed by "/" characters. You can use both specifier types within a single operand. Leaving a specifier empty is equivalent to using the "*" glob pattern for that specifier. Running kstat with no arguments will print out nearly all kstat entries from the running kernel (most, but not all kstats of KSTAT_TYPE_RAW are decoded). The tests specified by the options are logically ANDed, and all matching kstats are selected. The argument for the -c, -i, -m, -n, and -s options can be specified as a shell glob pattern, or a Perl regular expression enclosed in "/" characters. If you pass a regular expression containing shell metacharacters to the command, you must protect it from the shell by enclosing it with the appropriate quotation marks. For example, to show all kstats that have a statistics name beginning with intr in the module name cpu_stat, you could use the following script: $ kstat -p -m cpu_stat -s 'intr*' cpu_stat:0:cpu_stat0:intr 878951000 cpu_stat:0:cpu_stat0:intrblk 21604 cpu_stat:0:cpu_stat0:intrthread 668353070 cpu_stat:1:cpu_stat1:intr 211041358 cpu_stat:1:cpu_stat1:intrblk 280 cpu_stat:1:cpu_stat1:intrthread 209879640 The -p option used in the preceding example displays output in a parsable format. If you do not specify this option, kstat produces output in a human-readable, tabular format. In the following example, we leave out the -p flag and use the module:instance:name:statistic argument form and a Perl regular expression. $ $ kstat cpu_stat:::/^intr/ module: cpu_stat instance: 0 name: cpu_stat0 class: misc intr 879131909 intrblk 21608 intrthread 668490486 module: cpu_stat instance: 1 name: cpu_stat1 class: misc intr 211084960 intrblk 280 intrthread 209923001 Sometimes you may just want to test for the existence of a kstat entry. You can use the -q flag, which returns the appropriate exit status for matches against given criteria. The exit codes are as follows:
Suppose that you have a Bourne shell script gathering network statistics, and you want to see if the NFS server is configured. You might create a script such as the one in the following example. #!/bin/sh # ... do some stuff # Check for NFS server kstat -q nfs::nfs_server: if [ $? = 0 ]; then echo "NFS Server configured" else echo "No NFS Server configured" fi # ... do some more stuff exit 0 11.2.2. Real-World Example That Uses kstat and nawkIf you are adept at writing shell scripts with editing tools like sed or awk, here is a simple example to create a network statistics utility with kstats. The /usr/bin/netstat command has a command-line option -I interface by which you can to print out statistics about a particular network interface. Optionally, netstat takes an interval argument to print out the statistics every interval seconds. The following example illustrates that option. $ netstat -I qfe0 5 input qfe0 output input (Total) output packets errs packets errs colls packets errs packets errs colls 2971681 0 1920781 0 0 11198281 0 10147381 0 0 9 0 7 0 0 31 0 29 0 0 4 0 5 0 0 24 0 25 0 0 ... Unfortunately, this command accepts only one -I flag argument. What if you want to print statistics about multiple interfaces simultaneously, similar to what iostat does for disks? You could devise a Bourne shell script using kstat and nawk to provide this functionality. You want your output to look like the following example. $ netstatMulti.sh ge0 ge2 ge1 5 input output packets errs packets errs colls ge0 111702738 10 82259260 0 0 ge2 28475869 0 61288614 0 0 ge1 25542766 4 55587276 0 0 ge0 1638 0 1075 0 0 ge2 518 0 460 0 0 ge1 866 0 7688 0 0 ... The next example is the statistics script. Note that extracting the kstat information is simple, and most of the work goes into parsing and formatting the output. The script uses kstat -q to check the user's arguments for valid interface names and then passes a list of formatted module:instance:name:statistic arguments to kstat before piping the output to nawk #!/bin/sh # netstatMulti.sh: print out netstat-like stats for # multiple interfaces # using /usr/bin/kstat and nawk USAGE="$0: interface_name ... interval" INTERFACES="" # args list for kstat while [ $# -gt 1 ] do kstat -q -c net ::$1: # test for valid interface # name if [ $? != 0 ]; then echo $USAGE echo " Interface $1 not found" exit 1 fi INTERFACES="$INTERFACES ::$1:" # add to list shift done interval=$1 # check interval arg for int if [ X`echo $interval | tr -d [0-9]` != X"" ]; then echo $USAGE exit 1 fi kstat -p $INTERFACES $interval | nawk ' function process_stat(STATNAME, VALUE) { found = 0 for(i=1;i<=5;i++) { if(STATNAME == FIELDS[i]) { found = 1 break } } if ( found == 0 ) return kstat = sprintf("%s:%s", iface, STATNAME) if(kstat in b_kstats) { kstats[kstat] = VALUE - b_kstats[kstat] } else { b_kstats[kstat] = VALUE kstats[kstat] = VALUE } } function print_stats() { printf("%-10s",iface) for(i=1;i<=5;i++) { kstat = sprintf("%s:%s",iface,FIELDS[i]) printf(FORMATS[i],kstats[kstat]) printf(" ") } print " " } BEGIN { print " input output " print " packets errs packets errs colls" split("ipackets,ierrors,opackets,oerrors,collisions", FIELDS,",") split("%-10u %-5u %-10u %-5u %-6u",FORMATS," ") } NF == 1 { if(iface) { print_stats() } split($0,t,":") iface = t[3] next } { split($1,stat,":") process_stat(stat[4], $2) } |