Showing posts with label process. Show all posts
Showing posts with label process. Show all posts

Thursday, March 26, 2009

Simple, But Effective. Echo Debugging On Linux And Unix

Hey there,

I took some time and did some simple "echo debugging" and found that the warning I issued about yesterday's script to find a process's idle time was completely backward. Fortunately, it turns out that my mistaken judgement meant that I had a lot less to worry about, in terms of damage control, from the flaw I perceived in my script (I'm not saying there aren't others, of course ;)

It turns out that the problem was not that the script would sometimes consider an active process, that didn't have an idle column value in the "w -s" output, to be idle and worth terminating. The actual problem was that it would consider processes that had been up for more than a day to be active and not worth terminating. This was a much better situation. At least I wouldn't be killing off active processes!

A sample of just using the DEBUG statements I put in yesterday's script pointed out the error very obviously, like so:

DEBUG::::: PIDTTY 6892 pts/119
DEBUG::::: W user1 119 2days ./program
DEBUG::::: LONGTIME TIME
PID 6892 is OK - Not Idle At All - Remove this message!
------------------------
DEBUG::::: PIDTTY 581 pts/232
DEBUG::::: W user1 232 2days ./program
DEBUG::::: LONGTIME TIME
PID 581 is OK - Not Idle At All - Remove this message!
-----------------------------------


And, yes, I felt like a complete moron when I finally took a second to actually look at the output ;) It's a amazing what a few simple echo statements in a script can tell about what problem's it has :)

From that point, I found several other issues and worked on them accordingly:

1. ISSUE WITH IDLE ALPHA DAYS NOTATION = FIX BY CHECKING FOR NON-NUMERIC TYPES

2. ISSUE WITH NO-IDLE MISSING COLUMN = FIX BY SETTING EMPTY VALUE TO NULL PADDED

3. ISSUE WITH MISSING COLUMN ERROR OUTPUT = FIX BY CHECKING COLUMN COUNT IN TIME

4. MUCH BETTER - "NOT IDLE AT ALL" EXCEPTION NEVER CAUGHT - UNNECESSARY NOW - REMOVED

5. REWORKED TIME HANDLING AND SET TO AMBIGUOUS ALPHA MATCH


Pardon my hysterical notes ;) Most of my problem stemmed from the fact that I switched from full-fledged "w" to "w -s" and made some mistakes in updating the relevant columns that I needed to assign to variables.

I should note that I also considered using "who -T" to get around the one time-stealer in this script. Although it did bring the script down to under a second (processing approximately 100 records), "who" only reports on the "user process." This is a huge consideration, since the "user process" can (and usually is) the parent process of the process you want to check the idle time on. I ultimately decided to stick with "w" since using "who" would mean I'd have to check the parent process, cross reference that with the grep output associated with the pty and then end up back at "w" again to get the process's idle time. A lot of extra work for a lot of extra uncertainty. I didn't want to end up in a situation where the "user process" was idle because the user kicked off a script that ran for 6 hours and then terminate the user's main process (which would kill the kids) based on the idle time of the user's session. Sometimes, lack of precision like that can cause you headaches you never imagined you could have ;)

As you can see below, the updates weren't all that impressive, but I did get the execution time down to 30 seconds from 2 minutes. The only way I could get it lower (that I've figure out so far ;) was to compromise the integrity of the script and remove the one awk statement that was holding it back. Notice the last step I took, just to see what would happen, that proved the awk if/else conditional in the script was responsible for a majority of the execution time:

TRIMMED CODE - REMOVED DEBUG AND UNNECESSARY ECHO STATEMENTS - USING BASH TEST AND OPERATORS
OLD SCRIPT EXECUTION TIME FOR 178 PROCS = 1m27.430s
NEW SCRIPT EXECUTION TIME FOR 179 PROCS = 0m56.517s
NEW SCRIPT EXECUTION TIME FOR 110 PROCS = 0m48.940s
SELF-CONTAINED SCRIPT EXECUTION TIME FOR 111 PROCS = 0m51.048s
ADDED TTY TO PS SCRIPT EXECUTION TIME FOR 101 PROCS = 0m29.703s
REMOVING AWK TTY STATEMENT SCRIPT EXECUTION TIME FOR 100 PROCS = 0m29.991s
ADDED ?, console and "continue" SCRIPT EXECUTION TIME FOR 102 PROCS = 0m33.018s
REMOVED W HEADING (REM SED) AND EXPLICIT USER SCRIPT EXECUTION TIME FOR 101 PROCS = 0m33.382s
TEST - HARDCODED UPTIME AND REMOVED AWK STATEMENT - SCRIPT EXECUTION TIME FOR 170 PROCS = 0m8.512s!!!!!!!!!!!


I'm going to work on it some more, because I believe it can be improved tremendously, but - to satisfy any curiosity, here's some of the mid-work that fixed that issue and made the bash script report correctly. I'll post the one with the fixes noted above (and more, I'm sure ;) once I've thoroughly tested them and removed a lot of the redundancy in this script. Redundancy really gets under my skin. I mean it; redundancy really irritates me. Plus, I don't much care for redundancy ;)

Cheers,


Creative Commons License


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

#!/bin/bash

#
# rip - Kill any processes that we know have been idle for more than 45 minutes - v2-alpha
#
# 2009 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

