On the server:

fetchnew.php:

#!/usr/bin/env php
<?php

$url = "http://www.secondlife.com/community/linux-alpha.php";
$tmpfp = tmpfile();

//$url = "http://www.cyberleo.net/cyberleo/Downloads/SecondLife_i686_1_18_1_2.tar.bz2";
//$tmpfp = fopen("/home/cyberleo/secondlife/SecondLife_i686_1_18_0_6.tar.bz2", "r");

$stage = sprintf("%s/%s", "/home/cyberleo/secondlife/tmp", md5(time()+microtime()));
$target = "/home/cyberleo/secondlife/linux";
$pointer = "/home/cyberleo/secondlife/linux/SecondLife";

$ptrfp = fopen($pointer, "w");
if (!flock($ptrfp, LOCK_EX | LOCK_NB, $wouldblock) && $wouldblock)
        die("Already running.\n");

// Create temp directory
if (!mkdir($stage))
        die("Directory race!\n");


$useful = file($url);

// Extract the most useful line
$useful = preg_grep("/\.tar\.bz2.*Linux i686/", $useful);

// Extract the most useful URL from that line
$useful = array_values($useful);
$useful = $useful[0];

$useful = preg_split("/\"(http:\/\/.*\.tar\.bz2)\".*Linux i686\<\/a\>: ([^ ]+)/", $useful, -1, PREG_SPLIT_DELIM_CAPTURE);

$url = $useful[1];
$version = $useful[2];

if (!$url)
        die("Didn't get a valid URL! Help!");

$components = parse_url($url);

printf("Fetching version %s from %s...\n", $version, $components['host']);

unset($useful);
unset($components);

$curl = curl_init();
curl_setopt($curl, CURLOPT_USERAGENT, "MyBrowse/1.0 (GS/OS 6.0.3; AppleIIgs)");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
//curl_setopt($curl, CURLOPT_MUTE, TRUE);
curl_setopt($curl, CURLOPT_NOPROGRESS, FALSE);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($curl, CURLOPT_AUTOREFERER, TRUE);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_FILE, $tmpfp);
curl_exec($curl);
curl_close($curl);

$length = fstat($tmpfp);
$length = $length['size'];

// Set up command environment
$command = sprintf("/usr/bin/nice -n 10 /usr/bin/tar jxvCf %s - 2>&1", escapeshellarg($stage));
$pipes = Array(
        0 => Array("pipe", "r"),
        1 => Array("pipe", "w"),
        2 => Array("pipe", "w")
);
$cmdfp = proc_open($command, $pipes, $pipes, $stage);
if (!is_resource($cmdfp))
        die("proc_open failed.\n");

if (!is_resource($pipes[0])) {
        var_dump($pipes);
        die("stdin isn't a pipe!\n");
}

stream_set_blocking($pipes[0], FALSE);
stream_set_blocking($pipes[1], FALSE);

echo "Extracting...\n";
fseek($tmpfp, 0);
$count = 0;
$f_len = strlen($length);
$fmt = sprintf(' %%%1$uu / %%%1$uu (%%3u%%%%) %%s '."\033[K\r", $f_len);
sprintf($fmt, $count, $length, (100 * ($count / $length)), "");
$time = $oldtime = time();
$bufr = "";
while(!feof($tmpfp) || strlen($bufr)) {
        if (strlen($bufr) < 512)
                $bufr.= fread($tmpfp, 65536);
        $read = Array($pipes[1]);
        $write = Array($pipes[0]);
        $except = NULL;
        if (stream_select($read, $write, $except, 1)) {
                if ($read) {
                        while ($tmp = fgets($pipes[1], 4096))
                                $curout = $tmp;
                }
                if ($write) {
                        $len = fwrite($pipes[0], $bufr, strlen($bufr));
                        if ($len)
                                $bufr = substr($bufr, $len, strlen($bufr) - $len);
                        $count+= $len;
                }
        }
        if (time() != $time) {
                printf($fmt, $count, $length, (100 * ($count / $length)),
                        sprintf("...%s", substr(trim($curout), -45, 45)));
                $oldtime = $time;
                $time = time();
        }
}
printf($fmt, $count, $length, (100 * ($count / $length)), "");
echo "\n";

fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
$result = proc_close($cmdfp);
fclose($tmpfp);

unset($count, $length);
unset($fmt);
unset($time, $oldtime);
unset($bufr, $read, $write);
unset($command);

if ($result !== 0) {
        var_dump($curout);
        die("Something failed!\n");
}

echo "Moving into place...\n";

$name = trim(shell_exec(sprintf("ls -1 %s", escapeshellarg($stage))));

$src = sprintf("%s/%s", $stage, $name);
$dst = sprintf("%s/%s", $target, $name);
shell_exec(sprintf("/bin/rm -Rf %s", escapeshellarg($dst)));
rename($src, $dst);

shell_exec(sprintf("/bin/rm -Rf %s", escapeshellarg($stage)));

fwrite($ptrfp, $name, strlen($name));
fwrite($ptrfp, "\n", 1);
flock($ptrfp, LOCK_UN);
fclose($ptrfp);

/*
fclose($dstfp);

echo "Extracting...\n";
$command = sprintf("/usr/bin/nice -n 10 /usr/bin/tar jxCf %s %s", escapeshellarg($target), escapeshellarg($dstfile));
var_dump($command);
var_dump(shell_exec($command));

unlink($dstfile);
*/

On the client: updatesl.sh:

#!/bin/bash

mkdir -p tmp
echo "Fetching pointer..."
rsync --compress --progress --stats rsync://cyberleo@pizzabox:~/secondlife/linux/SecondLife ./tmp/pointer
if [ "$?" -ne 0 -o ! -f ./tmp/pointer ]
then
        echo "Pointer fetch failed."
        exit 64
fi

pointer="$(cat ./tmp/pointer)"

echo "Got pointer to ${pointer}"

if [ -e "${pointer}" ]
then
        echo "Destination directory ${pointer} already exists."
        exit 32
fi

cur="$( stat -c "%N" SecondLife | cut -d' ' -f3 | tr -d '`/'\' )"

echo "Updating ${cur} -> ${pointer}"

cp -pR "${cur}" "${pointer}"
if [ "$?" -ne 0 ]
then
        echo "Tree clone failed."
        exit 16
fi

rsync --archive --compress --delete --hard-links --progress --sparse --stats "rsync://cyberleo@pizzabox:~/secondlife/linux/${pointer}" "./${pointer}"

if [ "$?" -ne 0 ]
then
        echo "rsync failed."
        exit 8
fi

echo "Linking"
rm -f SecondLife
ln -svf "${pointer}" SecondLife
rm tmp/pointer
echo "Done."

PHP Warning

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead:"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead:"