Showing posts with label usage. Show all posts
Showing posts with label usage. Show all posts

Tuesday, March 31, 2009

Measuring Heavy CPU Usage Over Time On Linux And Unix

Hey There,

Today's bash script is going to be somewhat related to our previous script which tracked idle process time on Linux and Unix, insofar as it deals with trying to rid your system of troubling processes as automatically as possible. Of course, there's no substitute for an eyeball-inspection (of the system, I mean. Unless your eyeballs are hurting ;) but, once you've got a few things down and feel reasonably safe, the more you can take off of your daily plate, the better. ...Just don't make your job so incredibly simple that a machine (or a pre-schooler from a third-world country) could do it ;)

This script is, like most of the stuff we put out here, incredibly easy to run (especially since you set all the variables inside it - change as you see fit), like so:

host # ./munchies

And you're off. In the screenshots below, we'll walk through some basic examples of simple usage, assuming the script's built in parameters. Any process consuming more than 10 percent of the CPU gets added to the blacklist and any process that shows up in the blacklist, 10 times consecutively, will get killed (No screwin' around here ;)

In the first screenshot, we've isolated process id 499 (which happens to be the X server), since it's the only process on the box that meets the "CPU percentage" criteria. Once it finds that process, it adds it to the default temporary file (the simple way to maintain state ;). We then populate the /tmp/munchiestats file with a whole bunch of other PID's (some real, some non-existent) and multiple instances of PID 499 (but, less than 9, so we don't trigger the kill on the next execution) and cat that so you can see the contents:

Click on the picture below. Like water on a sponge ;)

munchies script output 1

In the second screenshot, we run munchies again and see it clear all the PID's in the temp file that are legitimate, but aren't using over 10% of the CPU anymore. We also free any PID's in the temp file that don't exist any more (possibly, from a process exiting, but - in this case - because we just made them up ;). The final run executes the kill of PID 499 and removes it from the temp file:

Click on the picture below and brace yourself for the HUGEness ;)

munchies script output 2