if [[ $# -lt 1 ]]
then
echo "Usage: $0 PID [user]"
echo "User defaults to the value"
echo "of \$LOGNAME if not specified"
exit 1
fi

PID=$1
ISITAPID=$(echo $PID | grep [A-z])

if [[ ! -z $ISITAPID ]]
then
echo "PID $1 contains non-numeric characters!"
echo "-----------------------------------"
exit 2
fi

PID="$1"
USER=${2:-$LOGNAME}

PIDTTY=$(/usr/bin/ps -fu $USER -o pid,tty |/usr/bin/grep -w $PID|/usr/bin/grep -v grep)

echo DEBUG::::: PIDTTY $PIDTTY

if [[ -z "$PIDTTY" ]]
then
echo "PID $PID is either non-existent, not owned by \"$USER\" or not attached to a p/tty!"
echo "-----------------------------------"
exit 3
else
TTYNUMBER=$(echo "$PIDTTY"|/usr/bin/sed '/TT/d'|/usr/bin/awk -F"/" '{print $2}')
fi

if [[ -z "$TTYNUMBER" ]]
then
echo "PID $PID is not attached to a p/tty!"
echo "KILL OR NOT-----------------------------------"
exit 4
fi

echo DEBUG::::: W $(w -s|/usr/bin/sed 1d|/usr/bin//awk '{if ( $2 == '"$TTYNUMBER"' ) print $0}')

TIME=$(w -s|/usr/bin/sed 1d|/usr/bin/awk '{if ( $2 == '"$TTYNUMBER"' && NF == 4 ) print $3;else if ( $2 == '"$TTYNUMBER"' && NF == 3) print "0"}')
#TIME=$(w -s|/usr/bin/sed 1d|/usr/bin/awk '{if ( $2 == '"$TTYNUMBER"' ) print $3}')
#WCOLUMNS=$(w -s|/usr/bin/sed 1d|/usr/bin/awk '{if ( NF == 4 ) print "4";else print "3"}')

ISITANUMBER=$(echo $TIME | grep [A-z])
if [[ ! -z $ISITANUMBER ]]
then
unset TIME
fi

LONGTIME=$(echo $ISITANUMBER | grep [A-z])

echo DEBUG::::: LONGTIME $LONGTIME TIME $TIME

if [[ ! -z "$LONGTIME" && -z "$TIME" ]]
then
echo "PID $PID is ancient - Idle for $LONGTIME... Killing $PID"
# KILLKILLKILL
elif [[ "$TIME" = "0" ]]
then
echo "PID $PID is OK - Not Idle At All - Remove this message!"
else
TIMEIDLE=$(echo $TIME|grep -v "[:]")
echo DEBUG::::: TIME $TIME
if [[ -z $TIMEIDLE ]]
then
echo "PID $PID has been idle way too long - $LONGTIME $TIME so far... Killing $PID"
# KILLKILLKILL
elif [[ $TIMEIDLE -gt 45 ]]
then
echo "PID $PID has been idle too long - $TIMEIDLE minutes so far... Killing $PID"
# KILLKILLKILL
else
echo "PID $PID is OK - Only idle for $TIME minute(s) - Remove this message!"
fi
fi
echo "-----------------------------------"


, 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.

Tuesday, August 19, 2008

Finding Running Process ID's On Linux Using Pidof

Hey again,

Today, we're going to take a look at a quirky little command (The use of the term "quirky" is my personal bias creeping in ;) called "pidof" that you can, absolutely, find on RedHat ES versions 4 and up. It's probably on lots of other distro's, too, but I can only afford to muck with what's in the free-server-pool at any given moment. This command is actually very interesting and, given that RHEL3 boasts the "pgrep" command, I was quite surprised when I bumped into it. I'm not sure if it seemed contradictory or complementary; just unexpected.

"pidof," as the name would suggest, is a program that will find the process id (PID) of a running program (or the PID's of programs). Again, just like its name, it finds the "pid of" a running process. I'm just repeating this over and over again because the name is so self explanatory is seems contrary to everything I've come to expect from Linux and Unix (od, bc, dc, nm, ar, etc.. &;-- Literally etcetera. There's no program, that I know of, named etc yet ;)

Normally, I would blow a command like this off and stick with what I know; relegating it to that place in the back of my mind so cluttered with mental detritus that it's bound to all crumble apart sooner or later ;) As luck, or a fate I couldn't possibly avoid, would have it, this command does have some interesting (if not puzzling) features and an even more interesting lineage (skip to the bottom of the post for the most bizarre thing about it ;).

In it's basic form, you use it much like you might use pgrep. For instance:

host # pidof dsmadmc
27937 27927 27921 27918 24324 15596 11970 17360


the output format is somewhat different (horizontal rather than vertical) and more limited, but the results are relatively equal. You've just pulled a list of PID's that have, in this case, the string "dsmadmc" in them. It should be noted that pidof's standard mode of operation is like using "pgrep" with the "-x" option. It only returns exact matches and not substring matches. It should also be noted that, unlike pgrep, you can specify more than one program on the command line without making any major changes. Of course, the output is cryptic enough that this may or may not be a good idea:

host # pidof dsmadmc sshd
27937 27927 27921 27918 24324 15596 11970 17360 20657 20651 31593
host # pidof sshd
20657 20651 31593
<-- As you can see, the PID groups follow each other in order, but you have no way of knowing - at least from the straight output - where the PID's from your first named program stop and the PID's from your next named program begin!

This seems like it would be a great way to line up and knock down zombie processes, but, unfortunately, it won't match them (at least not the ways I tried):

host # ps -efl|grep Z
F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD
4 Z root 20992 20989 0 79 0 - 0 exit 00:00 ? 00:00:00 [sh] <defunct>
host # pidof Z

host # pidof defunct

host # pidof "<defunct>"

host # pidof "[sh]:


...and nothing.

If, for some reason, you only want to return one PID from a pool of them, you can run it with "-s," like so:

host # pidof -s dsmadmc
27937


The only thing I could ascertain from running this option multiple times is that it just picks the first PID from it's normal output when you run it in "single shot" mode. I couldn't make any correlation between start date, run time, child/parent process relationship or anything more complex. It's actually as simple as it seems. I suppose you could use this option if you just needed to make sure that at least one instance of a program was running.

The "-x" option is good for hunting down what shell is running what script. You can usually find this out by backtracing the PID from child to parent and so forth, by running "file" against the script itself or just checking your ps output. In the case where you have a script, showing up in your process table, that doesn't have an obvious point of origin for you to examine, this option is a pretty quick way to figure out the invoking shell. Brownie points to anyone who can tell me why this is a complete waste of time in the example I'm giving here ;)

host # ps -ef|grep "[s]leeper"
user1 28884 20658 0 13:37 pts/0 00:00:00 /bin/bash ./sleeper
<-- It should be noted that this is the ps output from a straight run of a script with a shebang line of: #!/bin/bash.
host # pidof -x sleeper
28884


Generally, that shell won't be hanging around once the shell script stops running. If it doesn't die, there's no way to backward-extrapolate the script it had previously run without prior knowledge.

And finally there's the "-o" option, which let's you "omit" a process, with a certain process id, from your output, like so:

host # pidof -o 30401 dsmadmc
30691 30381 30370 24324 15596 11970 17360


For multiple omissions, you can't just add more PID's, you need to preface each with a -o flag, like so:

host # pidof -o 30401 30691 dsmadmc
30691 30381 30370 24324 15596 11970 17360
<-- The wrong way
host # pidof -o 30401 -o 30691 dsmadmc
30381 30370 24324 15596 11970 17360


The special %PPID descriptor can be used to denote that you want to make sure the parent PID doesn't show up in your output. In this case, it doesn't make any difference:

host # pidof -o %PPID dsmadmc
30691 30401 30381 30370 24324 15596 11970 17360
host # pidof dsmadmc
30691 30401 30381 30370 24324 15596 11970 17360


And, of course, just like pgrep and pkill, it's always best to be as specific as you can when naming the process you want to get the PID of. We noted above that this program is pretty good at making exact matches (no substrings matches - so "ini" won't match "init"), but you can never be too careful. Depending upon the process name, you may end up listing out PID's you didn't intend to (especially since there's no option to show both PID's and process names). For instance, if you went looking for a shell, you'd probably be running a high risk of returning false positives, like this:

host # pidof sshd
20657 20651 31593
host # ps -ef|grep "[s]shd"
root 31593 1 0 Apr11 ? 00:06:22 /usr/sbin/sshd
root 20651 31593 0 12:46 ? 00:00:00 sshd: user1 [priv]
user1 20657 20651 0 12:46 ? 00:00:00 sshd: user1@pts/0


Oh, yes, and that thing I mentioned at the beginning about "pidof" having an interesting lineage. As it turns out, this command is really just a symbolic link to the "killall5" command:

host # ls -l /sbin/pidof
lrwxrwxrwx 1 root system 8 Feb 8 2007 /sbin/pidof -> killall5


The "killall5" program's sole function is to send a signal (take your pick) to all processes except for those within the shell from which it's called. The reason this is interesting (at least to me) is that there is no option to send a signal, of any kind, in "pidof." This seems contrary to my sense of style, but arguments can be made for why this functionality was left out of "pidof." I think probably the most reasonable one is that "pidof" appears to have been written as an output producer only. A program that spits up lines of ordered and spaced numbers with the intention of having them "dealt with" by some other program on the other end of a pipe. Still, it seems a bizarre distinction to make.

But, enough of my belly-aching, "pidof" may be just the thing you're looking for. Who am I to judge? I've been around *nix too long to have a truly "objective" opinion about much of it ;)

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

