Recently in Linux/Unix Category

Shock! Horror! Bug found where Windows applications will open DLLs that are in the current working directory of a process!

Except it's not a bug. It's by design, and it's existed since NT.

Microsoft is being smacked in the head by a required feature of Windows due to the initial weakness of the LoadLibrary call. If you don't specify a path to the file to load, it uses the standard library search path.

Dear god, you would think that this was news. It is not news, nor has it been since the goddamned operating system shipped. Granted, the issue is severe, but the fact of the matter is if an application is executed using a working directory that isn't under your control, then what can you do? if there are libraries in the same directory that launched the program that happen to share the name of system libraries then you're hosed.

Hey, guess what asshole, if you link a linux binary with a search path containing '.', then you get the same problem. It's just as well that nobody links their binaries with -R. .... eh?

The documentation is blatant in this regard. I've known it was a security issue since I first learned of the LoadLibrary call, as any even half decent developer should have known when they started using the damned function.

The rule is simple. Resolve the full path to a library before you load it. Validate that it 'looks right' at that point. Then load it.

BTW .init section in .so files - so totally a security hole. You can't dlopen a file to determine if it's good without executing the .init code. Game over man, game f**king over!

My .init code does a setenv("LD_LIBRARY_PATH", "." + getenv("LD_LIBRARY_PATH")) ... now piss off and write secure code for once...

Well I had a minor hiccup today when I decided it was 'password change day'. I duly went around changing the password on all my systems. Then I got back to work. 10 minutes later I turned to my other system and typed in the password.
... It didn't work ...
I smacked my head and said to myself "D'oh", I need to use the new password. But I couldn't remember all of it. All I had was a few characters I could remember and the fact that my mail program was checking the mail every few minutes and still working.

First I got the pid of thunderbird...

~% ps -fe | grep thunder
1000     17509     1  0 13:19 ?        00:00:00 /bin/sh /usr/bin/thunderbird
1000     17521 17509  0 13:19 ?        00:00:00 /bin/sh /usr/lib/thunderbird/run-mozilla.sh /usr/lib/thunderbird/thunderbird-bin
1000     17526 17521  0 13:19 ?        00:00:24 /usr/lib/thunderbird/thunderbird-bin
1000     19101 19006  0 14:09 pts/10   00:00:00 grep thunder

Then I got the address of the heap from the process' maps

~% grep 'heap' /proc/17526/maps
08d02000-0a9ad000 rw-p 08d02000 00:00 0          [heap]

I compiled up memory_dumper, and ran it against the process and heap addresses listed.

% ./memory_dumper 08d02000 0a46a000 17526 heap

Then I ran strings on the resulting file, looking for the pattern that matched my remembered password

% strings heap | grep t%7
cheat%7Ladel
cheat%7Ladel
cheat%7Ladel
cheat%7Ladel
%

4 copies of the password in memory in the program. That is just in-freaking-sane. It should be present in the program only once, and should probably be concealed using some form of obfuscation. Mind you, it has kept the new password in my mind now, so I should be grateful.

And just in case you feel like trying the password listed, don't. It's not the real password ;)

Nothing more than a rant....
It's not that tough - when using most english locales, we sort case insensitively. a==A, B==B and so on. Pragmatically, the only reason for picking a locale other than UTF-8.generic is because I would really, really like these rules obeyed.
I am sick to death of having to work around stupidity.
I'm just complaining as I look at the output from ls and it's pretty much a case sensitive sort. I'm sure that accents are sorted correctly in EN_ie - after all á is the same as a, but apparently it's different to A.
Sorting it difficult... the rules are so complicated... stop complaining! you're able to perform at least 600 million operations per second, and a table lookup for a case insensitive sort is probably going to cost 20.
Bear in mind that the number above was a quick back of the envelope number of an iPhone. I'm sure a real computer will be able to do something a little better...

Update:

Looks like it's not Linux, it's only Leopard that doesn't understand EN_ie collation. Oh well, that's life I suppose…

URL shortening...

| No Comments | No TrackBacks
Not a lot of code. We create a rewrite rule for apache to remap any 5 character requests at root to this script.
RewriteRule ^/([A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9])$ /cgi-bin/shorten.cgi?$1 [PT].
Requests for http://site/..... lookup the entry in the database, requests to shorten.cgi?URL return the shortened uri in a text/plain output when it works.
There isn't a lot of checking, and you probably need to create the db/ directory with mode 777 so you can update the database under cgi, but it... works on my box ;)
#!/usr/bin/perl -w
# shorten or unshorten a url passed in
use strict;
use DBI;
use Sys::Hostname;

