Friday, August 29, 2014

Copying permissions and ownership of files

One of the big joys I find in working with Linux and Unix systems is that there is always something new I can learn, even with tools I have been using for over 15 years.

Today I have been working for one of my customers on a script that for a bunch of files matching a glob will read each file, process it, and generate some output into a new file.

I need the output files to have the same permissions and ownership as their respective sources, and started to look into different more or less elaborate ways of doing that. But then it turns out that this is a very well solved problem already. Both chmod and chown have an option for this:
--reference=RFILE
              use RFILE's owner and group rather than specifying OWNER:GROUP values

So in my script have added two lines, and now the permissions and ownership are copied onto the new files

    chmod ${DSTDIR}/${LOGFILE} --reference=${LOGFILE}
    chown ${DSTDIR}/${LOGFILE} --reference=${LOGFILE}

I guess these options have been there for years and years, waiting for me:-)


Wednesday, February 8, 2012

Adventures in bash - catching several exit values in a piped set of commands

"All in all, very odd, bash continues to be the most bizarre of languages, convoluted, twisted, but with strange solutions thrown in just when you are about to give up hope entirely." (forum post at Techpatterns)

Yesterday I was re-working a database backup script at one of my customers and stumbled onto a problem when I wanted to have both proper error handling and at the same time avoid filling the disk.

The code providing the challenge was this
          $MYSQLDUMP $MYSQLDUMP_OPTS $DB | gzip -9 > $BACKUP_FILE 
I need to pipe the output of mysqldump to gzip, because otherwise I run into problems with the disk filling up. And yes, having to it like this also means that doing restores are quite a pain, but that is another problem.

Normally I do error handling in scripts by evaluating $?, but to have proper error handling in here I need to capture the exit value of both mysqldump and gzip.  And $? only gives med the exit value of gzip - the least important of the two.

Luckily, and as expected, I'm not the first person to run into this problem, ad by way of googling I found that Bash actually have a built-in way of giving me both exit values - the array $PIPESTATUS. $PIPESTATUS is an array with all the exit values from you last command line. $PIPESTATUS[0] contains the first exit value, $PIPESTATUS[1] the second and so on
sigurdur@ifconfig:~$ true | false
sigurdur@ifconfig:~$ echo ${PIPESTATUS[0]}
0
sigurdur@ifconfig:~$ true | false
sigurdur@ifconfig:~$ echo ${PIPESTATUS[1]}
1
You can also get the entire array
          sigurdur@ifconfig:~$ true | false |false |true
          sigurdur@ifconfig:~$ echo ${PIPESTATUS[@]}
          0 1 1 0
A single, non-piped command is considered to be a "pipe of one", thus leaving you with a $PIPESTATUS array with one value. Since $PIPESTATUS is updated after every command line I had to copy the array before extracting the exit values.
So my code ended up like this:
$MYSQLDUMP $MYSQLDUMP_OPTS $DB | gzip -9
# We want the exit values of both mysqldump and gzip
exitarray=("${PIPESTATUS[@]}")
mydumpexitcode=${exitarray[0]}
gzipexitcode=${exitarray[1]}
PIPESTATUS have probably been part of Bash since forever, but to me it was new - and it solved my problem. Fun stuff:-)

Friday, January 7, 2011

When the radius server came to a grinding halt - and how we brought it back

One of my customers have a few hundred pieces of hardware spread around the country that are authenticated and get their IP addresses from a radius server (http://freeradius.org/) we run. In between the few hundred pieces of hardware and the radius server there is another server that among other things handles the lookups against the radius server  and then gives the clients their connection information.

This have been running for four years with no problems what so ever, handeling a handful or so authentications a minute.

Yesterday the intermediate server suddenly booted (we learned this later), and that led to a need reinitialize the network connections for all the little pieces of hardware (thus authenticating them and looking up their IPs) - all at once. The load on the radius server went through the roof, and we had large amounts of timeouts on the lookups and the radius server came to a grinding halt. Most of the little pieces of hardware didn't get their IP's and the customer's monitoring system went all red and no-one was enjoying them selves much.
A trivial radius server should be able to handle at least a few thousand requests a second, so we were a bit boggled by this. A restart of the service didn't help.

We saw log lines like these in large amounts

Thu Jan  6 15:30:26 2011 : Error: Discarding duplicate request from client FOOFOO3:49910 - ID: 32 due to unfinished request 895
Thu Jan  6 15:30:26 2011 : Error: WARNING: Unresponsive child (id 1314167728) for request 890

The server was also exhausted CPU-wise - and mostly spent it's time in system CPU.
This led me to suspect that the problem was related to some kind of busy waiting on some kind of resource. A quick check in the trusty old /proc filesystem showed that the radius process had a couple of hundred file descriptors pointing to the same file - /var/log/radius/radutmp - an 89MB file with almost 1M short lines.

So what is this radutmp file for? It is updated whenever a client logs in or out, and is used by the command  radwho to see who is logged in at the moment. On this system we have no need for that so I removed the relevant sections from the config and restarted the service - and service was immediately restored.

According to the default and heavily commented config file the radutmp file is not a log file, and does not need to be rotated. But ours have obviously been growing over the last years, so some kind of housekeeping should probably have been done. Out of curiosity I tried starting with an empty radutmp and the original config - and it seemed that the size of the radutmp file affects how hard it is for the server to do it's work  - which makes sense. (but this testing was not done in any way scietifically, and might just be misleading).

I think the main lesson to learn from this is that /proc is your friend - always. Secondary, remove parts of services you don't need - problems might just as well show up there.

Tuesday, November 9, 2010

Quick trick to speed up Firefox (again)

After a few months of use Firefox tends to slow down and spend more and more time doing disk-IO. The reason is that FF uses sqlite for various things like where you have been and what you have filled into forms. These databases get fragmented, and there is no automatic vacuuming of them (but in Thunderbird it seems this is done automagically, go figure).

This have bothered me from time to to me over the last years, and now it happened again. And this time I thought I could write down the quick fix (for lilnux, probably works with Macs too)

  •    stop Firefox
  •    cd into your firefox profile
  •    for i in `find  . -iname \*sqlite`; do echo " -- $i --"; ls -l $i; sqlite3 $i VACUUM; ls -l $i ; echo; done


This reduced places.sqlite from 21 to 3MB, cookies.sqllite almost halved in size, while some of Firefox's own db's remained unchanged.


And most importantly - Firefox feels a lot quicker now:-)