Friday, May 23, 2008

Using Who To Find What And When On Linux and Unix

Hello again,

Today's post is yet another in a somewhat disjointed series of posts on "stuff you might not know and you might find interesting" regarding very common commands. And they don't get much more common than the "who" command.

Generally, "who" is used like the last command that we looked at in our previous post. It's generally issued at the command line to determine who (yes, it's not just a clever name ;) is logged on "right now," if anyone is at all.

Unlike "last," however, the "who" command has quite a number of options that make it a great troubleshooting, and statistics gathering, command. And, as luck would have it, the four options that we're going to look at today are exactly the same on SUSE Linux 9.x, Solaris 9 Unix and even Solaris 10 :) We'll go through the options from most to least used (in my experience). Not that it matters. We're only looking at four options, so it's going to be hard to get lost ;) All example output will be from SUSE Linux 9.x

1. "who -r" - Prints the current runlevel. This is somewhat similar to the functionality of the last command that we posted about before, but it gives more limited information. This command is excellent for a quick overview of the system's current runlevel, previous state and last state-transition time. For instance, take the following example:

host # who -r
run-level 3 Feb 27 16:06 last=S


This shows us that our system is currently at "run level 3," was in "Single User" mode (S) previous to that, and that the transition from "Single User" to "run level 3" occurred approximately February 27th at 16:06. I say approximately, because (if we look at last's output, as we did in our previous post on using last to its full potential, we could see that this was actually a reboot).

The last state will usually appear as "S" on a reboot, since it's the last recorded state the system is at before it switches to "run level 3" (Of course run level 2 is executed on a normal boot to run level 3). All the information about switching from "run level 3" to "run level 6," and from "run level 6" to "run level S", and all the reboot and shutdown commands are not reported. Again, we don't know the year, but, since this command reads from wtmpx, you can check out a few older posts on user deletion with Perl and the relevant mods for Linux if you want to use Perl to grab that information, as well.

2. "who -b" - Prints the system boot time. Didn't I just get through a really long-winded explanation of all the information missing from "who -r"? ;) Well, here's some of that. This invocation of "who" prints out the last time the system was booted. Note that this doesn't differentiate between a reboot and a power-cycle:

host # who -b
system boot Feb 27 16:06


3. "who -d" - Prints out a list of all the dead processes on your system. This invocation of the who command is really only useful if you're looking for a problem process and can't seem to find it. Generally, you'd use either lsof or ptree/pfiles to find the rogue process, but, if you don't have those (or find them too messy), this command can sometimes help. Mostly though, it's just a listing of processes which are no longer running and still in memory. Note that, for our example below, all of these processes aren't even in the process table anymore!

host # who -d
Feb 27 16:06 2134 id=si term=0 exit=0
Feb 27 16:07 4410 id=l3 term=0 exit=0
pts/2 Apr 14 10:40 24532 id=ts/2 term=0 exit=0
pts/1 May 2 20:29 20407 id=ts/1 term=0 exit=0


4. "who -t" - Prints out the last time the System Clock was changed. Like I mentioned, I saved the least used, and/or obvious, invocation of who for last. You may never have to run the who command with this argument. Still, it's nice to know it's there. As far as I can tell, this setting is not affected by the NTP protocol or any similar software you might have running on your machine (xnptd, etc) to keep the OS clock set correctly. If someone with root (or equivalent) privilege decides to run the "date" command on the server to set an incorrect (or correct) time, this command's output will note it. Unfortunately, it's been a while on the machine I'm using as a test case, and the default output (assuming no change) is nothing. On the bright side, we can be reasonably certain that no one's been goofing with the system clock :)