my %keys;
my $value=0;
# 26 + 26 + 10 = 62
my $keys = join("", 'A'..'Z') . join("", 'a'..'z') . join("", '0'..'9');
my @keys = split(//, $keys);
for my $i (@keys) {
    $keys{$i} = $value++;
}

my $file = "shorten.db";
my $dir;
my $var;

if (defined($ENV{'SCRIPT_FILENAME'})) {
    $var = $ENV{'SCRIPT_FILENAME'};
} else {
    $var = $0;
}

($dir) = $var =~ m/(.*)\/[^\/]+/;

$file = $dir . "/db/" . $file;

if (! -d $dir . "/db") {
    mkdir($dir . "/db", 0777);
    chmod(0777, $dir . "/db");
}

my $dbh = DBI->connect("dbi:SQLite:dbname=$file", "", "") || die "Could not open $file";
chmod(0666, $file);

$dbh->do("create table if not exists mapping (id INTEGER PRIMARY KEY, url TEXT)");
$dbh->do("create index if not exists mappurl on mapping(url)");

exit(0) if (!defined($ENV{'QUERY_STRING'}));
my $qs = $ENV{'QUERY_STRING'};

if (length($qs) == 5) { # from short -> long
    my $key = 0;
    map { $key = $key * 62 + $keys{$_} } split(//, $qs);
    my $ary = $dbh->selectall_arrayref("select url from mapping where id = $key");
    if ($ary) {
        my @ary=@$ary;
        print "Location: " . $ary[0][0] . "\n\n";
    }
} else {
    my $sth = $dbh->prepare("select id from mapping where url = ?");
    my $ret = $sth->execute($qs);
    die "Failed to execute " . $sth->errstr unless($ret);
    my @row = $sth->fetchrow_array();
    my $value;
    if (!@row) {
        $sth = $dbh->prepare("insert or replace into mapping (url) values (?)");
        $sth->execute($qs) or die "Failed to insert" . $sth->errstr;
        $value = $dbh->last_insert_id("","","","");
    } else {
        $value = $row[0];
    }
    if (defined($value) && ($value > 0)) {
        my $op = "";
        while(length($op) != 5) {
            $op = $keys[$value % 62] . $op;
            $value /= 62;
        }
        my $base;
        if (!defined($ENV{'HTTP_HOST'})) {
            $base = hostname();
        } else {
            $base = $ENV{'HTTP_HOST'};
        }
        print "Content-Type: text/plain\n\nhttp://" . $base . "/" . $op . "\n";
    } else {
        print "Content-Type: text/plain\n\nFailed to shorten $qs.";
        exit(0);
    }
}

# vim: ts=4:sw=4:et
Unlike my default shell (zsh), bash has a wonderful feature where it doesn't keep variables that are set at the other end of a pipe, so for example:
i=
cat foo | while read bar; do
    i=$bar
done
echo $i

Yields an empty line. I've been stung once or twice on this as I prototype the code initially in an interactive shell, which doesn't exhibit the issue.
The simplest solution is to use a named pipe.

i=
mkfifo /tmp/foo$$
cat foo >/tmp/foo$$&
pid=$!
while read bar; do
    i=$bar
done </tmp/foo$$

This gives the last line of the file in the i variable.
So there I am looking at the sysinfo from a particular machine and I look at the content of the procs field. It looked to be a bit out. Went hunting through the kernel source and noticed that the procs field is filled with the value of the number of threads in the system. This is a little bit odd, as I'm used to separating my threads from my processes.
Turns out that there is an nr_processes() call, which returns the number of processes in the system, rather than the number of threads. A little bit of a change, rebuild and testing now gives me the correct number of processes from the proc field, and I also have a separate result for the number of threads.
There we go, much more sensible ;)
diff -Naur linux-2.6.25.18/include/linux/kernel.h linux-2.6.25.18.new/include/linux/kernel.h
--- linux-2.6.25.18/include/linux/kernel.h      2008-10-09 03:58:32.000000000 +0100
+++ linux-2.6.25.18.new/include/linux/kernel.h  2009-03-16 16:23:39.000000000 +0000
@@ -415,7 +415,8 @@
        unsigned long totalhigh;        /* Total high memory size */
        unsigned long freehigh;         /* Available high memory size */
        unsigned int mem_unit;          /* Memory unit size in bytes */
-       char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
+       unsigned int threads;           /* Number of current threads */
+       char _f[20-2*sizeof(long)-2*sizeof(int)];       /* Padding: libc5 uses this.. */
 };
 
 /* Force a compilation error if condition is true */
