Archive for the ‘Linux/UNIX/Open Source’ Category

AFS file locking with Perl

Tuesday, January 30th, 2007

Recent versions of OpenAFS obey advisory locks. This means that lockf() and fcntl() locking will work properly across the network (flock() will never work since it does not support network filesystems). The historical catch with AFS locking is that attempts to lock a locked file will return EAGAIN in every case, not only in the “try lock” case.

You can use the Fcntl module of Perl to accomplish the locking, but File::lockf (available on CPAN) makes it much simpler if all you need is exclusive locking. The main difference is that lockf will not lock a file that is opened readonly since it only supports exclusive locks. If you need specific reader/writer locks you must use Fcntl instead.

Since lockf won’t function on a file opened readonly, we open read-write, and use O_APPEND and omit O_TRUNC to ensure that we do not accidentally overwrite any part of the file through the file handle used for the locking. You must also ensure that the file’s current position points to 0, otherwise the lock will be placed past the end of the file and be nonfunctional.


use Fcntl ':seek';
use File::lockf;
use IO::File;

my $lockfh = IO::File->new;
#Alternate method:
#sysopen($lockfh, "$fname", O_WRONLY|O_APPEND|O_CREAT) or die "Couldn't open $fname: $!";
$lockfh->open(">>$fname") or die "Couldn't open $fname: $!";
seek $lockfh,0,SEEK_SET or die "Couldn't seek: $!";

my $lock = new File::lockf(\$lockfh);
my $locked = 0;

while (1) {
        my $now_string = localtime;
        if ($lock->tlock == 0) {
                if ($locked) {
                        warn "$now_string: lock on $fname acquired\n";
                }
                last;
        }
        else {
                warn "$now_string: can't immediately write-lock $fname ($!), trying again in 60 seconds...\n";
                $locked++;
                sleep(60);
                next;
        }
        if ($locked > 10) {
                die "$now_string: giving up after $locked tries to lock $fname\n";
        }
}

my $fh = IO::File->new;
$fh->open(">$fname") or die "Couldn't open $fname: $!";

... rest of program here ...

close $fh;
if ($lock->ulock != 0) { warn "Failed to release lock on $fname" };
close $lockfh;
exit 0;


Apache filters, gzip, and WordPress

Sunday, January 28th, 2007

Don’t enable WordPress’s gzip function unless:

  • you have a good reason not to use mod_deflate instead, such as wanting to compress RSS files
  • you are not using any filters of type AF_FTYPE_RESOURCE or higher in the Apache filter chain to modify the HTML afterwards.

As soon as WordPress has gzipped the content, it is impossible for any other filter to modify it. It will also be very easy to forget that you have set this option, and then you will go nuts like me trying to figure out why mod_deflate seems to be invoked so early in the filter chain — when in fact the content is being compressed by PHP itself.

Why can’t I use Kerberos TGT forwarding when SSH’ing from a remote network?

Sunday, January 28th, 2007

A few possibilities:

  • Clock skew. Make sure ntp is installed.
  • OpenSSH versions differ too greatly, install the same version on both ends
  • You do not have both ‘GSSAPIAuthentication yes’ and ‘GSSAPIDelegateCredentials yes’ on the client ssh_config
  • The server does not have a /etc/krb5.keytab containing the key for host/server.fqdn.com
  • The server does not have ‘GSSAPIAuthentication yes’ and ‘GSSAPIKeyExchange yes’ in sshd_config
  • The client has a different reverse-DNS idea of the server’s fully-qualified domain name than the server does. Very common if the server is using a private DNS server but the client is using a public one. In this case, the client needs a ticket for host/server.domain.com but due to the reverse DNS lookup, requests one for host/ipaddr.isp.net instead. Either the same name server needs to be used by both server and client, or client needs to add server to his hosts file.
  • The server has an incorrect ordering on the 127.0.0.1 line in the hosts file. It should be 127.0.0.1 followed by FQDN followed by hostname followed by localhost.

Compiling a Linux kernel with distcc

Thursday, December 14th, 2006

Distcc with different architecture hosts

You may notice some strange problems when using distcc on mixed architecture machines. Especially when one of your machines is amd64 and the other i386. The object code that is output is mixed depending on what the output of gcc on each machine is, because distcc just calls the system gcc. Well, how can we make this more robust? In /usr/lib/distcc, there will be files named with GNU configuration strings such as /usr/lib/distcc/i486-linux-gnu-gcc. If you invoke make with CC=/usr/lib/distcc/i486-linux-gnu-gcc instead of CC=distcc, then distcc will only run this compiler if it exists. So this forces the remote hosts to have a correctly configured compiler for this build or they will reject the requests.