host # who -t
host #


Enjoy the rest of your day, and have a great Memorial Day weekend ;)

Cheers,

, Mike

Thursday, May 15, 2008

Finding An "Invisible" Proc's Working Directory Without lsof On Linux Or Unix

Ahoy there,

Today, we're going to take a look at something that gets taken for granted a lot these days. lsof (a fine program, to be sure. No debate here) has become a very common staple for finding out information about processes, and where they're hanging out, on most Linux and Unix systems today. Much like the command "top," it provides a simple and robust frontend to having to do a lot of grunt-work to achieve the same results.

I find that, for the most part, lsof is used to find out where a process is, or what filesystems, etc, it's using, in order to troubleshoot issues. One of the most common is the "mysteriously full, yet empty, disk" phenomenon. Every once in a while that will turn out to be an issue where all of the inodes in a partition have been used before all of the blocks have, which produces confusing output in df, leading to the mistaken assumption that there is plenty of space left a device even when there isn't.

However, many times, that empty-yet-full disk is the victim of a process that met an untimely demise and never cleaned up a lot of temporary space in memory (or virtual disk, to split hairs). Another issue that lsof is used for is to find out which dag-nabbed process is holding onto a mount-point that claims it's in use when no one is logged on and no user processes are running that would access it (for instance, a really specific, user-defined, mountpoint like /whereILikeToPutMyStuff - Hopefully the OS isn't depending on this to be around ;) Both problems are, essentially, the same.

However, should you find yourself in a situation where lsof either doesn't come with your Operating System, and/or hasn't been installed, you can still break down these two (and I'm just limiting the post to these two particulars so I don't end up writing an embellished manpage ;) separate issues into one, and find the solution to your problems using the commonly available "pwdx" utility.

pwdx will print out the working directory of any given process (using the process ID as input) at its best. But this is enough to get you to the answer you need.

For instance, we'll take this common scenario: /tmp is reporting 100% full, but df -k shows that /tmp is only at 1% capacity (99% of it is unused). My thinking here almost immediately gravitates toward vi, or some other program that opened up a buffer in memory (using /tmp or /var/tmp), got clipped unexpectedly and never let the system know that it was done with the space it allocated for itself. This would normally not be an issue but, since your Linux or Unix machine "thinks" /tmp is full, whether or not it actually is makes no difference. It won't let you use the free space :(

This command line could be used to figure out what process was using that space in /tmp or /var/tmp:

host # ps -ef|awk '{print $2}'|xargs pwdx 2>&1|grep -iv cannot|grep /tmp
2969: /tmp


Taking it a step further (assuming we trust our own output), we could just skip right to the process in question by adding a bit more to the pipe-chain:

host # ps -ef|awk '{print $2}'|xargs pwdx 2>&1|grep -iv cannot|grep /tmp|sed 's/^\([^:]*\).*$/\1/'|xargs -n1 ps -fp
UID PID PPID C STIME TTY TIME CMD
root 2969 2966 0 Mar 21 ? 0:05 /bin/vi /home/george/myHumungousFile


Since it's May already, we can fairly assume that this PID is pointing to a dead process (especially since it has no TTY associated with it), and (double-checking, just to be sure) we can probably solve our problem by killing that PID. See our previous post on killing zombie processes if it won't seem to go away and "ps -el" shows it in a Z state.

Yes, that example was pretty simplistic, but the same methodology can be used to find other programs using up other filesystems. Just like "lsof -d," you'll be able to find out what processes are using what filesystems and narrow down your list of suspects, if you don't nail the correct one right away. Since pwdx comes with your Linux or Unix OS, it's actually statistically more likely than lsof to be correct about what process is using what filesystem :)

Cheers,

, Mike

Tuesday, May 13, 2008

Killing Zombie Processes In Linux And Unix

Greetings,

Today's post is going to deal with "zombie" processes. These are processes to which the definition of a process only loosely applies.

A zombie process is most often generated when a parent process loses track of its child process and that child process becomes detached. The parent process, generally running some sort of a "wait()" call to receive notification that the child process has exited, loses track of the child process and never receives that information. The child process exits normally, but the parent thinks it's still running, and thus is a zombie process born :)

There are a number of steps to take, from simplest to most obscure, to get rid of zombie processes. And then there's what to do if none of that seems to work. Here we go :)

1. First, identify the fact that you have zombie processes running on your system (you may not notice, and there's a good reason why, which we'll address near the end of this post). You can do this on most major brands of Unix and Linux by running:

host # ps -el|grep Z <--- The -l flag to ps will include the "state" column. The zombie state is represented by a capital Z.

On Solaris 9:

host # ps -el|grep Z

F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 Z 0 3038 1 0 0 - - 0 - ? 0:00
0 Z 0 19769 2966 0 0 - - 0 - ? 0:00


On SUSE Linux 9:

/home/ymdg001# ps -el|grep Z
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 Z 0 476 9874 0 0 - - 0 - ? 0:00


2. Now that you know you have zombie processes running, the first, and easiest, thing you can do to kill them is to try and "assassinate" the actual defunct (zombie) process. For the process in the SUSE example above, you can always try:

host # kill -9 476

It probably won't work, but it's worth a shot. Sometimes it does and your troubles are over just like that :)