diff -Naur linux-2.6.25.18/kernel/compat.c linux-2.6.25.18.new/kernel/compat.c
--- linux-2.6.25.18/kernel/compat.c     2008-10-09 03:58:32.000000000 +0100
+++ linux-2.6.25.18.new/kernel/compat.c 2009-03-16 16:43:31.000000000 +0000
@@ -1031,7 +1031,8 @@
        u32 totalhigh;
        u32 freehigh;
        u32 mem_unit;
-       char _f[20-2*sizeof(u32)-sizeof(int)];
+       u32 threads;
+       char _f[20-2*sizeof(u32)-2*sizeof(int)];
 };
 
 asmlinkage long
@@ -1076,7 +1077,8 @@
            __put_user (s.procs, &info->procs) ||
            __put_user (s.totalhigh, &info->totalhigh) ||
            __put_user (s.freehigh, &info->freehigh) ||
-           __put_user (s.mem_unit, &info->mem_unit))
+           __put_user (s.mem_unit, &info->mem_unit) ||
+           __put_user (s.threads, &info->threads))
                return -EFAULT;
 
        return 0;
diff -Naur linux-2.6.25.18/kernel/timer.c linux-2.6.25.18.new/kernel/timer.c
--- linux-2.6.25.18/kernel/timer.c      2008-10-09 03:58:32.000000000 +0100
+++ linux-2.6.25.18.new/kernel/timer.c  2009-03-16 16:20:02.000000000 +0000
@@ -37,6 +37,7 @@
 #include <linux/delay.h>
 #include <linux/tick.h>
 #include <linux/kallsyms.h>
+#include <linux/sched.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -1166,7 +1167,8 @@
                info->loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
                info->loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT);
 
-               info->procs = nr_threads;
+               info->procs = nr_processes();
+               info->threads = nr_threads;
        } while (read_seqretry(&xtime_lock, seq));
 
        si_meminfo(info);

The Full patch.
I've been testing the resizing of the drives located on a Dell MD3000, and i've seen errors when resizing after the 2TB mark. This is on the new firmware which supports > 2TB logical drives. I wrote a script to write to random locations of a block device. It can then read them back and verify that they're still the same as what was written. Rather than writing to the entire device I use random sampling, with a few fixed points on the block device. I pretty much get consistent failures. If I put in the failed locations into the next write run they come out again in the subsequent run. Kind of makes resizing a dangerous operation, even though it is stated that resizing is non-destructive.
I realize that the array is nothing more than a rebrand of another device, but it would be great if it was tested in a lab before something this bad got out to the customers.
#! /usr/bin/perl -w

use strict;
use Getopt::Long;
use Digest::MD5 qw(md5_hex);
use File::Basename;

my $fs;
my $readfile;
my $writefile;

my $numpatterns = 2048;
my $seed = undef;
my $size;
my $real_size;
my $help;

my %vars;
my @def_offsets = (0);

sub usage($) {
        print <<EOM;
Usage: $0 --fs=<filesystem> --read=<file>|--write=<file>
        [--num=<number of blocks>] [--offset=<offset to test>]
        [--seed=<random number seed>]
EOM
        exit ($_[0]);
}

my $result = GetOptions( 'fs=s' => \$fs,
        'num=i' => \$numpatterns,
        'seed=i' => \$seed,
        'read=s' => \$readfile,
        'offset=i' => \@def_offsets,
        'write=s' => \$writefile,
        'h|help' => \$help);

usage(0) if defined($help);
warn "Need file system to use" if (!defined($fs));
warn "Need either a read or write file" if (!(defined($readfile) || defined($writefile)));

usage (1) if (!defined($fs) || !(defined($readfile) || defined($writefile)));
my $base = basename($fs);

open (IN, "</proc/partitions") || die "Could not load partition tables";
while (<IN>) {
        chomp();
        my ($major, $minor, $blocks, $name) = m/(\w*)\s+(\w*)\s+(\w*)\s+(\w*)$/;
        next if (!defined($major));
        if ($name eq $base) {
                $real_size = $blocks;
                last;
        }
}
close(IN);

die "Could not get size" if (!defined($real_size));

# Write to the offset in blocks
sub write_to_offset($$) {
        my ($offset, $buffer) = @_;
        sysseek(INFS, $offset * 1024, 0);
        my $write = syswrite(INFS, $buffer, 1024);
        if (!defined($write) || $write != 1024) {
                warn "Failed to write: $offset $!\n";
        } else {
                $vars{$offset} = md5_hex($buffer);
        }
}