Distcc building a Debian kernel package

Here is how to use distcc to build a Debian kernel package using make-kpkg:

$ DISTCC_HOSTS="localhost remotehost1 remotehost2" CONCURRENCY_LEVEL=4
MAKEFLAGS="CC=/usr/lib/distcc/i486-linux-gnu-gcc" fakeroot make-kpkg \
--revision=1 --bzimage --initrd kernel_image kernel_headers

Comparison of Microsoft Dfs to AFS

Tuesday, December 12th, 2006

Similarities

  • Both DFS and AFS use a volume location server to present many spatially-disparate server volumes in a single tree
  • Both DFS and AFS support strongly encrypted authentication methods

Benefits of DFS compared to AFS

  • DFS has full incremental snapshot capability instead of AFS’s single backup volumes
  • DFS client support is built in and supported by Microsoft on NT-based Windows; the AFS client must be installed and supported separately
  • DFS management tools are built in to Microsoft server operating systems
  • DFS-compatible SAN appliances are readily available
  • DFS has read-write (multi-master) replication and failover; AFS only has read-only replication (though DCE DFS, a derivative of AFS, has read-write replication)
  • DFS volumes can be manually parsed and checked using standard filesystem check tools; AFS uses its own file storage mechanisms (namei and inode) that require the AFS salvager to recovery and verify, and in which files and directories appear as nonsense to someone attempting data recovery

Drawbacks compared to AFS

  • AFS supports Unix-style symbolic links and same-directory hard links
  • AFS has a unified cross-domain namespace (/afs) and standardized AFSDB record to locate servers in other cells
  • AFS encrypts transmitted file data using ‘fcrypt’, a variant of DES
  • AFS employs a local file cache on the client machine; DFS does not, making it infeasible to run applications or directly manipulate data files that are stored on a network volume
  • AFS employs UNIX filesystem semantics with few exceptions (@sys, cross-directory hard links and device files unsupported); DFS employs Windows filesystem semantics, so UNIX applications cannot create case-differentiated file names, create files corresponding to MS-DOS devices (con, aux, prn, lpt[1-9], com[1-9], nul), or create files with reserved characters in the name (such as a colon character)
  • AFS users can create and manage their own ACL groups; DFS ACL groups can only be created by domain administrators

Unix mail tips

Monday, December 4th, 2006

Some hints for using mutt, spamassassin, razor, procmail, formail:

  • To set up razor correctly, run razor-admin -create, razor-admin -discover, and razor-admin -register in that order.  Not doing this will result in a 202 error.
  • When delivering to a maildir or filtering mail with formail or some other stdin/stdout filter that does not otherwise create a file, the procmail recipe does not require a lock colon as in (:0:), only (:0).
  • Automatic expiration of list mail can be done by adding an Expires: header with formail.

http://www.howtoforge.com/procmail_tips_recipes/

How to implement tagged spamassassin reporting in mutt

Reporting each mail as spam individually in mutt is too time consuming because spamassassin must usually contact several servers, some of which may time out, and there may be 20 or more spams in your inbox if you have not paid attention to it for a while.

It is tempting to use mutt’s message tagging feature to tag several messages and send them all to spamassassin at once.


set pipe_split = yes
macro index S "<enter-command>unset wait_key<enter><tag-prefix-cond>
<pipe-message>spamassassin --report<enter><tag-prefix-cond>
<delete-message><enter-command>set wait_key<enter>"

(tag-prefix-cond is a relatively new addition to mutt that aborts execution of the rest of the macro if no messages are tagged.)

The problem with this approach is that the only thing that both mutt produces and that spamassassin can accept is a single message.  Setting pipe_split = yes in muttrc has the intended effect, that spamassassin is invoked once for each message.  But spamassassin is quite slow in this mode because it must establish a new session with each of the spam reporting servers for each piece of mail.  It is possible to background spamassassin, but without some form of external serialization, many spamassassins will be started at once, overloading the VM and competing for the write lock on the user’s Bayesian database.

Setting pipe_split = no (the default) causes mutt to concatenate all of the messages and pipe them to the program once.  But spamassassin can’t accept this input since it is not in a format that spamassassin recognizes.  Since spamassassin can accept an mbox as input, it is tempting to use something like

