Linux


I had a Bourne Shell (sh) script I needed to capture the exit status of, but it was being run through “tee” to capture a log file, so “$?” always returned the exit status of “tee”, not the script. In a nutshell, it went something like this:
#!/bin/sh
DO_LOG=$1
LOGNAME="`hostname`.out"
if [ "$DO_LOG" -eq "1" ]; then
# Logging is turned on, so relaunch ourself with logging disabled, and tee the output to the logfile
sh $0 0 | tee $LOGNAME
exit $?
fi
#... Do lots of things in the script
exit $ERRORCODE

Now, the important thing here is that the script sets very specific error codes (we have 16 defined) based on different error states, so that a tool like HP Opsware can give us different reports based on the exit status. When run with “0″ for no logging, this works great, but it requires the controlling tool to capture logs, and not all do (especially cheap “for” loops in a shell script.)

But when run with logging enabled, all of the fancy error code handling (45 lines of subroutines’ worth) gets lost, because “$!” is equal to the status code of the “tee” command. Bash scripters out there will say “but what about $PIPESTATUS ?” If we could use bash, the code would be:
#!/bin/sh
DO_LOG=$1
LOGNAME="`hostname`.out"
if [ "$DO_LOG" -eq "1" ]; then
# Logging is turned on, so relaunch ourself with logging disabled, and tee the output to the logfile
sh $0 0 | tee $LOGNAME
exit ${PIPESTATUS[0]}
fi
#... Do lots of things in the script
exit $ERRORCODE

(Note the single line change in the conditional exit.)

But, I don’t have the luxury of bash (thanks AIX and FreeBSD and Solaris 8), so we needed to get fancy…
#!/bin/sh
DO_LOG=$1
LOGNAME="`hostname`.out"
if [ "$DO_LOG" -eq "1" ]; then
# Logging is turned on, so relaunch ourself with logging disabled, and tee the output to the logfile
cp /dev/null $LOGNAME
tail -f $LOGNAME &
TAILPID=$!
sh $0 0 >> $LOGNAME 2>&1
RETURNCODE=$?
kill TAILPID
exit $RETURNCODE
fi
#... Do lots of things in the script
exit $ERRORCODE

In this last example, we’re creating the empty logfile by copying /dev/null to the logname, then starting a backgrounded “tail” command on the empty file. Because we haven’t disconnected STDOUT in the backgrounding, we will still get the screen output we desire from “tail”. The script now only writes *its* output, with redirected STDOUT and STDERR, to the log file, which is already being tailed to the actual screen. At the end of the script, we capture the true exit code, clean up the tail ugliness, and exit with the desired status code.

This does have a serious downside that if the script encounters and error and exits, the “tail” is left running indefinitely on Linux and Solaris, since the kernel there will simply scavenge the process to be owned by init. So, if you take this method, be very careful to capture all errors you may possibly encounter. Or, just use a better scripting tool. 🙂

Because not enough information exists in easy-to-find searches: as a simple reminder – SCSI device IDs can and will change.

A few months ago I hot-added a new disk to an ssh bastion host (a VM on ESX). As these things tend to go, I eventually took a maintenance window and updated firmware/BIOS/OS on the ESX host. When the bastion VM came back online, however, I was presented with an odd error:

[root@bastion ~]: fsck /dev/sdc1
e2fsck 1.39 (29-May-2006)
fsck.ext3: Device or resource busy while trying to open /dev/sdc1
Filesystem mounted or opened exclusively by another program?
[root@oracle1 ~]# cat /proc/mounts
rootfs / rootfs rw 0 0
/dev/root / ext3 rw,data=ordered 0 0
/dev /dev tmpfs rw 0 0
/proc /proc proc rw 0 0
none /selinux selinuxfs rw 0 0
devpts /dev/pts devpts rw 0 0
tmpfs /dev/shm tmpfs rw 0 0
none /proc/sys/fs/binfmt_misc binfmt_misc rw 0 0
sunrpc /var/lib/nfs/rpc_pipefs rpc_pipefs rw 0 0
[root@oracle1 ~]# cat /etc/fstab
/dev/main/root / ext3 defaults 1 1
/dev/sdc1 /home ext3 defaults 1 2
/dev/main/var /var ext3 defaults 1 2
/dev/main/tmp /tmp ext3 defaults 1 2
LABEL=/boot /boot ext3 defaults 1 2
tmpfs /dev/shm tmpfs defaults 0 0
devpts /dev/pts devpts gid=5,mode=620 0 0
sysfs /sys sysfs defaults 0 0
proc /proc proc defaults 0 0
/dev/main/swap swap swap defaults 0 0
# Beginning of the block added by the VMware software
.host:/ /mnt/hgfs vmhgfs defaults,ttl=5 0 0
# End of the block added by the VMware software