sub read_from_offset($) {
        my ($offset) = @_;
        my $buffer;
        sysseek(INFS, $offset * 1024, 0);
        my $read = sysread(INFS, $buffer, 1024);
        if (!defined($read) || $read != 1024) {
                warn "Could not read 1024 bytes at $offset $!";
                return (1);
        }
        if (md5_hex($buffer) ne $vars{$offset}) {
                warn "Data at offset $offset was not the same as expected";
                return (1);
        }
        return (0);
}

sub get_buffer {
        my $i = 0;
        my $buffer = "";
        while ($i++ < 256) {
                my $randval = int(rand(255 * 255 * 255 * 255));
                $buffer .= chr($randval >> 24) . chr(($randval >> 16) & 255) .
                        chr(($randval >> 8) & 255) . chr($randval & 255);
        }
        (length($buffer) == 1024) || die "Buffer was " . length($buffer);
        return $buffer;
}

if (defined($readfile)) {
        # reading from previous file
        open (INPUT, "<$readfile") || die "Could not open previous run log";
        while(<INPUT>) {
                chomp();
                my ($key, $value) = m/(.*)=(.*)/;
                if ($key eq "patterncount") {
                        $numpatterns = $value;
                        next;
                }
                if ($key eq "size") {
                        $size = $value;
                        next;
                }
                if ($key eq "seed") {
                        $seed = $value;
                        next;
                }
                $vars{$key} = $value;
        }
        close(INPUT);
} else {
        $seed = time ^ $$ ^ unpack "%L*", `ls -l /proc/ | gzip -f` if (!defined($seed));
        $size = $real_size if (!defined($size));
        open (OUTPUT, ">$writefile") || die "Could not open new run log";
        print OUTPUT "patterncount=$numpatterns\n" .
                "size=$size\n" .
                "seed=$seed\n";
}

print "Size: $real_size [$size] Seed: $seed\n";
srand($seed);

my $mode = "<";
$mode = "+<" if ($writefile);
open(INFS, "$mode$fs") || die "Could not open raw device";

if ($writefile) {
        map { write_to_offset($_, get_buffer()) } @def_offsets;
        write_to_offset($size - 1, get_buffer());
        while($numpatterns > 0) {
                my $offset = int(rand($size));
                print "Writing pattern: $numpatterns           \r";
                next if defined($vars{$offset});
                write_to_offset($offset, get_buffer());
                $numpatterns--;
        }
        map { print OUTPUT "$_=" . $vars{$_} . "\n" } keys(%vars);
        close(OUTPUT);
} else {
        my $failcount = 0;
        my $tocount = scalar(keys(%vars));
        map { $failcount += read_from_offset($_); printf("To Count: %0.7d\r", $tocount--); } sort(keys(%vars));
        print "Count difference: $failcount\n";
}

consistency.pl.txt

signal versus sigaction

| No Comments | No TrackBacks
the use of the
signal(int signum, void (*handler)(int))
is a smidgin dangerous on various operating systems. Under Solaris, for example once the signal has been delivered to the process the signal handler is reset, so a typical piece of code that wants to reuse the signal handler repeatedly will typically set the signal handler again when receiving the signal. This leads to a minor race condition where upon receipt of the signal and the re-setting of the handler the process receives another copy of the same signal. Some of these signals cause Bad things to happen - such as the stopping of the process (SIGTSTP for example). Under Linux it keeps the signal handler in place, so you have no fear of the event triggering an unwanted event.
The manual page for
signal
under Linux makes it clear that the call is deprecated in favour of the much more functional
sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact)
call, which keeps signal handlers in place when you don't pass the SA_RESETHAND parameter as part of the sa_flags parameter of the sigaction structure. So you get to explicitly choose to accept a signal once, and then have the system deal with it in the default manner afterwards.
Signals, are of course a real pain in the ass when dealing with sub-processes. For example the use of ptrace to perform profiling works well until you fork. If another SIGPROF signal arrives before you can create your signal handler then the child process is terminated as that's the default behaviour in that situation.
Under Solaris (and Leopard) you can make use of dtrace to perform profiling on a set of processes without needing to deal with vagaries of signal handling, making this a non-issue. For those of you stuck in LD_PRELOAD land, probably the only thing that can be done is to set the signal disposition to be ignored before execing the new process. you have a small window where the profiling is missing, but the overall increased stability of the application is improved by preventing it from accidentally being terminated due to a profiling signal being received too soon. I know the accuracy nuts would hate that, but it's part of the price of dealing with standards.
#!/bin/bash -p