3. Next, you should try to kill the parent process. This may or may not be possible for you. For instance, the parent process may be a process that you "need" to have running. It may also be a process that the Operating System "needs" to have running (like "init" - process 1, shown in the Solaris example above, under the PPID column).

Killing the parent process (if possible) will almost always work to get rid of a zombie process.

Please "never" try to kill init (process 1). If you're successful, your machine will go down hard and fast!

4. Assuming none of the above worked, some common wisdom says you should just give up (and for good reason, which we'll get to very soon ;). However you can try killing both the zombie process (and/or the parent process) using signals other than SIGKILL (or -9). I've seen it happen more than a few times. Different programs trap, and/or handle, different signals different ways. If your zombie doesn't go away when you execute a "kill -9" against it, try a simple "kill" (Which is, technically "kill -15" or SIGTERM). You can try to kill the process with any signal you want. I generally try signals 1 - 15 and then SIGUSR1 and SIGUSR2, just in case they're defined differently for that particular program on that particular system. You'd be surprised how many zombies you can whack with a SIGHUP or SIGINT. Sending a kill SIGCHLD or SIGCLD (Which is the same as SIGCHLD on System V) is a good one to try, as well. Sometimes your chosen method won't make "textbook sense" but it will work from time to time :)

You can find a handy list of signals to try in our old post on translating signal names to numbers and vice versa.

5. And the point I've been alluding to throughout this entire post.

What to do if your zombie process just won't die, you can't kill the parent and/or you're otherwise stuck?

The answer is: nothing.

Here's a brief explanation why: Even though zombie processes alarm most casual users of Unix and/or Linux, and they can make the process table look ugly with all those "defunct" messages scattered in between everything else, a zombie process lives up to its name in more ways than the sense defined above. It literally is like the somewhat-living dead. Although the proc table (and filesystem) have space reserved to record it, the process has already exited and is not consuming any of your system resources. It takes up none of your kernel or system space and is only a minor nuisance since "times" keeps track of its time (If you're a fly, you'll notice the 0:00 slow-down ;)

6. But WAIT!

There's more... (I'm starting to sound like a pitch man ;). Here's one last thing you can do if that ps entry for your zombie process is really bugging you: Once the zombie has totally disconnected from its parent process, you can just use the "wait" command to make it go away. For example:

host # ps -el|grep Z
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 Z 0 3038 1 0 0 - - 0 - ? 0:00
host # id
uid=0(root) gid=0(root)
host # wait 3038


...and when that returns (I'd recommend that you run this with "&" to background it - e.g. "wait 3038 &")

host # ps -el|grep Z
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD


It's gone :)

In any event, hopefully, after reading this, you'll no longer worry about zombies :)

Cheers,

, Mike

Friday, April 25, 2008

Determining Signal Definitions In Linux and Unix

Greetings,

Today, we're going to take a quick look at simple return codes (or errno values) that get returned by the bash and ksh shells in Linux (and Solaris Unix). This complements a post we did a while back on trapping signals in Perl and the shell, and adds a bit more to understanding of the fork-and-exec process introduced in our post on running a login shell on a network port.

While these signals are subject to change, the POSIX standard is fairly consistent between most Unix and Linux systems. If you ever need to find out what a signal means, you have a number of options at your disposal to determine that information.

1. At the process level on Solaris, you can figure out what signals are associated with what processes by using the "psig" command. This command will list out all signals associated with a given process (assuming you know its process ID). A sample of this process-finding process would be something like:

host # ps -ef|grep "[l]pd"
daemon 2073 1 0 Mar 21 ? 0:00 /usr/local/sbin/lpd
host # psig 2073
2073: /usr/local/sbin/lpd
HUP caught sigacthandler
...
ILL default
...
PIPE ignored
...


basically, you'll get a ton of output. And none of it may make any sense to you. That's okay for now :)

2. At the process level on Linux, you can get approximately the same functionality from the "crash" command ( used interactively, if available ) or, even better, this publicly available script written specifically to emulate Solaris' psig functionality, for use on Linux. It's called psig.sh for Linux and is an excellent tool for replicating the psig experience for Linux users who are used to Solaris' proc commands.

3. On either Linux or Unix (any flavor), you can determine what signals are handled by your machine, what their names are and what their signal numbers are, by checking your system include files. On Solaris, the header file that contains this information is almost guaranteed to be named /usr/include/sys/iso/signal_iso.h (at least for Solaris 9 and 10). In Linux, it will generally be very specific to the architecture of your build system (something like: /usr/include/asm-x86_64/signal.h)

In any event, you can follow a simple process to figure out where your system's signal definitions are loaded, no matter what flavor of Unix or Linux you're running. It all comes down to derivation and, luckily, you'll always have the same starting point (I may be wrong on this, but I've never experienced it ;).

Here's a quick command line walkthrough of two different ways to figure out where your signal definitions are listed (that is, the include/header file that defines the signal numbers, their abbreviated signal names and definitions) that can be used on almost any *nix system. As a starting point, /usr/include/signal.h is probably the best, since it exists on most systems. We'll also use SIGHUP (the standard HangUp signal and signal number 1) to guide our search:

The painful way:

host # grep SIGHUP /usr/include/signal.h|grep -w 1
host # grep include /usr/include/signal.h
#include <sys/feature_tests.h>
#include <sys/types.h>
...
host # grep include /usr/include/signal.h|sed 's/^.*<\([^>]*\)>/\1/'|xargs -ivar grep SIGHUP /usr/include/var
host # grep include /usr/include/signal.h|sed 's/^.*<\([^>]*\)>/\1/'|xargs -ivar grep "^#include" /usr/include/var|grep sig
#include <sys/iso/signal_iso.h>
#include <sys/siginfo.h>
...