So everything in the fstab is how I left it – /dev/sdc1 is the new disk I added that is giving errors mounting. So I thought to check for corruption on the disk, and found the problem:

[root@oracle1 ~]# fdisk -l
Disk /dev/sda: 42.9 GB, 42949672960 bytes
255 heads, 63 sectors/track, 5221 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Device Boot Start End Blocks Id System
/dev/sda1 * 1 13 104391 83 Linux
/dev/sda2 14 5221 41833260 8e Linux LVM
Disk /dev/sdb: 42.9 GB, 42949672960 bytes
255 heads, 63 sectors/track, 5221 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Device Boot Start End Blocks Id System
/dev/sdb1 1 5221 41937651 83 Linux
Disk /dev/sdc: 32.2 GB, 32212254720 bytes
255 heads, 63 sectors/track, 3916 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Device Boot Start End Blocks Id System
/dev/sdc1 * 1 3917 31457279+ 8e Linux LVM

So, a simple fix – change “/dev/sdc1″ to “/dev/sdb1″ in /etc/fstab (or to VOLUME=home), and boot back up.

It’s not something that’ll probably happen on this server again, but it is something to be aware of, on both VM guests and on physical servers. This is why so many newer Linux OSes are using UUID= or VOLUME= instead of device path for SCSI disks.

It used to be that you could edit /etc/modprobe.d/blacklist and add “blacklist pcspkr” to turn off the console beeps entirely on Ubuntu / Kubuntu.  As of 9.04, the module is now called “snd_pcsp”.

So, to turn off console (not X terminal, but tty) beeps, you can do one of the following:
1) (This is my preference)

echo blacklist snd_pcsp >> /etc/modprobe.d/blacklist.conf

2) (I’ve done this, but it doesn’t affect all software)

for i in 1 2 3 4 5 6
do
setterm -blength 0 > /dev/tty$i
done

3) (Only works per shell if ~/.inputrc is included)

echo set bell-style visible >> ~/.inputrc

Enjoy more-sane editing from ttyX in the future!

I just finished my upgrade from Kubuntu 8.04 to 8.10 this past week (since I had downtime from work, I could afford to break things for a few days).  The upgrade went great, and I’ll write about it shortly, once I get used to the newness.

Anyways; Workstation 6.5 has been giving me problems.  Because of the newness of KDE4, I initially thought it was a KDE problem, but it turns out it’s something between Workstation 6.5 and Ubuntu 8.10.  I just ran the “adapt –dist-upgrade-devel” command from the Ubuntu wiki to upgrade, and upon reboot, I couldn’t “ctrl-alt-ins” or “ctrl-alt-del” to log into my Windows VM, my “Windows/Start” key on the keyboard wouldn’t respond, and my arrow keys wouldn’t work.  Incredibly, when I’d hit the “down” arrow, I’d get the Windows Start menu pop up!!

Fix is easy, edit /etc/vmware/config and add the line below like:

sudo vim /etc/vmware/config
:$
A (that's vi-command for "go to the end of the file, and start writing a new line")
xkeymap.nokeycodeMap = true

Have to restart your VMs for this change to take effect. Thanks to Duncan Epping for this fix (he posted it in the forums, where I found it).

I�m hunting down an issue on Fedora Core 7 where PHP5 can�t send mail using sendmail or postfix. In /var/log/httpd/access_log we are getting sh: /usr/sbin/sendmail: Permission denied every time the mail() function is accessed, and postfix never sees any connection. This is being caused by SELinux blocking Apache from transitioning from the �httpd� role to the �mta� role – I�m just not sure what the *best* way to fix it is yet. I haven�t seen many posts about this, so stay tuned – I expect to have a fix tomorrow afternoon.

« Previous PageNext Page »