Monday, December 1, 2014

Stat - just the facts, ma'am

Stat is a useful tool on Linux that wraps the stat system call to return all available info about a file, and prints it out neatly. I wanted an abbreviated output - just atime, mtime and ctime. Rather than pipe stat's output through something else to strip out the lines I didn't want. I used the stat utility's --printf option to output just the bits I wanted:

$ stat --printf="atime: %x\nmtime: %y\nctime: %z\n" /tmp/testfile
atime: 2014-12-02 09:57:01.890339130 +1100
mtime: 2014-12-02 09:58:31.066781362 +1100
ctime: 2014-12-02 09:58:31.066781362 +1100

Yay for stat (and reading the man page once in a while!)

Wednesday, July 16, 2014

Fun with tar

I had an interesting challenge today: we use an application (Pinnacle) that uses tar files to save a collection of patient files as an archive. How can we tell which tar file contains which patients?

For each patient in the archive, there's a file called "Patient", so I initially started by getting these out and grepping them. Because tar doesn't allow a wildcard operator, you have to first build a list of the files (one per patient) in a sub-shell, then pass it to tar:

tar xfO 20131025_03_HD1.1.tar `tar tf 20131025_03_HD1.1.tar| grep 'Patient$'` | grep -i lastname

Note: you'll need to use gtar if you're on Solaris (on Solaris 10 boxes it's installed at /usr/sfw/bin/gtar) so you can extract the file's contents to STDOUT using xfO (that's a capital letter Oh, not a zero).

However, there's an easier way to manage this. At the start of each tar file, there's a file called Institution which stores header information about the patients contained in this archive file. The section we're interested in looks like this:

  PatientLite ={
    PatientID = 98765;
    PatientPath = "Institution_123/Mount_0/Patient_98765";
    MountPoint = "Mount_0";
    FormattedDescription = "CLAUS&&Santa&&&&098765&&SL&&2013-10-23 11:20:03";
    DirSize = 349.607;
  PatientLite ={
    PatientID = 12345;
    PatientPath = "Institution_123/Mount_0/Patient_12345";
    MountPoint = "Mount_0";
    FormattedDescription = "CHRISTMAS&&Mary&&&&012345&&MAG&&2013-10-23 11:20:14";
    DirSize = 262.177;

OK, so it shouldn't be too hard to get this info:

$ gtar xfO 20131025_03_HD1.1.tar Institution | awk -F'=' '$1 ~ /FormattedDescription/ {print $2}'

 "CLAUS&&Santa&&&&098765&&SL&&2013-10-23 11:20:03";
 "CHRISTMAS&&Mary&&&&012345&&MAG&&2013-10-23 11:20:14";

... clean up those ampersands:

$ gtar xfO 20131025_03_HD1.1.tar Institution | awk -F'=' '$1 ~ /FormattedDescription/ {print $2}' | sed -e 's/&/ /g'

 "CLAUS  Santa    098765  SL  2013-10-23 11:20:03";
 "CHRISTMAS  Mary    012345  MAG  2013-10-23 11:20:14";

Now let's write something to catalog a directory full of these tar files:

$ for TARFILE in *.tar; do echo "Filename: $TARFILE"; (gtar xfO "$TARFILE" Institution | awk -F'=' '$1 ~ /FormattedDescription/ {print $2}' | sed -e 's/&/ /g'); done

Filename: 20131025_03_HD1.1.tar
 "EXAMPLE  Fred    012345  SL  2013-10-23 11:20:03";
 "EG  Robert    123456  MAG  2013-10-23 11:20:14";

Filename: 20131025_04_HD1.1.tar
 "CITIZEN  Jeanette    234567  SL  2013-10-23 11:20:03";
 "ALIAS  Dean    345678  MAG  2013-10-23 11:20:14";

Filename: 20131025_05_HD1.1.tar
 "MANCHU  Fu    456789  SL  2013-10-23 11:20:03";
 "KHAN  Ghengis    567890  MAG  2013-10-23 11:20:14";

Hey presto!

Monday, June 2, 2014

Firefox - running multiple instances

If you've ever logged on to the same host from two different displays and tried to run Firefox, you will probably have seen:

Firefox is already running but is not responding. To open a new window, you must first close the existing Firefox process or restart your system

It's because two instances of the Firefox application are attempting to share ~/.mozilla/firefox/some-default-profile. No matter how many combinations of -no-remote and -new-instance I tried, same problem.

Solution: small shell script that creates a new profile each time (we don't need any bookmarks imported or anything, we just want a simple browser to display an HTML page) then deletes it afterwards:



TEMP_PROFILE=`mktemp -d`
$FIREFOX -CreateProfile "$PROFILE_NAME $TEMP_PROFILE" 2>/dev/null

Tested and working on Linux and Solaris 10. The idea came from here but I couldn't get to the shell script from that post (busted link?) but I figured this was probably what he/she meant :-)

Tuesday, April 22, 2014

What window is that?

Somtimes, in this wonderful Unix-Linux world, I want to know "what is the name of the executable application that popped open that window?" - this is especially helpful on user-friendly Linux distros that try to hide the gory details for the user. For example, what is the name of the application being used to open my PDF file by Nautilus here?

The answer is /usr/bin/evince, but it's not that easy to figure that out, now is it? The trick is to allow the window to open, then use... something... to identify the executable that opened it.

Some good folks came up with a neat answer over here which works pretty well. Use xprop to get the PID of the window, look up /proc/PID/exe and hey presto, you have the name of the executable (in most cases). I slightly adapted the second answer (I like shell aliases!) to come up with this addition to my Linux ~/.bashrc:

alias xident='ls -l /proc/$(xprop _NET_WM_PID | awk "{print \$NF}")/exe | awk "{print \$NF}"'

And for Solaris 10 and 11 we can do similar. There's no /proc/PID/exe, but pargs tells us the name of the executable. Note that this doesn't work in CDE, but does for Java Desktop/Gnome Desktop:

alias xident='pargs $(xprop _NET_WM_PID | awk "{print \$NF}") | awk "\$1 ~ /argv\[0\]/ {print \$2}"'

Sunday, January 26, 2014

Booting sparc? You'll need to talk slower!

Recently, I found myself trying to install Solaris 10 on a Sun Blade 2500, with very little luck. I downloaded sol-10-u11-ga-sparc-dvd.iso, burnt it to DVD on my Linux box, then put the DVD in the sparc machine. Once the openboot PROM screen came up, I'd do this:

{0} ok boot cdrom
Boot device: /yadda/yadda/yadda:f File and args:
Can't read disk label.
Can't open disk label package
ERROR: boot-read fail

I tried almost everything: DVD-R and DVD+R media, a different (but similar model) IDE DVD drive, different IDE cables, different Sun Blade system, swearing and cursing... none of these things helped.

What worked was to burn the DVD at the slowest speed possible. I use K3B so I just set burn speed to 4x, booted from it, and hey presto! All working.

Monday, January 13, 2014

WindowMaker on Ubuntu 12.04, Part 1

Windowmaker was the first "proper" window manager I used on Linux, going back some 15 years ago. Since then, I've tried (and tried to love!) all manner of other window managers: KDE, Gnome, CDE (on Solaris and DEC)... Unity. It was that last one - Unity - that finally pushed me too far. I decided to go back to WindowMaker and see if I could make it workable. And you know what? I love it all over again.

There are a plethora of themes and style available for WindowMaker. In the end, I found myself drawn back to the default theme. Boring, huh? There are awesome themes everywhere out there, and trust me, I've tried a few lot of them in my time. I just like the plain old default :-)

Some things work perfectly

Login is almost instant - less than one second from entering my password till the time I have a usable desktop. That's pretty amazing for a basic business desktop computer with an oldish Core2 CPU.

WindowMaker is simple, stylish and beautifully retro. No desktop icons,  no system tray, no sidebars. Just bare desktop and some dock icons.

The same apps I used under KDE or Unity - they're all still there, and run just fine. Firefox, Thunderbird, gnome-terminal, amarok, gkrellm, nautilus... Getting them all in the menu... well, that took a little tweaking (see below).

Window Shade mode - god, I'd forgotten how much I love that! Double-click an application's title bar and it rolls up out of the way. Double click again and down it comes. It's like window minimising, but I find it far more useful.

Multimedia play/pause/skip keys still control amarok music player! (this I did not expect)

Some things have taken a bit of tweaking.


Screen locking

With small and curious kids in the house, I NEVER leave my desktop unlocked. With KDE, Gnome, Unity, that all automagically works. Not so on WindowMaker, so...

I used to use xlock(more) so I installed it and used it. However I got situations where it would not unlock again. The solution wasn't too hard: CTRL-ALT-F1 to jump to a text console, login and run

kill `ps axwu | grep [x]lock | awk '{print $2}'`

but really, that's not quite elegant. Instead, I followed these instructions to install xscreensaver instead. Then I created the file ~/GNUstep/Library/WindowMaker/autostart and added the following lines:

xscreensaver -nosplash &

You have to make autostart executable (finding that out took me a while!):

chmod u+x  ~/GNUstep/Library/WindowMaker/autostart

Then using WPrefs I edited the "Lock Screen" menu entry so that it reads:

xscreensaver-command -lock

I also configured xscreensaver by starting a terminal, and typing xscreensaver-demo

This allowed me to choose the Matrix screensaver. Hey, if I'm going back to the 90s, surely that's the screensaver of choice!

Some things have taken a fair bit of work to get operational.


Multimedia Volume keys

Under KDE/Gnome/Unity, these keys "automagically" work - in reality, there's an application, probably lurking in the system tray, which receives these keystrokes and adjusts the volume. I tried a few of the existing applets for WindowMaker, but none of them seemed to speak properly to Alsa. However alsa has a command-line client (amixer) which allows you to programatically control volumes. Put this together with xbindkeys to listen to the keystrokes, and hey pesto! (actually, it took a lot of doing, thanks to some buggy behaviour with un-muting Master channels). Here's what worked for me:

Install xbindkeys:

sudo apt-get install xbindkeys

create ~/.xbindkeysrc with these contents:

# (un)mute
"amixer -D pulse set Master toggle"
m:0x0 + c:121
# XF86AudioMute

# volume up
"amixer -c 0 set Master 5+ unmute"
m:0x0 + c:123
# XF86AudioRaiseVolume

# volume down
"amixer -c 0 set Master 5-"
m:0x0 + c:122
# XF86AudioLowerVolume

If these key bindings don't match yours, run xbindkey -k - this will open a window, press a key and you'll get the correct key-code to put in your own ~/.xbindkeysrc. Even more handy hints here. On my travels I also found this absolute corker of a site. Very very useful stuff there.

Run xbindkey and test. You can make xbindkeys re-read its config file with a HUP signal:

kill -HUP $(ps axwu | awk '$11 ~ /xbindkey/ {print $2}')

When your config is working, make sure you start xbindkeys on each login by adding it to ~/GNUstep/Library/WindowMaker/autostart. Don't forget the & at the end of the line. Update: that turns out to be unnecessary - even without that, xbindkeys is automagically running when I log in. It must hook into X when it starts, somehow.

Making volume controls start at preferred settings

Only a minor annoyance, but each time I'd log in to WindowMaker my alsa mixer (volume controls) would be at some semi-random state. Most annoyingly, this meant the internal speaker was on (ick!) and the external speakers weren't. The solution is to run alsamixer, get the controls set as you like them. Then use alsactl to store the settings, and alsactl restore to restore them on login. By default the store command will try to save the settings to /var/lib/alsa/asound.state which is not writable by regular users. You can either sudo to root to save to this file, or create your own asound.state in your home directory and use that. I chose the latter:

alsactl store -f ~/asound.state

Then in ~/GNUstep/Library/WindowMaker/autostart add the following:

alsactl restore -f ~/asound.state &

This approach means you could set up several sound profiles. I think this will come in useful for recording vs. playback, and probably a few other scenarios.

Some things... I still haven't got working to my satisfaction

Actually, having a few weeks off from work has allowed me to fritter away use my time to squash quite a few of the annoyances that I was going to write about in this section.

One that remains is that I still haven't found a The Ultimate Way to generate the Root menu (the menu that appears when you right-click the desktop) - specifically, how to generate a list of all installed applications that you'd want to use. The default one was in the old WindowMaker style, but WMPrefs (the editor that you would use to edit the menu) won't work with that format. So I had to generate a fresh WMRootMenu file in proplist format. I found wmgenmenu did pretty much what I wanted:

cd  ~/GNUstep/Defaults/
mv WMRootMenu WMRootMenu-old
wmgenmenu > WMRootMenu

It wasn't perfect, but it was a good start. I did a few edits to make things as I wanted them. I changed the screensaver/lock option (see above: Screen Locking)

I wanted to easily start up my "Usual Suspects" - a couple of gkrellms (one for localhost, one for the mythtv box) plus Thunderbird and Firefox. But I don't want my desktop startup delayed waiting for them, so I didn't put them in ~/GNUstep/Library/WindowMaker/autostart. Instead I created a small shell script in ~/bin:



gkrellm -s xx.xx.1.202 &

Then using WMPrefs, created a menu item to run that script:

I also added some applications that wmgenmenu didn't pick up automatically (netbeans, for example) and moved a few things around to where I wanted them - no point digging through 5 menu levels for something you use every day. Some really useful Gnome or KDE tools that I manually added or moved were k3b (CD burner), Nautilus (file manager of choice) and palimpsest (disk partition tool).

I also added a program shortcut to start a Windows XP VM: /usr/lib/virtualbox/VirtualBox --comment Windows XP --startvm --no-startvm-errormsgbox

There were definitely other things I did along the way - I might have to do a Part 2 to document them as I think of them. Watch this space.