... and so on, and so on, until you find the right file. Basically, just follow the includes until you reach the end. This can be tedious and time consuming.

The incredibly easy way:

Solaris_9_or_10_host # find /usr/include|xargs grep SIGHUP /dev/null|grep -w 1
/usr/include/sys/iso/signal_iso.h:#define SIGHUP 1 /* hangup */
<--- This is our file :)

or

Linux_host # find /usr/include|xargs grep SIGHUP /dev/null|grep -w 1
/usr/include/bits/signum.h:#define SIGHUP 1 /* Hangup (POSIX). */
<--- Note that all 3 of these entries are valid, with this header file being the most generic. Our next command can narrow down the most "specific" correct result.
/usr/include/asm-x86_64/signal.h:#define SIGHUP 1
/usr/include/asm-i386/signal.h:#define SIGHUP 1
Linux_host # uname -pr
2.6.5-7.286-smp x86_64
<--- Now we know that, if we want to be extra sure, the "/usr/include/asm-x86_64/signal.h" is the signal definition file we should be looking at to determine our signal information.

And that's all there is to it :) As an interesting bit of trivia, if you receive an errno value from a process that's higher than 128, you can easily deduce what signal stopped that process. All you need to do is deduct 128 from the return code, like this:

host # sleep 2
host # echo $?
0
host # sleep 200
^C
host # echo $?
130


In this case, when run normally, our sleep command exited with a return code of 0 (success). When we did a control-C during the sleep command, it returned a code of 130. Of course, you won't find this signal number defined in any of your include files, but, utilizing the shell's native reporting of signal interrupts, all you need to do is subtract 128 from 130 and you now know that the sleep command was killed by a signal 2, which is defined as:

SIGINT 2 /* interrupt (rubout) */ <--- on Solaris

and

SIGINT 2 /* Interrupt (ANSI). */ <--- on the Linux box I'm using.

Both answers, although formatted differently, indicate the same signal. Nice :)

Below, I've listed the standard signals for your convenience (from a fairly generic file - signum.h) and take no credit for writing them myself ;)

Enjoy,

Some Basic signals from /usr/include/bits/signum.h on Linux (Note that I'm only listing the basic signals and not I/O polling signals, etc)

#define SIGHUP 1 /* Hangup (POSIX). */
#define SIGINT 2 /* Interrupt (ANSI). */
#define SIGQUIT 3 /* Quit (POSIX). */
#define SIGILL 4 /* Illegal instruction (ANSI). */
#define SIGTRAP 5 /* Trace trap (POSIX). */
#define SIGABRT 6 /* Abort (ANSI). */
#define SIGIOT 6 /* IOT trap (4.2 BSD). */
#define SIGBUS 7 /* BUS error (4.2 BSD). */
#define SIGFPE 8 /* Floating-point exception (ANSI). */
#define SIGKILL 9 /* Kill, unblockable (POSIX). */
#define SIGUSR1 10 /* User-defined signal 1 (POSIX). */
#define SIGSEGV 11 /* Segmentation violation (ANSI). */
#define SIGUSR2 12 /* User-defined signal 2 (POSIX). */
#define SIGPIPE 13 /* Broken pipe (POSIX). */
#define SIGALRM 14 /* Alarm clock (POSIX). */
#define SIGTERM 15 /* Termination (ANSI). */
#define SIGSTKFLT 16 /* Stack fault. */
#define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */
#define SIGCHLD 17 /* Child status has changed (POSIX). */
#define SIGCONT 18 /* Continue (POSIX). */
#define SIGSTOP 19 /* Stop, unblockable (POSIX). */
#define SIGTSTP 20 /* Keyboard stop (POSIX). */
#define SIGTTIN 21 /* Background read from tty (POSIX). */
#define SIGTTOU 22 /* Background write to tty (POSIX). */
#define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */
#define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */
#define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */
#define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */
#define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */
#define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */
#define SIGPOLL SIGIO /* Pollable event occurred (System V). */
#define SIGIO 29 /* I/O now possible (4.2 BSD). */
#define SIGPWR 30 /* Power failure restart (System V). */
#define SIGSYS 31 /* Bad system call. */
#define SIGUNUSED 31
#define _NSIG 65 /* Biggest signal number + 1


, Mike

Saturday, April 5, 2008

Further Dissection Of Paging And Swapping On Linux And Unix

Hey again,

Believe it or not, I actually got a few emails about our previous post on paging and swapping in Linux or Unix because it wasn't specific enough ;) While I can certainly understand the frustration, I was hoping to explain the main differences as completely and concisely as possible. I seem to have faltered a bit on each front: I glossed over two specifics which, I agree, deserve some attention and I wrote yet another novel ;)

With that in mind (and with a prayer that my fingers won't type any more than they have to ;) I'd like to address, and/or clarify, the level of depth I didn't descend to in my last post on the difference between paging and swapping and write about the difference between paging and swapping (The redundancy was intentional and any resulting confusion is expected, given the topic at hand and my writing style ;)

As I mentioned previously, the terms paging and swapping are used almost interchangeably these days. Some industry manuals will actually talk about "swapping out pages" which seems to be contradictory and, theoretically, impossible if swapping and paging are two separate concepts with distinct and unique definitions. This is where language and implied meaning become a barrier to actual definition. And, all the more reason to clarify this one last bit of the puzzle.

And here they come. The extra clarifications...

1. Difference in resident virtual memory management with paging and swapping.
When a system swaps a program, or process, it guarantees that it is resident (on disk or in memory) before it schedules it for execution, and will often hold onto the mapped resources reserved for that process from the time the process requests them until it notifies the scheduler that it is complete. When a system pages during the execution of a program, or process, there isn't any such direct correlation. You don't necessarily know (without specifically checking) how much of a process's virtual memory is resident or whether the process is entirely able to be scheduled for execution at the time paging begins. Pages can be selectively grabbed from a process (out of mapped physical memory) and never returned, unless re-requested by the process when it looks for the memory, can't find it and generates a page fault.

Phew... That's one down. Hopefully this isn't just becoming more confusing :)

2. More specific definition of paging and swapping with regard to page ins/outs and swap ins/outs.
In this instance, swapping specifically refers only to the transfer of memory pages from physical memory to dedicated swap devices or swap disk (on most systems this is now referred to as swapfs - or a unique swap filesystem) and vice versa. Paging, on the other hand, refers to the transfer of memory pages from physical memory to disk (regular disk or swap disk) and vice versa. So, really, the major difference is that swapping is limited to only transferring memory pages back and forth between the physical memory and a dedicated swap device or filesystem, while paging can transfer between physical memory and any sort of disk device.

Hopefully, we've reached a sufficient amount of explanation at this point, and this thing won't turn into the monster I'd hoped it wouldn't become ;)