Of course, the script has its faults. The most blatant pain in the arse (to our thinking, at this point - with very little QA'ing done ;) is that we've hardcoded the percentage of CPU (10%) and amount of times a PID is allowed to use that much (10 times) and not made them command line or top-listing variables. If you want to change it in the script, just modify these lines:

For the CPU percentage limit:

if [[ $cpu_percentage_integer -gt 10 ]]

And for the number of consecutive times you'll allow the offending PID to get away with it before you murder (I mean, kill... ;) it:

if [[ $chronic_muncher -gt 8 ]] <-- This is set to 8 since, if the pre-existing number of additions of a certain PID is over 8, it's (at best) 9, and this go 'round will put it at the limit of 10!
elif [[ $chronic_muncher -lt 10 ]]

Another maybe-flaw is that we don't have it set to run backgrounded, or as a daemon. In other words, you need to run it on your own schedule. We have it running in cron every 5 minutes, so a process can abuse the CPU for about 50 minutes before we kill it. If you run it every minute, you can kill it in 10. Of course, all of this is "variable" and you can change it to suit your needs.

And, if you consider this a flaw, the script was written in bash on Solaris 10, but should be easily portable to other Unix and Linux distro's. Let us know if you'd like to see a version for RedHat or Ubuntu!

Here's hoping this helps you out in some way, shape or form. It's probably translatable to a lot of other work-type performance-tuning situations, as well.

Cheers!


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/bin/bash

#
# munchies - eat up processes using over 10 percent of the cpu over 10 iterations...
#
# 2009 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

cpu_munchers_file="/tmp/munchiestats"
sed=`which sed`
awk=`which awk`
ps="/usr/ucb/ps" # Using /usr/ucb/ps on purpose for %CPU stats
grep=`which grep`
mv=`which mv`
wc=`which wc`
sort=`which sort`
xargs=`which xargs`
kill=`which kill`
# kill_signal="-9" # Don't set this if "kill -TERM"/"kill -15" - i.e. "plain vanilla"kill - is acceptable

while read a b c d
do
munch_pid="$b"
cpu_percentage="$c"

if [[ -z "$cpu_percentage" ]]
then
echo "munch_pid $munch_pid is either non-existent or is using less than zero percent of the cpu!"
continue
else
cpu_percentage_integer=$(echo "$cpu_percentage"|$sed 's/^\([^\.]*\)\..*$/\1/')
fi

if [[ $cpu_percentage_integer -gt 10 ]]
then
echo "Got A Bad One Here - munch_pid $munch_pid Is Using $cpu_percentage_integer Percent Of Our Cpu"
if [[ -f $cpu_munchers_file ]]
then
echo "Checking cpu_munchers_file $cpu_munchers_file For munch_pid $munch_pid"
chronic_muncher=$(echo `$grep -w $munch_pid $cpu_munchers_file|$wc -l`)
if [[ $chronic_muncher -gt 8 ]]
then
echo "munch_pid $munch_pid Count Is $chronic_muncher - This Will Put It At 10 Or Higher"
echo "Issuing \"$kill $kill_signal $munch_pid\" And Removing From $cpu_munchers_file now!"
temp_variable=$$
### $kill $kill_signal $munch_pid
$grep -vw $munch_pid $cpu_munchers_file >>${cpu_munchers_file}.$temp_variable
mv ${cpu_munchers_file}.$temp_variable $cpu_munchers_file
elif [[ $chronic_muncher -lt 10 ]]
then
echo "munch_pid $munch_pid, with $cpu_percentage_integer cpu usage, Being Added, Possibly Again, To cpu_munchers_file $cpu_munchers_file"
echo "$munch_pid" >>$cpu_munchers_file
fi
else
echo "No Cpu-Munchers Exist. Creating cpu_munchers_file $cpu_munchers_file And Adding munch_pid $munch_pid"
echo "$munch_pid" >>$cpu_munchers_file
fi
else
if [[ -f $cpu_munchers_file ]]
then
chronic_muncher=$(echo `$grep -w $munch_pid $cpu_munchers_file|$wc -l`)
if [[ $chronic_muncher -gt 0 ]]
then
echo "munch_pid $munch_pid Is Ok And Is In $cpu_munchers_file - Removing"
temp_variable=$$
$grep -vw $munch_pid $cpu_munchers_file >>${cpu_munchers_file}.$temp_variable
mv ${cpu_munchers_file}.$temp_variable $cpu_munchers_file
else
:
fi
else
:
fi
fi
done <<< "`$ps -aux|$awk '{print $1,$2,$3,$NF}'|sed 1d`"

echo "Checking $cpu_munchers_file For Non-Existent munch_pids"
if [[ -f $cpu_munchers_file ]]
then
muncher_array=$($sort -u $cpu_munchers_file|$xargs echo)
for possible_lost_pid in ${muncher_array[@]}
do
is_this_muncher_real=$(echo `$ps -aux|$grep -w $possible_lost_pid|$grep -v grep|$wc -l`)
if [[ $is_this_muncher_real -eq 0 ]]
then
echo "Lost munch_pid $possible_lost_pid Is No Longer Running. Removing From $cpu_munchers_file"
temp_variable=$$
$grep -vw $possible_lost_pid $cpu_munchers_file >>${cpu_munchers_file}.$temp_variable
mv ${cpu_munchers_file}.$temp_variable $cpu_munchers_file
fi
done
echo "All Possible Injustices Have Been Remedied"
fi



, Mike




Discover the Free Ebook that shows you how to make 100% commissions on ClickBank!



Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.

Wednesday, December 24, 2008

Taking Full Advantage Of "Who" On Solaris

Hey there,

First things first: Happy Christmas Eve :) Our apologies to our readers who celebrate different festivities this time of year. It's not that we don't want you to enjoy them (although our wishes are probably belated for some), just that we almost forgot about our own... What does that say about us? We don't know either ;) In the spirit of "it's never too late" - Happy Holidays (whatever they may be) from all of us :)