pipe_sep = "From abuse@localhost\n"

to emulate a mbox output.  But the first message is ignored by spamassassin, because no separator is placed at the top of the output.
This last problem can be addressed with a script like the following (mutt-sa-report).  It adds a From_ line at the beginning of mutt’s output.  After processing with this script, mutt’s piped output is now a mbox that spamassassin can recognize:


#!/usr/bin/perl --
use warnings;
use strict;
use File::Temp qw/tempfile/;
use Fcntl qw/SEEK_SET/; 
my $fh = tempfile;
my $back = "From abuse@localhost\n";
while (<STDIN>) { print $fh $back; $back = $_; }
seek $fh,0,SEEK_SET;
open my $sa, "| spamassassin --mbox --report" or die "Couldn't exec spamassassin ";
while (<$fh>) { print $sa $_; }
close $sa;
close $fh;
exit 0;

Now, this script can be called from mutt:


pipe_split = no
macro index S "<enter-command>unset wait_key<enter><tag-prefix-cond>
<pipe-message>mutt-sa-report >>/home/nemesis/Mail/logfile 2>&1<enter>
<tag-prefix-cond><delete-message><enter-command>set wait_key<enter>"

Look in logfile for the output of spamassassin. You should see “15 messages examined” or something to that effect. If so, it is working and you can remove everything but mutt-sa-report in between the pipe-message and enter tags.

cdrtools

Friday, December 1st, 2006

cdrtools/cdrecord: The original cdrecord by Schilling. Was released under GPL, later combined with CDDL build tools to render it undistributable due to contributed GPL code. After Schilling obtained permission from contributors to distribute with CDDL build tools, then cdrecord is changed to use the library libscg (under CDDL) itself. This is undistributable in any case.
cdrecord-ProDVD: The cdrecord with DVD burning capabilities. Binary only with a 6 month license renewal. Some parts open sourced in 5/06?

dvdrtools: Fork of cdrtools by Bero to support DVD burners.

growisofs: Rewritten DVD-only burning software.

cdrkit: Fork of pre-CDDL cdrecord, using cmake build system.

wodim: The new derived cdrecord replacement in cdrkit.

Linux 2.6 SCSI/ATAPI support has been spotty and the various cdrecords floating around that distributions pinned to older versions due to the license change has not helped. cdrkit/wodim should support the Linux 2.6 ATAPI interface correctly (as well as latest versions of cdrtools). ossdvd is another project to support Linux 2.6 with a forked cdrecord.

Dealing with some OpenAFS issues

Tuesday, November 14th, 2006

Some OpenAFS versions less than 1.4.1 have a bug in the fileserver that will cause tokens to be randomly discarded. The fix is to make sure the fileserver is at least 1.4.1.

Some previous OpenAFS versions allowed a principal with a ‘.’ (period) in the name. This no longer works. The symptom of this will be that you are able to obtain a token, but any operation on the filesystem that requires authentication will result in a short hang and the token is then discarded. The fix is to rename all such principals with a different character such as an underscore to replace the periods.

OpenAFS and Linux 2.6 have some issues with PAG support still. In my case, this manifested as an authenticated shell process that forks and calls another shell process will result in the child process having no tokens. Strangely, a shell process that runs other system programs that are not shells, such as ‘mv’, ‘rm’, etc, will succeed. So to work around this, convert your maintenance shell scripts that run authenticated to “source” each other with a . (dot) rather than to call each other. This will require some changes in error/exit handling but completely worked around the PAG issue here.

Sometimes you might notice your OpenAFS fileserver periodically restarting, with no cron job to explain it.  The culprit is the bos setrestart command.  By default, the fileserver restarts at 4:00am every Sunday, and at 5:00am every day if new binaries are detected.
To disable the periodic restart, issue the following command:
# bos setrestart server.domain.com -time never

coLinux adventures

Thursday, November 2nd, 2006

This is the best way to setup CoLinux networking, because it has a high speed TAP interface for the local X server traffic, and only uses WinPCap for external traffic. It also does not require Internet Connection Sharing to be enabled because WinPCap creates a virtual network adapter on top of the existing one.

Note that this will only work if your local X server can accept connections from 192.168.x.x, some commercial X servers have a license scheme limiting the IP range. If yours does, you can assign IP addresses within that rang (more…)