Thank you, everyone who wrote in, for your helpful input. As many folks have also noted, we don't have comments set up on this blog (because of issues with "comment spam" and not wanting to get shut down). If you ever want to leave a comment, or an objection, we welcome you to email us directly at our most often-check email address or, if you have a lot to say (or want to attach video, etc), sign up (for free) on our sister Linux and Unix Menagerie Forum, and we'll get your remarks there, as well. We do our best to reply, personally, to everyone who takes the time to write us. So far, I think we're still batting a thousand in that regard ;)

Best wishes,

, Mike




Friday, April 4, 2008

Swapping Or Paging On Linux And Unix?

Howdy,

Here's a question that gets asked a lot, and has a relatively simple answer to go with it: On Unix and/or Linux, what's the difference between paging and swapping?

It's a relevant question, given that the terms are used almost interchangeably these days. Even in most Linux or Unix monitoring commands, the issue can become confused. Consider our previous posts on free memory graphing on Unix and graphing out paging statistics on Linux. They're both showing approximately the same thing, but one of them is using the terminology in a not-totally-correct sense.

The good news is you only need to understand one thing about each (which is also a common thread) in order to understand what the terms "really" mean. This can be a great help when you're trying to determine the cause of a system issue, like a big slow-down. Of course, since the terms are mixed up a lot, it's a good rule of thumb to assume that any problem with "paging" or "swapping" may be a problem with either. Depending upon who's asking, they could mean one thing or the other. As in public speaking, it's always a good idea to know your audience ;)

The main difference between paging and swapping (on both Linux and Unix; all flavors, as far as I know) is this:

1. Swapping: This occurs when an entire process ( sometimes consisting of multiple parts like a read-only text segment, writable data segment and, more often nowadays, writable stack segment ) gets transferred to disk from physical memory or is read back into physical memory from the disk.

2. Paging: This occurs when part of a process ( a page, or a segment, of a process ) gets transferred to disk from physical memory or is read back into physical memory from disk. Paging also requires a MMU (Memory Management Unit) and a CPU capable of handling requests from it. This is just a side note, and slightly outside the scope of the definition. It really doesn't even make a difference any more since I haven't seen an OS without paging capability in years, and most dedicated Unix/Linux servers have had the latent capability for even longer.

Tomorrow, we'll begin looking at a real-life examples of determining a system issue highlighted by excessive paging (or is it swapping?). For today, we'll keep it abstract.

To wrap up, on today's system's (The year now being 2008 - Just dating this in case it gets read 2 years from now and I'm totally off-base by then ;) there's almost no such thing as swapping. Paging occurs normally and, if you do see actual heavy swapping, it's generally an indication of a problem with memory or disk (Except in situations where you have large applications - like an Oracle database, for instance - that hoard lots of Virtual Memory Address (VMA) space and cause the system to swap naturally). In somewhat contrast, if your system is paging heavily, but not swapping, your issue is most likely with CPU or memory. Memory is often mistakenly assumed to be the culprit in most situations because both swapping and paging involve writing to, and reading from, memory. However, it should always be taken into account what other component of the OS is doing the work to make that activity possible, or maybe even necessary.

One last thing to remember is that either of these situations ( excessive swapping, excessive paging or both ) could be indicators of either memory, CPU or disk issues. They could also point to a problem with your network subsystem or any number of things. The generic explanations/answers in the previous paragraph assume a relative norm. In reality, you have to look at the situation in the context of the problem you're facing on the system that's having the issue and work from there.

We'll run down some quick and easy real-life troubleshooting starting tomorrow.

Until then, best wishes :)

, Mike




Monday, December 31, 2007

Network Port Querying Script

Hey there,

The script I've put together here was originally written to meet a certain demand. That demand was actually my own, but that's beside the point ;)

This script should come in useful for you if you ever need to query a port and find out what's going on with it (like who's using it and/or what process id is associated with it). It's simple to invoke (taking only the port number as its argument) and produces information that can be a great aid in troubleshooting network connection issues.

If you refer back to this previous post you can check out a small walkthrough regarding how to query a port using lsof and/or the proc commands. This script uses lsof also, but combines it with netstat to produce output in an easy to read format, while grabbing a little more information in the process. Assuming we call it portquery, it can be invoked like this:

host # ./portquery 22 <--- Let's just see what's going on with SSH

and it will produce output for you like the following. Note that it produces a formatted output block for every single process connected to a port. On a high-traffic machine, checking SSH might produce a few pages of output. This is what it looks like when it's run:

Port 22 Information :
Service = sshd
PID = 469
User = root
Protocol = TCP
Status = LISTEN
Port 22 Information :
Service = sshd
PID = 469
User = jimmy88
Protocol = TCP
Status = LISTEN


...and the list goes on to print out information blocks for every PID attached to that port. This script has been a great help for me not only in that it makes a manual process automatic, but also in that it's easy for other non-admins to read.