This post is more of an expansion, than a follow-up, to our May 2008 post on using who to find out what and when on Linux and Unix (picking only the options that appeared in most distro's version of "who"). It's also a bit more restrictive than our previous post, as we're restricting the discussion to newer Solaris' (8/9/10) implementation of the classic command (Okay, "according to Hoyle" (and I'm using that idiom loosely, since this post has nothing to do with the game of Whist ;), it can't be a classic for another 12 years, but if TNT can televise "new classics" that just came out last year, the meaning of the word has either been completely devalued or we're making liberal use of artistic license. We prefer the latter justification ;)

Solaris' implementation of who is a great deal better than in older versions, and turns what used to be a "mostly" informational command into a command that you can use to really get to the bottom of things. Following, a list of Solaris who's usage parameters and a brief discussion of each. One thing that should be noted is that the Solaris who command has no "help" switch (-h, --help, nothing), and it will produce output if you just run it without arguments. We usually go with "who -h" (since -h isn't an option) to get usage/help output. You'll have to subject yourself to the humiliating error message, but it's generally worth it ;)

Ladies and gentleman, The Options :)

1. Who straight-up (what better way to start a list of options than with the no-option option? This is what you get if you settle. Four columns: User ID (NAME), terminal (LINE), date (TIME) and local-screen/IP-address:

host # who
user001 console Dec 8 09:48 (:0)
user001 pts/3 Dec 8 09:50 (:0.0)
user001 pts/5 Dec 23 08:56 (10.99.99.99)


2. -a. This option is fairly obvious. It stands for "all" and is the equivalent to using "-Abdlprtu" which, the astute among you may have noted, does not comprise the entirety of the options available ;) We'll go over all the options that are lumped together in this option shortly (If I had more time to proofread, I wouldn't have made the word option a tag for this post ;).

host # who -a
. system boot Dec 8 09:46
. run-level 3 Dec 8 09:47 3 0 S
zsmon . Dec 8 09:47 old 307
LOGIN console Dec 8 09:47 old 331
user001 + console Dec 8 09:48 old 663 (:0)
user001 + pts/3 Dec 8 09:50 old 1015 (:0.0)
user001 pts/4 Dec 8 10:37 old 0 id= /4 term=0 exit=0
user001 + pts/5 Dec 23 08:56 . 17914 (10.99.99.99)
user001 pts/4 Dec 11 16:15 old 28003 id=ts/4 term=0 exit=0
user001 pts/6 Dec 19 10:39 old 11406 id=ts/6 term=0 exit=0
user001 pts/7 Dec 18 16:40 old 9997 id=ts/7 term=0 exit=0
user001 pts/8 Dec 16 14:05 old 5804 id=ts/8 term=0 exit=0


3. -b. This option will show you the last time the system booted. This can be very helpful (especially when used in combination with "last -x" to make use of last's full potential):

host # who -b
. system boot Dec 8 09:46


4. -d. This option purports to list out "dead" processes. The reason we phrase it in that way is that, generally, these processes (or pseudo terminals) may have been used before, but this doesn't mean that they're hanging around like a bunch of zombie processes. For instance, the following output lists 5 "dead" pseudo terminals, although none of them can be found in the output of either "ps" or "lsof" (???) In any event, it's a cool feature :)

host # who -d
user001 pts/4 Dec 8 10:37
user001 pts/4 Dec 11 16:15
user001 pts/6 Dec 19 10:39
user001 pts/7 Dec 18 16:40
user001 pts/8 Dec 16 14:05


5. -H. This one is a fantastically fun joyride through the land of the obvious. It forces who to print out the header for each column it reports on (although it does forget about the display/IP column noted in straight-up "who" output from point 1):

host # who -H
NAME LINE TIME
user001 console Dec 8 09:48 (:0)
user001 pts/3 Dec 8 09:50 (:0.0)
user001 pts/5 Dec 23 08:56 (10.99.99.99)


6. -l. Using who with the -l option lists out only "login" processes. Basically, it will only report on logins that are logged in (or appear to be logged in) to the localhost directly (no external pseudo terminals):

host # who -l
zsmon . Dec 8 09:47 old 307
LOGIN console Dec 8 09:47 old 331


7. -q. This will perform a quick who (only showing the NAME field), and is the only option that the -n option works with. If you use -n with -q, you can specify the number of returned processes you want to see per line of output, at most. By default, who -q tries to return as many results as possible on a single line:

host # who -q
user001 user001 user001

who -q -n 2
user001 user001
user001


8. -r. This option will let you know what run level your system is currently at (again, check out our previous post on using who for more specifics on all of the output "who -r" produces:

host # who -r
. run-level 3 Dec 8 09:47 3 0 S


9. -s. This option is considered the "short form," since it doesn't report any "time since last login," session activity status or PID output. who, run with this option alone is actually the default output. The one time this comes in handy is when you're using it with -a (and -H for the headers, if you want), and want to trim that output a bit. Otherwise, using this option wouldn't make sense, since you'd have to specify the flags to print the two fields you want removed ;)

host # who -s
user001 console Dec 8 09:48 (:0)
user001 pts/3 Dec 8 09:50 (:0.0)
user001 pts/5 Dec 23 08:56 (10.99.99.99)

host # who -asH

NAME LINE TIME
. system boot Dec 8 09:46
. run-level 3 Dec 8 09:47 3 0 S
zsmon . Dec 8 09:47
LOGIN console Dec 8 09:47
user001 + console Dec 8 09:48 (:0)
user001 + pts/3 Dec 8 09:50 (:0.0)
user001 pts/4 Dec 8 10:37
user001 + pts/5 Dec 23 08:56 (10.99.99.99)
user001 pts/4 Dec 11 16:15
user001 pts/6 Dec 19 10:39
user001 pts/7 Dec 18 16:40
user001 pts/8 Dec 16 14:05


10. -t: This option will show you all the times that your system clock was reset (and, yes, sometimes this output can be empty, for reasons that require no explanation ;)

host # who -t
host #


11. -T. This flag shows your tty status (referred to also, above, as session activity status). The + symbol indicates that the tty's status is "writable," the - symbol indicates that the tty's status is "not writable" and the ? symbol indicates general confusion ;) It just means that the system has no idea what the tty's status is, which generally means that it's hung:

host # who -T
user001 + console Dec 8 09:48 old 663 (:0)
user001 + pts/3 Dec 8 09:50 old 1015 (:0.0)
user001 + pts/5 Dec 23 08:56 . 17914 (10.99.99.99)


12. -u. This flag lists out (and I'm quoting from the "usage" output) "useful information." That isn't to say that any other output you can get from who is completely useless. Although, the terminology does seem to cast a shadow... ;)

host # who -u
user001 console Dec 8 09:48 old 663 (:0)
user001 pts/3 Dec 8 09:50 old 1015 (:0.0)
user001 pts/5 Dec 23 08:56 . 17914 (10.99.99.99)


13. -m. This flag limits the information to the current terminal session only. As you can see below, we're logged in using pseudo tty /dev/pts/5:

host # who -m
user001 pts/5 Dec 23 08:56 (10.99.99.99)


14. And, to begin the wrap-up, Solaris' who makes up for the fact that it doesn't have a built in handler to deal with being called as "whoami" by providing two different options to get that same information. In an alarming show of disregard for proper capitalization, both of these versions work ;) Note that this output is almost always exactly the same as the output from "who -m":

host # who am i
user001 pts/5 Dec 23 08:56 (10.99.99.99)
host # who am I
user001 pts/5 Dec 23 08:56 (10.99.99.99)


follow that up with the question that, statistically, follows "who am I?" most often, give it a little bit of "Talking Heads" flavour, and you've got yourself a command that's completely useless ;)