if [ $# -eq 0 ]; then
    echo "Usage: $(basename $0) " 1>&2
    exit 1
fi

while [ -d /proc/$1 ]; do sleep 0.5; done
If I implemented it using inotify, I presume I can get rid of the sleep, but that entails compiled code.
Not really stated anywhere obvious, but apparently Xgl isn't the preferred mechanism for all the special effects in Xorg post 7.1, it's AIGLX that you should be using. It's integrated too :)
So after wasting a lot of time trying to get the nvidia driver working properly with XGL after the latest updates I just searched the docs here, there and everywhere and finally picked up on the 'just use AIGLX' vibe.
Maybe I should be reading the release notes... or are they in the release notes at all? I managed to survive gutsy and hardy without changing over to AIGLX and it still worked, so I may just have missed this in the notes somewhere.
Sitting in the Galway Hooker bar, having a pint waiting until my train starts boarding.
Using an Acer Aspire One laptop, running Ubuntu Intrepid Ibex and my USB 3g data dongle.
It's actually usable. It may be small, but it's cabable.
Oh, and it looks like my train is boarding. At least I have a seat reserved so I don't need to queue with the other folks.
Aargh, it's too bloody easy to rip off these tabs and there's no way to re-attach them from what I can tell. Something about the sensitivity pop-up menus and the tab drag thing has been tuned up. It's practically impossible to keep a pop-up menu open using a two-fingered click (touchpad).
Every time I rip-off a tab it makes me want to throw gnome out the window. the UI seems to have become more and more of a crayon interface without actually improving.
Tabs. A logical option for grouping works on different projects. Apparently, you're supposed to use multiple windows in a desktop.
Busybox is pretty much essential if you're using a small, embedded linux. It's small footprint and complete replication of most of coreutils (and a bunch of other packages) makes it great. All you end up with are a bunch of symlinks.
The problem is, though, that pretty much all the commands are 'slightly different'. They don't take long options. Help is not helpful (I've regularly had to look at the source to tell what's the problem).
The real problem comes when you decide you want to rip it out of your system. All those minor things that had to be changed to work under the busybox system now have to be re-checked under coreutils and family.
Fun for all the family.
It's great. simply prettier and a lot more usable than Firefox 2. The awesome bar (the address bar) kicks ass. Much easier to use than the previous one. Bookmark management has been improved. The look and feel is nicer. I even 'kind of' prefer the subtle dialog box improvement which turns up at the top of the form, which is like a wide series of websites that perform the same thing themselves.
This definitely has replaced my web browsers in Windows and Linux. There's a very high chance that it will replace Safari on the Mac. The only niggle I have is that it doesn't store your passwords in the Mac keychain, which I still feel is the better place to have them.
Damn the electric fence...
For Linux and the mac, it means that the file has an ACL associated with the file.
~% ls -ld .
drwx--x--x 163 pshanahan pshanahan 12288 2008-06-16 16:26 .
~% setfacl -m user:postfix:rx .
~% ls -ld .                    
drwxr-x--x+ 163 pshanahan pshanahan 12288 2008-06-16 16:26 .
On the Mac if you see an '@' sign where the plus(+) is, then it indicates that there's extended attribute information. If you've got a version of ls that supports extended attributes (takes the -@ option), you should see the same thing in Linux.
Well linux and solaris get it correct, but it looks like the little old mac can't sort things lexicographically (even when it claims in the manpage that it does).
On Linux/Solaris:
~/x% locale
LANG=en_IE.UTF-8
LC_CTYPE="en_IE.UTF-8"
LC_NUMERIC="en_IE.UTF-8"
LC_TIME="en_IE.UTF-8"
LC_COLLATE="en_IE.UTF-8"
LC_MONETARY="en_IE.UTF-8"
LC_MESSAGES="en_IE.UTF-8"
LC_PAPER="en_IE.UTF-8"
LC_NAME="en_IE.UTF-8"
LC_ADDRESS="en_IE.UTF-8"
LC_TELEPHONE="en_IE.UTF-8"
LC_MEASUREMENT="en_IE.UTF-8"
LC_IDENTIFICATION="en_IE.UTF-8"
LC_ALL=
~/x% ls
a  B  c
On the Mac:
himitsu:~/x% locale
LANG="en_IE.UTF-8"
LC_COLLATE="C"
LC_CTYPE="en_IE.UTF-8"
LC_MESSAGES="en_IE.UTF-8"
LC_MONETARY="en_IE.UTF-8"
LC_NUMERIC="en_IE.UTF-8"
LC_TIME="en_IE.UTF-8"
LC_ALL=
himitsu:~/x% ls
B  a  c
According to the spec:
The following environment variables shall affect the execution of ls ...
LC_COLLATE
Determine the locale for character collation information in determining the pathname collation sequence.
Sad little mac does not sort by the locale's character collation specification (case insensitive, in case you missed it).

typedef long time_t;

| 1 Comment | No TrackBacks
There isn't a lot of time before this evil, evil signed long value goes negative. It should make a good retirement gift for us; Kind of like the Y2K problem. Of course this issue goes away almost immediately when you start working on LP64 programming environments.
Grumbling about determining a particular time zone's offset from UTC without actually setting the value. There doesn't seem to be much in the lines of determining this without significant programmatic interference.
Well, I have a dlna server running on my little always-on laptop. Now I just need to get something similar on the worldbook, removing the need to have the laptop always on.
Setting up network-manager (0.6.5-0ubuntu16.7.10.0) ...
Installing new version of config file /etc/dbus-1/system.d/NetworkManager.conf ...
Auto interfaces found: lo eth1 eth2 ath0 wlan0
iface to disable = eth1
iface to disable = eth2
iface to disable = ath0
iface to disable = wlan0
Disabling interface: eth1 ... done.
Disabling interface: eth2 ... done.
Disabling interface: ath0 ... done.
Disabling interface: wlan0 ... done.
 * Reloading system message bus config...
   ...done.
 * Restarting network connection manager NetworkManager
And that's all it wrote. I do not like NetworkManager - it is a piece of crap
Apple have obviously made some significant backwards compatibility errors. Firstly, there's the firewall - altering the on-disk content of applications to make them signed when you accept them. Its an interesting approach, but it's complete pants. You don't go around altering binaries on disk. You create a detached signature! It's not really bloody difficult.
On Vista, you can see *every* rule that exists for the firewall. On Leopard, you only get to see the exceptions you created yourself.
I've been having random application crashes. They seem to be related to drag and drop operations that went wrong.
the calendar application does not want to talk to my instance of davical properly (all the calendars disappear after restarting, and I get an error every time I create a calendar). Then there's the 'the application terminated unexpectedly' - no, it didn't, I used the <Apple>Q menu item to quit the application.
Context sensitivity on the mail application is kinda limited - It doesn't detect URL links properly - I have a site that's called http://foo4/..., and all the link comes up with is http://foo. As I said, a bit limited.
Overall, though, the experience is positive. I would have preferred if apple had simply spent some more time testing the damned thing against anything other than their own applications and services.
And, as soon as they allow a replacement for .mac that can be replaced with an external, non-proprietary service I'll be a happier person

gnome on low bandwidth

| No Comments | No TrackBacks
I would have to say 'serves you right', but even with a reasonably fast cable modem connection X blows goats on remote displays. vnc is an improvement, but the windows remote terminal system kicks ass on a 56k ordinary modem connection. Hmmm....
It turns out there's a bug, due primarily to testing on zsh and putting the script into bash.
function find_lowest_subprocess() {
    local -i parent=$1
    local pids
    typeset -a pids

    pids=($(pgrep -P $parent))
    while ((${#pids[@]} > 0)); do
        if ((${#pids[@]} > 1)); then
            parent=${pids[0]}
            local i=0
            while ((i < ${#pids[@]})); do
                local sub=$(pgrep -P ${pids[$i]})
                [[ -n $sub ]] && parent=$sub
                ((i=i + 1))
            done
        else
            parent=$pids
        fi
        pids=($(pgrep -P $parent))
    done
    echo $parent
}
Someone, somewhere forgot about the parenthes around the array assignments. Shame on me!
I'm replaying network traffic at 1000 packets per second into a vmware client that's hosted on a vista machine. It's losing quite a few packets. the Vista OS does not appear to be losing the packets, they are simple missing on the guest operating system. This is a lot like crap, really.
This is the official declaration of a patch for the linux kernel. It provides for the replacement of all GPL only exported symbols with generically exported symbols.
While the code is trivial, I hereby declare that it is copyright 2007 Pete Shanahan.
It is, itself subject to the GPL, so there.
Starting from the kernel source directory issue the following command:
for i in $(find . -type f); do
sed -i -e 's/EXPORT_SYMBOL_GPL/EXPORT_SYMBOL/' $i
done
If someone is putting multiple symbols on a line, then you have my permission to use:
for i in $(find . -type f); do
sed -i -e 's/EXPORT_SYMBOL_GPL/EXPORT_SYMBOL/g' $i
done
Gosh, now that wasn't difficult, now was it?
This developer created this patch while under the influence of several personally made martinis, a couple of beers and a few shots of vodka (it was nice, though), so if the spelling of any of the code is incorrect then feel free to correct it, send me a patch and I'll add you as a contributor to it. After all, we're all pragmatists together.
The GPL is a difficult beast.
all those MODULE_EXPORT_GPL symbols.
F**k them.
I'm just going to release a patch that remaps them all to MODULE_EXPORT.
The patch is GPL.
F**k you I'm a pragmatist, not an idealist.
This was written at 3am, I am drunk and I'm bitter. You know who I am.
I don't prefix my posts with 'yes, I drink...', you should know what I'm like, after all; you're here

it's a tomato

| No Comments | No TrackBacks
Well, having had enough of the dd-wrt firmware for the linksys router. It was annoying, slow and irritating and every time we enabled QOS it lost the connection to the WAN I upgraded to the tomato firmware. So far it works. It successfully QOSes the p2p stuff down to the lowest category. It has pretty graphs! Whoopee!

AMT is handy....

| No Comments | No TrackBacks
It's just a shame that you can't use it easily on Linux due to the lack of a driver to communicate directly with the hardware. It's the replacement for IPMI. Complete remote management of your servers (and desktops and laptops) through an always-on network connection (that is as long as you have power going to the box). All it needs is to be configured (not for the faint hearted) and then you need a machine to talk to it. Unless you're using a half decent windows server box (something that can at least pretend to be a provisioning server), you're screwed as you'll only be able to use it in small bunnies mode (business :). You can make a local ISO image on your computer act like it's in the CD drivce of the remote machine, you can PXE boot it from the command line (easy installs; easy cleanup!). It cooks, it cleans and it even sends out SNMP traps when something goes wrong (except of course for when the power goes out). It supports a watchdog (but it's not as easy to program for as the linux watchdog). Unfortunately you have to talk to the damned thing over SOAP. I mean really, wot are you like? It's like using a butcher's knife to perform and appendectomy.
We need to extend the linkit script to support (a) Solaris and (b) spaces/escape characters in the file name.
Sorry, my shell environment just isn't cooperating with me - BASH_ARGV[0] == {}, yet I cannot dereference the variable correctly no matter what I try. No wonder people use perl. God this is so frelling irritating.
Playing with the latest 2.6.20 kernel, I tried to enable paravirtualization on the kernel and it broke vmware. It looks like the XEN changes that went in should be disabled for the time being until there is a more recent release of vmware - prefereably one that can play well with others.
Strangely enough, I had actually thought of this before I made the post. Snapshots are a wonderful feature in zfs which allow you to take point in time images of a filesystem that are mutable and which themselves can be snapshotted.
Unfortunately, this leads an explosion of snapshots if we want to be able to arbitrarily remove any one application from the system.
Consider the following operation:
pkg(1) + pkg(2) + pkg(3)
Now remove pkg(2) without using anything other than snapshots.
snapshot before adding anything sn(0). snapshot after adding package 1 sn(1)(sn(0)). snapshot after adding package2 sn(2)(sn(0)) + sn(2)(sn(1)). snapshot after adding package3 sn(3)(sn(0)) + sn(3)(sn(2)) + sn(3)(sn(1)).
Repeat for arbitrary pkg(n).
Unless you're planning on creating a whole travelling salesmanOk, it's not quite the travelling salesman problem, but it gives you a good idea as to how much work is involved of snapshots, I think my mechanism is easier.
This little piece of shell script attempts to find the 'lowest subprocess' of a passed in process. It works well with a straight tree of processes, and if there are the occasional pipes in the command tree then it will miss them most of the time.
Maybe tomorrow I'll talk about how to fix it.
function find_lowest_subprocess() {
        local -i parent=$1
        local pids
        typeset -a pids

        pids=$(pgrep -P $parent)
        while [[ -n "$pids" ]]; do
                if (( ${#pids[@]} > 1 )); then
                        local i=0
                        while (( i < ${#pids[@]} )); do
                                local sub=$(pgrep -P ${pids[$i]})
                                [[ -n $sub ]] && parent=$sub
                                ((i=i + 1))
                        done
                else
                        parent=$pids
                fi
                pids=$(pgrep -P $parent)
        done
        echo $parent
}
If you use windows then this is probably going to be very, very boring.
Every now and again you find yourself needing to install some piece of software on your computer from a source package. You tar xjf the package and descend into the subdirectory and type ./configure.
At this point I would yell stop! Rather than putting it into the default location of /usr/local, consider putting it in /usr/local/<package-version>.
How does this help I hear you ask. Well, using a simple script (in the extended entry), you create a set of symbolic links in the /usr/local directories which reference the files in the /usr/local/<package-version> directories.
If you decide to remove the package then simply remove the /usr/local/<package-version> directory and all the symlinks become broken. By using symlinks -rd /usr/local you clean the file system up and everything is peachy. If you don't have a copy of symlinks, it is available from the debian repository, where you should find the source package somewhere near the bottom.
#!/bin/bash -p

package=$1
destdir=${2:-/usr/local}
me=${0##*/}

[[ -z $package ]] && {
        echo "Usage: $me <package> [destination = /usr/local]"
        exit 2
}

cd $destdir/$package || {
        echo "$me: package $package does not seem to be installed"
        exit 1
}

# build the directory structure - this is a weakness
find . -type d | cpio -o | (cd $destdir; cpio -id)

find . -type f -exec $echo ln -s $destdir/$package/{} ../{} \;

Oh, and for solaris, as I'm using the file in various locations surrounded by symbols you will have to just pass it into a sub-program to execute the link command. Apparently solaris doesn't just substitute the name of the target for the link; instead it will only substitute the name of the target when it is isolated (i.e. you would need to use the {} on their own without anything surrounding them - which explains the space between the closing brace and the backslashed semicolon - old habits). I supposed I could throw a bit of perl at this problem but... it works on my box so frell the rest of you :).
Meh, the entire problem is annoying; generally I would always have to create a program to process the {} operation anyway to prevent space characters from getting in the way but as we say in the trade 99% is better than 0%. If you want a 100% solution you need to add a script that performs the link - one per line produced from the find.
FeatureBourne ShellBusybox ShellBash
Subprocess Execution`` (the backtick)`` or $()As Busybox
Math Evaluationuse expr (not builtin)$(( ))As Busybox; adds ((var=math))
ConstantsNoneNonetypeset -r
IntegersNoneNonetypeset -i
Evaluation[[[
Extended Evaluation/bin/[[ (1)/bin/[[ (1)[[

(1) The [[ operator is not the same as the program /bin/[[ as a program you need to still use double quotes around the variables to be expanded; thus defeating the reason for having them in the first place.

For Example:

	# file="/tmp/let me go"
	# touch "$file"
	# [[ -e $file ]] && echo "There"

Yields [Busybox]:

	[[: me: unknown operand
- as $file is word split before handing it to the command [[

Yields [bash]:

	There
- due to $file not being split when passed to the test -e.
Well Solaris express doesn't panic my laptop any more. I had one of those wierd variants of a bge card. Now all I need is wireless.
and sound...

And another thing...

| 1 Comment
It's the world's most advanced operating system? I mean really, that's an overstatement. Hello! that's nothing more than a brag as there's nothing to back up the statement. Advanced for what? File systems? zfs! observability? dtrace! pretties on the screen? XGL! The ability to perform more than one name service lookup at a time? [ok, that's a cheap shot, I'm sure they fixed this]
Pants, complete pants I tell you!

Finally got XGL working properly

| No Comments
It started off not displaying on the screen correctly - it turns out that I had 16 bit visuals enabled. Changing to a default depth of 24 made that go away. It is really pretty. Prettier than vista. All I need to do is not waste time on it.
gedit being helpful gedit has this nice feature where it asks you what character set encoding a document is in if it can't decide this for itself. I'm not familiar with the mechanism that is being used for this, but it probably has something to do with ninja badgers, character counting and a telepathic link to the borg collective. The problem is that if it has to give up on guessing what the file is, there's no way to force the file to be opened as any file type at all. I encountered this when trying to access some old data that had trailing NULL characters at the end of the file. The problem is that there's no 'mangle it to this file type and show it to me' option.
This one: Secure Java apps on Linux using MD5 crypt
Firstly, the encrypted string is: $<mechanism>$..., where a mechanism of 1 is MD5. My desktop has 2a, which indicates I'm using the Blowfish algorithm - I see no reason to compromise.
Well, guess what - this document won't work for me because I use blowfish locally, and secondly, the only accounts in /etc/shadow (and passwd) are local accounts - if you're using nis, nisplus, or ldap (solaris more so) for your name services, then you're SOL with this mechanism.
This is another reason for not using the crypt mechanism is that this is trying to solve the problem from the wrong level. You should not be trying to compare the encryption strings, you should be using an alternative to the OS provided security mechanism. So in this case you should be using jaas, and a PAM plugin. The use of yet another 'well it works on my box' mechanism is so cripplingly annoying that it angries up my blood.

About this Archive

This page is a archive of recent entries in the Linux/Unix category.

Hardware is the previous category.

Mac is the next category.

Find recent content on the main index or look in the archives to find all content.