Here's hoping you have some use for it :)

Best Wishes,


Creative Commons License


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

#!/bin/ksh

#
# 2007 - Mike Golvach - eggi@comcast.net
#
# Usage: portquery [port number]
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

trap 'exit' 1 2 3 9 15
if [ $# -ne 1 ]
then
echo "Usage: $0 portNumber"
exit 1
fi

portnumber=$1

/bin/netstat -a |grep -w "$portnumber" >/dev/null 2>&1

if [ $? -ne 0 ]
then
echo "Nothing's listening on - or using - port $portnumber"
exit 1
fi

/usr/local/bin/lsof 2>&1|grep -v "^lsof:"|grep -w $portnumber 2>&1|while read x
do
portinfo=`echo $x|awk '{print $1 " " $2 " " $3 " " $4 " " $5 " " $6 " " $7 " " $8 " " $9 " " $10}'`
echo "Port $portnumber Information :"
echo " Service = `echo $portinfo|awk '{print $1}'`"
echo " PID = `echo $portinfo|awk '{print $2}'`"
echo " User = `echo $portinfo|awk '{print $3}'`"
echo " Protocol = `echo $portinfo|awk '{print $8}'`"
echo " Status = `echo $portinfo|awk '{print $10}'|sed 's/(//'|sed 's/)//'`"
done



, Mike




Saturday, November 17, 2007

How to Find a Rogue Process That's Hogging a Port

Hey there,

Today's little tip can actually come in useful even if the information you're seeking isn't "mission critical" (which, by the way, ranks among one of my least favorite terms. If there's one thing positive I can say about where I work now, it's that they don't describe every problem, resolution or project as if we were engaged in war -- but that could be an entirely separate post ;).

I've actually been asked to figure out what process was running on what port more often for information's sake than to try and figure out why something was "wrong," but the same principles apply. The scenario is generally something like the following:

Internal customer Bob needs to start (or restart) an application, but it keeps crashing and getting errors about how it can't bind to a port. This port is necessarily vague, since, in my experience, it's very common to be asked to figure something out with little or no information. I consider myself lucky if I have a somewhat-specific description of the problem at the onset. As we all know, folks will sometimes just complain that "the server is broken." What does that mean? ;)

The troubleshooting process here is pretty simple and linear (perhaps more detail and information in a future post regarding similar issues, as any problem or situation can be fluid and not always follow the rules). In order to try and fix Bob's problem, we'll do the following:

1. Double check that the port (We'll use 1647 as a random example) is actually in use by running netstat.

netstat -an|grep 1647|grep LIST

you can leave out the final "grep LIST" if you just want to know if anything is going on on port 1647 at all. Generally the output to look for is in the local address column (Format is generally IP_ADDRESS:PORT - like 192.168.1.45:1647 or *:1647 - depending on your OS the colon may be a dot). Whether or not you're checking for a LISTENing process, information about a connection from your machine on any port to foreign port 1647 shouldn't concern you.

2. We're going to assume that you actually found that the port is either LISTENing, or actively connected to, on your local machine (if it isn't, your troubleshooting would likely take a much different turn at this point). Now we'll try to figure out what process is using that port.

If you have lsof installed on your machine, figuring this out is fairly simple. Just type:

lsof -i :1647

and you should get a dump of the list of processes (or single process) listening on port 1647 (Easily found under the PID column). They're probably all going to be the same, but, if not, take note of all of them.

3. Run sommething along the lines of:

ps -ef|grep PID

and Problem solved! You now know what process is listening on port 1647 and you'll probably end up having to hard kill it if Bob doesn't have any idea why it won't let go of the port using standard methods associated with whatever program is using it.

But, sometimes, the last part isn't that simple, so:

4. What's that? lsof isn't installed on your machine? My first inclination is to recommend that you download it ;) Seriously, it's a valuable tool that you'll find a million uses for. But you can find out the process ID another way, just in case you can't get your hands on it and/or time is of the essence, etc.

In this instance, and we'll just assume the worst, you can use two commands called "ptree" and "pfiles" (these are standard on Solaris in /usr/proc/bin - may be located elsewhere on your OS of choice and/or named somewhat differently). Use the following command to just grab all the information possible and weed it down to the process using port 1647:

for x in `ptree -a | grep -v ptree | awk '{print $1}'`
do
pfiles $x 2>/dev/null|grep 1647
done


and you'll get the line of output that maps your PID to your port. The above is, admittedly, somewhat messy (not really messy, but you'll end up printing a lot of blank lines ;) Feel free to tailor it to your needs and make it more general (I explicitly used port 1647, but that should also be a variable if you want to create a little script to keep in your war chest).

Run your ps, as above, and now you should know what process is hogging that port and, in the process, making Bob's life miserable. If you cleanly kill that process, Bob should have one less thing to worry about and his program should be able to bind to the now-free port :)

, Mike





Tuesday, October 30, 2007

Keeping Grep Out of Your Grep Output

Hello, again,

Most folks who've worked on Linux or Unix before know that when you run a command like:

ps -ef|grep process

You end up, sometimes, with two lines of output. One with the process you're grepping for (if it exists) and one that shows your grep command executing.

Generally, most people I've known do this:

ps -ef|grep process|grep -v grep

While this is perfectly legitimate, you can actually use the shell's builtin functions to achieve the same thing with fewer keystrokes. It's look cooler too :) Do this instead:

ps -ef|grep "[p]rocess"

The big difference here is the thing we're grepping for. Note that it's in quotes and the first letter (although it could be the second, third or whichever) is in square brackets ([]). This will only produce one line of output: The line with the process you're grepping for.

The reason this works is that the shell interprets the character within the square brackets as a "range" (albeit of one character) and effectively strips the brackets when it interprets the command (it's still running your original "grep process"). And the reason it will never match itself is that, in the "ps -ef" output, your literal brackets will still be there and, of course, won't match.

Enjoy :)

, Mike