host # my God, what have I done?
-bash: my: command not found


15. Back off the Road To Nowhere (David Byrne, again. Make him stop!! ;)... Lastly (no pun intended, as you'll understand by the end of this paragraph), you can use who, using any combination of options (with the exception of -n, which only works with -q), and follow it all up with a different utmpx file (if, for instance, your old one got to big and you copied it off somewhere). Straight up who on Solaris makes use of /var/adm/utmpx, but you can tell who to use any utmpx-like file (including wtmpx, which can make the "who" command emulate the "last" command to a basic degree):

host # who /var/adm/wtmpx
root console Nov 6 13:39
root console Nov 6 13:48 (:0)
root pts/3 Nov 6 13:51 (:0.0)
root pts/3 Nov 6 14:38 (:0.0)
root pts/4 Nov 6 14:39 (:0.0)
user001 sshd Nov 7 09:48 (host.subnet.domain.com)
user001 pts/4 Nov 7 09:48 (host.subnet.domain.com)
user001 sshd Nov 7 09:54 (host1.subnet2.domain3.com)
user001 pts/5 Nov 7 09:54 (host1.subnet2.domain3.com)
...


Here's hoping today's post help shed a bit more light on Solaris' who options than the standard usage screen does, pointed out a number of reasons it can be a great tool to have in your troubleshooting arsenal and (perhaps) taught you a trick or two :)

Cheers,

, Mike




Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.

Tuesday, July 1, 2008

Using Strings To Safely Get Program Usage Information On Linux And Unix

Hey There,

We've posted quite a bit about the "strings" command in various past-posts running the gamut from using strings to extract RPM header information to using the basic strings construct in C to make running shells on network sockets possible. Today we're going to take a look at the "strings" command in an entirely new light.

Imagine that you were tasked with running a particular command named, for the sake of argument, BLARG. Unfortunately, in our manufactured situation, BLARG has no man page, and searches for it in Google, and other search engines turn up no useful information. Also your boss just said that you needed to run it, and left it at that, with no further instruction (he also can't be reached. What's wrong with this guy? ;) BLARG is also a compiled binary.

Your basic inclination might be to just run it without any arguments, as many commands (like "mkdir") will give you the usage information you need if you use this method, like so:

host # mkdir
usage: mkdir [-p] [-m mode] dirname ...


However, lots of other programs don't, so it's not the wisest choice. Remember that BLARG could potentially be a very harmful program. Running it without arguments may destroy things you can't afford to lose.

Other options you have, would include (but not be limited to), the following, coupled with their undesirable possible outcomes:

1. You could give the command a bogus switch line, like "BLARG -xKECVDSLdlske" : Assuming that that command line is indeed bogus, lots of programs silently ignore bogus switches and run their default instructions anyway.

2. You could cat the command : This will probably just turn your terminal output into Chinese. Even if you redirect standard error to /dev/null, odds are standard output is going to include a lot of funky characters that might cause more harm than good. You might also note that, a lot of the time, the usage message is printed to standard error and not standard output!

3. You could use eval to run the program, like "eval BLARG" : Unfortunately, even though it seems counterintuitive, eval just evaluates a condition or program's return status. Unfortunately, in order to get that, it has to run the command.

4. You could use commands like crash to get the information : This can be a great way to find out the information you need. By typing "crash -h BLARG" you should, theoretically, get a dump of all the help information you need. Unfortunately, not all distro's of Linux and Unix include it by default and not all distros' versions of crash operate the same. Some require you to be proficient in running a debugger against a dump file, afterward. Way too much hassle.

So far, we've gone through about 5 options, going from worse to better. There are probably a lot more than I'm thinking up here as I type (email them to me at eggi@comcast.net with comments if you'd like, as I'd love to do a follow-up to this post with more of that kind of information).

One way I've found that is virtually foolproof, and works in every distro I've tested, is to use the "strings" command to extract usage information. If you've ever used strings before, you know that distilling what it spits out when you run it against a command to a universally acceptable output of help information for any and/or all binaries is next to impossible. The Linux version of the crash command comes much closer to doing this, and doing it better. But, for the rest of us (even those without the privilege to run "crash"), we can still get the information we need using "strings", like so:

host # strings BLARG 2>/dev/null|egrep -i 'usage|help' <-- Note that strings generally requires the fully qualified name of the binary, like /bin/BLARG or ./BLARG
usage: %s [-abcdefGHIJKv] [file ...]

and you can even add the universal "%s" printf modifier to your egrep if you want to get all the lines that might contain useful help information, if you're not sure that the usage message is limited to a single line of output. This has the side effect of, sometimes, making the output a little messy, although (as some of you may have noted) the above usage display (while better than nothing) doesn't really help you. You'll probably be right 99% of the time if you guess the -v flag stands for verbose or version, but you never know. Using strings and grabbing all the lines with %s can provide more insight, if not a more distracting view of the binary's guts (of course, this output is from another command entirely ;)

host # strings BLARG 2>/dev/null|egrep -i 'usage|help|%s'
%s: %s
%s: directory causes a cycle
%s %*u %-*s %-*s
ls: %s: %s
%s/%s
usage: %s [-abcdefGHIJKv] [file ...]
%ld%s-blocks
%s: unknown blocksize
%s: minimum blocksize is 512
%s:
%s: %m
netgroup: Cycle in group `%s'
%s.%s
(%s,%s,%s)
option requires an argument -- %s
unknown option -- %s
stack overflow in function %s
%.3s %.3s%3d %2.2d:%2.2d:%2.2d %s
%H:%M:%S
%a %b %e %H:%M:%S %Z %Y
%I:%M:%S %p
%s/%s.%d
YP server for domain %s not responding, still trying
<; errno = %s
%s: %s - %s
%s/bt.XXXXXX
%s/_hash.XXXXXX


Worst case, you can just run something like:

host # strings BLARG >OUTPUT 2>&1

and safely cruise the lines of text in the OUTPUT fiel to manually find what you need. You may have to ;)

In any event, you've got a great tool at your disposal to find out what you need to know the hard way. And, sometimes, that's the only way to be absolutely sure :)

Cheers,

, Mike

Wednesday, June 4, 2008

Shell Script To Monitor Disk Usage On Linux and Unix

Hey There,

Today, we're going to take a look at a simple shell script to monitor disk space usage. It's been quite a while since we've touch on that, going back to a post from last November regarding finding space hogs on overlay mounts. The script has been kept simple (basically checking every partition for one fixed percentage full) to highlight other features.

The main intent here was to set up a monitor that would be able to handle a variety of Linux and Unix Operating Systems (all dependant on the "uname -s" output from that system) and focus on that area distinctly. We've limited our initial list to HP-UX, Solaris, SCO and OpenBSD.

In this case we're using a simple case statement to enumerate through the four *nix's we have listed here. Obviously, we could easily add more operating systems, and their variations of the "df" command, to our list and, if it ever got too big, either roll them into an array or simplify the script so that more OS's would fall under the same umbrella.

Also, notice that we're stepping through parsing of the df output more tediously than is actually necessary. For instance, the creation of the df output could be parsed with sed all in one fell swoop. Again, although it is generally considered best practice to compact your script/code, our hope here was that this would be easy to follow for as many people as possible. Some folks learn better by tackling the tough-stuff and working back to basics and some of us learn better by starting with the basics and putting them all together to create the tough-stuff. It's a long and convoluted statement of philosophy, to be sure, but fairly descriptive of what we actually mean ;)

If you prefer, on the line where we parse the TABLE file and trim it with sed, you can take out this part (or add to it) as it was placed in there as an example of how to ignore a specific partition (/usr):

-e '/usr$/d'

So, the line:

sed -e '1d' -e '/usr$/d' ${BASEDIR}/TABLE >> ${BASEDIR}/TABLE2

could be changed to:

sed -e '1d' ${BASEDIR}/TABLE >> ${BASEDIR}/TABLE2

which could then be simplified even further (since you don't need to use -e, even though it's okay to, if you only have one instruction to pass to sed) to become this:

sed '1d' ${BASEDIR}/TABLE >> ${BASEDIR}/TABLE2

And the entire script could be thusly compacted and streamlined, etc.
In any event, I hope this can be of some help (or, at least, an inspiration to reach higher ;) to you!

Best wishes,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/bin/ksh

#
# dfvk.sh - Check partition % full
# across multiple OS'
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

trap 'rm -f ${BASEDIR}/TABLE ${BASEDIR}/TABLE2 ${BASEDIR}/MAILER;exit 1' 1 2 3 15

#BASEDIR="/tmp"
BASEDIR="tmp"
LOGHOST=`hostname`
MAILEES="you@yourhost.com"
LIMIT=90
OSVERSION=`uname -s`

case $OSVERSION in

SunOS | OpenBSD )
df -k >> ${BASEDIR}/TABLE
;;
HP-UX )
bdf >> ${BASEDIR}/TABLE
;;
* )
df -v >> ${BASEDIR}/TABLE
;;

esac

echo "$LOGHOST is getting ready to bother you!" >> ${BASEDIR}/MAILER
echo >> ${BASEDIR}/MAILER

sed -e '1d' -e '/usr$/d' ${BASEDIR}/TABLE >> ${BASEDIR}/TABLE2
sed 's/%//g' ${BASEDIR}/TABLE2 > ${BASEDIR}/TABLE
cat ${BASEDIR}/TABLE |while read ONE TWO THREE FOUR FIVE SIX
do

case $OSVERSION in

HP-UX | SunOS | OpenBSD )
if [ $FIVE -gt $LIMIT ]
then
print "$SIX partition at ${FIVE}% capacity" >> ${BASEDIR}/MAILER
else
continue
fi
break;;
* )
if [ $SIX -gt $LIMIT ]
then
print "$ONE partition at ${SIX}% capacity" >> ${BASEDIR}/MAILER
else
continue
fi
break;;

esac

done

MAILCOUNT=`cat ${BASEDIR}/MAILER |wc -l`
if [ $MAILCOUNT -gt 2 ]
then
cat ${BASEDIR}/MAILER |mailx -s "$LOGHOST : Potential Paging Threat!" $MAILEES
fi

rm -f ${BASEDIR}/TABLE ${BASEDIR}/TABLE2 ${BASEDIR}/MAILER


, Mike

Tuesday, April 8, 2008

Usage And Compile Help For Linux/Unix Network Port Shell Program

Hey there,

Today's post is a follow up to yesterday's post on running a shell on a network socket. There are a few notes we'd like to add regarding compilation and usage, once you've got the program up and running on your Linux or Unix server.

First, the compile time note. Additional testing on other flavors of Linux showed that neither:

#include <sys/byteorder.h>

nor

#include <sys/endian.h>

worked on all systems :( We did find that this Linux "include" seems to work as a handy substitute for either:

#include <linux/byteorder/generic.h>

Of course, if none of these options work for you, we put comments in the code that name the functions and/or declarations that we're trying to grab from each of the includes. So, if you still find yourself in a pickle after trying all 3 of these include statements, you can probably find the correct include (.h header file) by typing the following at your command prompt:

host # find /usr/include |xargs egrep 'htons|htonl' /dev/null

It may be a bit tricky trying to find the correct include file, but it will probably have a name very similar to the 3 noted above.

Now, on to the fun stuff: Usage :)

To get this out of the way, if you've compiled and used the program to run a Linux or Unix shell on a network socket, you've probably noticed that the input and output don't behave exactly as you would expect in a regular shell.

Note that this line in the code:

execl("/bin/sh","sh",(char *)0);

was originally attempted in the following two manners (to try and force an interactive shell):

execl("/bin/sh","sh","-i",NULL); <--- Socket would connect, but then it would disconnect you immediately
execl("/bin/sh","sh","-i",(char *)0); <--- Socket would connect, and it wouldn't look ugly, but it wouldn't do anything else either (and we made sure it wasn't just an issue with echo by touching some files and verifying that they never got "touched" ;)

When all was said and done, this was the quickest, and dirtiest, way we could get the shell to answer on the network socket and be truly interactive. However, as mentioned above, it doesn't quite behave the way you might assume. Even shell built-in's don't work correctly for the most part, like in this mini-run-through:

host # ls
. .. netsock netsock.c
host # ./netsock
host # telnet localhost 40236
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
ls
: command not found
pwd
: command not found
id
: command not found
echo
: command not found


Yet, strangely enough, "echo," with arguments, works (???):

echo hi
hi


although "eval" doesn't work, straight up:

eval ls
: command not found


Now, we can start to have some fun :) Using the backtick operators to execute an "eval" statement and echoing that, we can actually do something, and get confirmation back on our terminal!:

echo `eval ls`
netsock netsock.c
<--- This will always pump the output out on one line, so if you have a lot of files in your directory, you'll get back a long long line.
echo `eval pwd`
/export/user/bin
echo `eval id`
uid=0(root) gid=0(root) groups=0(root)
<--- This will be your PID if you started the program, which may be good enough if you just need to get in and do something that doesn't require privilege. Note that this program runs the shell on the socket under the UID and GID of the user that invokes it (or their effective UID and GID at that time)
echo `eval touch TOUCHY`
<--- We'll touch something, just to see if it works. Of course, we get no terminal response to indicate success, but that's normal since we don't have a prompt to return to.

Now, if we disconnect from the Telnet connection and do an ls, we should have an extra file waiting for us:

^]
telnet> q
Connection closed.
host # ls
. .. netsock netsock.c TOUCHY


Good deal :) Now we'll write a simple script and see if we can execute it from the shell attached to the network port. If this works, it'll be much easier to stage work for the future:

host # vi test.sh
host # chmod 700 test.sh
host # cat test.sh
mkdir a
cd a
touch file
echo "ALL SET"
host # telnet localhost 40236
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
echo `eval ./test.sh`
ALL SET


And we get the output we expected! Just need to disconnect from Telnet again and check to make sure it actually did everything it was supposed to, and not just run the echo statement.

^]
telnet> q
Connection closed.
host # ls
. .. netsock netsock.c TOUCHY
a
host # ls a
. .. file


Success! Here's hoping this "how to" and compilation-assistance post helps you get more out of this program. If you haven't got the code already, please check out our post on running a shell on a network socket and have a blast!

Just, please, be considerate of others :)

Best wishes,

, Mike




Tuesday, November 20, 2007

Trimming Space in /var - The Problem with Solaris' lastlog

Here's another interesting tidbit from the "terminally boring" archives of system administration ;)

A lot of times, when you get a complaint that /var, on a Solaris box, is exceeding whatever size limitation you've placed on monitoring it, your first inclination is to go and wipe out the largest (but not most necessary) files immediately and see if that takes care of the problem.

Every once in a while, if you're checking around, you may notice that /var/adm/lastlog is gigantic. Theoretically, zeroing that out (catting /dev/null into it), should take care of your disk usage problem as it seems fairly obvious. Some of us would just leave it at that. The rest of us would check "df -k /var" again and notice that the percentage of partition space used is relatively the same. That doesn't seem to make any sense.

This is where the interesting part comes in. Solaris' implementation of lastlog has an interesting bug/feature that makes it seem larger than it is; but only some of the time.

The reason for this is that, while its size remains fairly static (about 24kb maximum), lastlog always indicates its size (when using "ls -l") relative to the user account id that last logged in (after the 24 Kb maximum is reached). The equation is roughly "the user account id number" multiplied by "28 bytes." So, when root logs in with a userid of "zero" (after you've zeroed out the file), it seems to grow to a size of 28 bytes (Yes, this is the minumum - and, yes, 28 times zero should equal zero ;) However, if you do an "ls -s" (to figure out the number of blocks) and a "du -k" (to figure out the size in Kb) on /var/adm/lastlog, you'll see that it's not really taking up all that much space. Below:

$ ls -l /var/adm/lastlog
-r--r--r-- 1 root root 28 Nov 19 17:51 lastlog
$ ls -s /var/adm/lastlog
2 /var/adm/lastlog
$ du -k /var/adm/lastlog
1 /var/adm/lastlog


If a user with a userid of 6504 logs in (after zeroing out the file) the block and Kb size will show the maximum (48 and 24, respectively), but "ls -l" reports:
$ ls -l /var/adm/lastlog
-r--r--r-- 1 root root 182112 Nov 19 17:53 lastlog


Crazy, yeah? But, interesting to know, and helpful, since you can avoid this file when trying to pare down the size of the /var partition.

As a caveat, the "fake" size reported by "ls -l" is only fake when lastlog is being manipulated by the Solaris Operating System in the manner in which it was specifically designed to be manipulated. If you copy that 500Mb file (or move it, tar it, etc) it pads all the "blank" space with NULLs and you end up having a file on your hands that really "is" insanely large!

, Mike