Email fucked until at least late Tuesday. agl02 at doc.ic.ac.uk should still work.
here (via BoingBoing)
Apparently I have been subpoenad, personally, on 8-17-2003 by an as-yet unknown entity under the DMCA clause, because of xmule, when it went on to gov'ment radar w/ the e-matters.de alert :P The subpoena lasts, suposedly, until Dec 6, when i must stand infrotn of a federal appellet court
I'm going to have to do something about this problem at some point, but for the moment I'm going to settle with describing it.
I'm considering the design of some status monitoring for the servers in DoC. At the moment we have some pretty complex triggers setup on our admin Postgres server that allows you to insert values into a table and have per-minute and per-hour tables filled out automatically with the min, max and average. This is all very nice, but very slow. Postgres just can't handle it so we need something different.
We want to be able to set alarms on values over any averaging time and we want to record the per-hour, per-minute, per-day etc data for long term analysis of server load and so forth.
I've written a small C program that parses /proc/stat and pulls useful information out of it. Every bit of information is a name-value pair like servername.load, 2.3. I don't want to have to bother with authenticating raw TCP connections so I'm going to have the status server ssh out and invoke the monitoring program to trusted servers.
That's all just background.
Now I have lots of incoming streams from the servers and I need to demultiplex them into a stream with all the data. I'm a good UNIX programmer so I want everything to be as modular as possible. Let's say that I collect the data with a command line like: ssh -t -t -x ... servername /usr/bin/monitor_program | domcat /var/status_data (domcat is like netcat, but for UNIX domain sockets). Now I need a program that can merge the incoming streams and allow people to connect and receive the total stream.
If I was being a poor UNIX programmer I would pass a couple of TCP port numbers to this program. It would take all the input from anyone who connected to the first port, merge it and throw it out to everyone connected to the second port.
But the decision to use TCP shouldn't be ingrained (authentication nightmare), nor should the splitting of streams (it's just data). All this program should do is use it's protocol specific knowledge to merge streams into one. Thankfully, I already have a program called conguardian that just passes file descriptors to the stdin of it's child and accepts (and authenticates) connections from a named UNIX domain socket. So, the command line is looking like: conguardian /var/status-data merger_program.
But how do we get the data out of it? We write a program called splitter that just takes an input stream from stdin and copies it to everyone who connects. Thankfully, conguardian already abstracts the business of accepting and authenticating connections. So we say conguardian /var/status-data merger_program | conguardian /var/status-data-out splitter.
Opps! conguardian passes file descriptors in via stdin and we are trying to pipe data into stdin. How well do you know your shell syntax? Can you even pipe the output of one program into a numbered fd input of another? Are you going to have a headache by the time you have finished?
I'm always finding that I can't connect programs together with anything like the flexibility I want. How do you do bidirectional pipes? You put make programs' name and arguments, arguments of the first and write special fork handling code in the first. And if you want two bidirectional inputs to the second program? Oh dear.
(The above may be clearer if I include the conguardian manpage)
CONGUARDIAN(1) CONGUARDIAN(1)
NAME
conguardian - Access control for UNIX domain sockets
SYNOPSIS
conguardian []...
DESCRIPTION
conguardian attempts to unlink the given socket path if it
exists and is a socket. If it is not a socket then it will
fail to bind to it and give up.
conguardian accepts connections on the given socket and
checks the UID of the other end against an internal list
of allowed usernames. UID 0 is always allowed and the
internal list is initially empty. If not on the list, the
connection is terminated.
If the client is allowed and sends an ASCII NUL as the
first byte, the connection is passed to the child over
UNIX domain DGRAM socket on stdin. If the client sends a
0x01 byte and is root, it can upload a new username list.
ENVIRONMENT
IDENT given in all syslog messages
AUTHOR
Adam Langley
CONGUARDIAN(1)
As O'Reilly books go, this is a pretty small one. It's list price ($25) is
more than I would value it at, but I got it from the library
.
The book is in three sections: an introduction to Perl 6, an introduction to Parrot and a primer in Parrot assembly. The last one is highly skimmable unless you are actually programming in Parrot assembly (in which case you probably already have a far better knowledge of Parrot).
Now Perl 6 looks quite cool, it fixes a couple of things that I don't like about Perl 5. Assigning a hash or array to a scalar produces a reference to it...
Interlude: I'm half watching a program about asteroid impacts and I've just seen a (poor) computer graphics simulation of an impact on right on Imperial College, of all the places in the world. I'm a little gob smacked...
... which makes a lot more sense than assigning the phase of the moon or something. And the rules system (even more complex regular expressions) looks very powerful and a little more sane than Perl 5 regexps.
Also, we have an intelligent equality (~~) operator, which looks neat and leads to a nice switch operator (given). But I'm a little concerned about the number of different things it does depending on the types of it's arguments, but that's very Perlish. And the book lists 12 different contexts in which anything can be evaluated.
Less cosmetically, Perl 6 might gain continuation and coroutine support from Parrot. I don't know if Perl 6 will actually expose these, but Parrot can do them. And Parrot looks like it could really do wonders for open source scripting languages. It looks fast, and has been designed to support Perl 6, Ruby, Parrot, Scheme and others. Intercalling between them might allow us to get rid of some of the terrible C glue code that we have at the moment.
One thing that does worry me about Parrot is that it's basic integer type is a signed 32-bit. If you want anything else you have to use PMCs, which is a vtable based data type that allows for arrays and hashs and so forth, and is much slower. Now there are many applications for which 31-bits isn't enough. File offsets are obvious, but how about UID and device numbers? Both of these are looking like that are going to be 32-bit unsigned ints. You can fit this into a Parrot signed int, but it's going to cause huge headaches.
I've been dealing with APC UPSs a fair bit this week. A quick Google search will turn up the serial protocol that they use and it's really quite nice. A lot of devices (APC MasterSwitches for one) have a fancy vt100 menu interface which is totally unusable for an automated system. The UPSs, on the other hand have a simple byte code protocol and hopefully I'll have the servers shutting down neatly in a power failure. Software like that already exists but it's generally too far simple minded. We have many servers on any given UPS and some servers on several.
APC do loose points for their serial cables however. APC supply (for quite a price) so called 'smart cables' that are specially pinned out and nothing else uses the same interface. Thankfully, after looking at diagrams for about an hour I stuck 3 pins into a D9->RJ45 converter and it worked first time!
(IV should stop falling over quite as often now. It looks like there's a bug in the sunrpc code in 2.4.20 kernels. The maintainer doesn't know why, but 2.4.21 fixed it.)
I'm rewriting a replacement user-land automounting daemon at the moment which I'll post here when it's kindof ready. The two current solutions (autofs and amd) are either too fragile (autofs) or too bloated and too fragile (amd). Sadly enough, amd came from Imperial CSG originally and has turned into a monster over time.
I'm a little limited in what I can do on my laptop however (I'm at home for the weekend) because it only has GCC 2.95 which lacks the nice C99 features that GCC3 supports. (Actually I'm a little hazy on which are C99 features and which are GCC extensions. But since the automounter is only ever going to run on Linux they are pretty much the same).
Lexical functions and C++ style variable decl placement are an absolute wonder (though I have found a couple of placement gotchas which might be because I was using a CVS GCC). One thing that I'm not so sure about is run-time array sizes.
This allows the size value of an array to be a run-time variable. I suppose this (with the more flexible decl placement) is a `cleaner' way of doing alloca. But it was certainly a surprise when I forgot a sizeof, thus making the array size run-time and (so it happened) negative. It certainly scared the crap out of gdb.
And speaking of gdb, it doesn't seem to understand much that GCC3 turns out. I guess I need to start CVS chasing gdb again (like I did when pthreads support was still going in).
I got 2.6.0-test3 to boot. This is the first 2.5/2.6 kernel that has ever managed to boot on my system. Personally it doesn't seem too obscure to me, but the AIC7xxx and megaraid cards have always freaked out a 2.5/2.6 kernel until now. (Which was kindof a bummer since the only root device I had left without those was a floppy disk).
I'm not sure if it's really that much quicker than a fully patched (preempt etc) 2.4, but at least it saves me from patching every kernel version with XFS. The new sysfs seems a little weird. I guess it's still a -test quality release, but different devices don't seem to argee on how to format things like device numbers and the like.
Still, udev thinks it can simulate devfs in userspace via sysfs and /sbin/hotplug, which is quite neat. I guess I'll need a `real' /dev directory again however, since you can't mount udev at boot like you can with devfs.
Also, I want disklabel support added to grub and the kernel. You can quite happily put UUID= and LABEL= tags in /etc/fstab, but you still need to give `real' device numbers to the kernel and grub. Worse yet, the kernel device numbers depend on the order of Linux drivers loading and grub's depend on the order of BIOSes loading. Under 2.4 there is pretty much no good way (that I know of) to get grub device numbers.
I think that the kernel people would say that support for labelled roots should go in an initrd. And I would agree with them if I didn't hate initrd's so much for all the pain they have caused me. I guess I should to hack linux/init/*.c.
I should also post my grub -R patch here (one shot reboots).
The BBC are reporting (lack of inet connection - no link at the moment) that Microsoft has `neutralised' the MS Blaster worm. What they have actually done is move the windowsupdate.com domain so that they don't get flooded off the face of the planet which would have been just reward.
It's still crashing unpatched systems left right and centre because it's so badly written. Once again, the world has been saved by the abject cluelessness of black-hat-wannabe-kiddies.
And from the world of less clueless coloured-hat people; the latest Phrack is out. Phrack is very much worth reading. It has a fair few wordz with too many z's on the end, but the actual content is of a very high quality. I certainly want to play with the ELFsh program.
Oh, another item for the wish list, code that will take a dynamic ELF and make it static.
And I guess there are a fair few computers on the Niagara Mohawk grid that haven't been patched yet
.
(I shouldn't smile about that actually. The UK has deregulated the grid recently too and investment has fallen to 0. Sure, prices are lower but people are asking where all that money came from yet.)
tmpfs is a cool thing. You almost certainly have it built in if you're running a 2.[456] kernel. I have a box sitting in the DoC machine room that, at rc.sysinit time, copies a Gentoo stage3 into a tmpfs and chroots into it. It has no swap enabled so you can (and I did) pull the SCSI ribbon off the motherboard (live) and the machine doesn't even blink.
It will be logging to the disk at some point and all those multilog and syslog-ng processes will drop into disk wait, but that shouldn't won't the main function of the box. My main worry is that syslog-ng creates /dev/log as a UNIX SOCK_STREAM (I have yet to test this) in which case some stuff that syslogs will lock up too.
My code expects syslog to block and will carry on working (dropping log messages as needed), but I'm not sure about sshd and the like. The solution is to make /dev/log a SOCK_DGRAM in the syslog-ng source code I guess.
I'm sure there was something important that I was ment to reply to today but I can't remember what. I expect it will blind-side me about 4pm tomorrow. These things usually do.
IV was down over the weekend because the webserver died again. We have physically switched boxes for the webserver and it's having the exact same issues as the old one. Autofs is causing a kernel oops that then locks up VFS layer and after that the webserver is a little useless.
The maintainer of the code in question (net/sunrpc) has had a look at the stack traces and can't see anything wrong so we are going to see if it happens again (with a 2.4.21 kernel) and start stripping out patches until we can reproduce it in a stock kernel. At that point we add debugging code to try and trap where the dodgy data structure is going dodgy. All on our primary webserver - wonderful.
And...
iptables -P INPUT DROP ; iptables -I INPUT -p tcp --destination-port=22 -j ACCEPT
just made my server drop off the face of the net. That really should have been in one packet, damm you fragments.
Oh, and train operating staff will be able to use swab kits to add people who spit at them to the UK DNA database. Charming.
[Amazon link] Frankly, I expected better from Hamilton and probably should have paid heed to the reviewers on Amazon. Hamilton writes some really good books; never hard core sci-fi, but good old fashioned page-turners.
But the plot of this book reads like a low-budget porno script and the characters are uninteresting and unbelievable. I read to the end, but mainly because I had nothing else to do.
DoC's primary web server (the server which you are getting this page from) has been failing a lot recently with autofs problems. At one point it died 3 times in as many hours so we switched to a different box and sat it on 146.169.1.10. That was ok for while until it died in the same place. I hope to get the opps output and have a look.
But autofs (the userland part) is a little dodgy. It can get upset pretty easily with NFS mounts as can amd (the alternative, written by CSG at Imperial) is only a little better. Both are pretty huge programs for doing a simple task. I think I'll write a replacement over the weekend.
Little to most people know of UNIX domain sockets. They may only work on the localhost, but when local communication is all you need they offer a number of funky features.
Firstly, you can find out who is connected to you:
struct client *
client_init (int socket)
{
struct ucred creds;
socklen_t creds_len = sizeof (creds);
struct passwd *pwent;
if (getsockopt (socket, SOL_SOCKET, SO_PEERCRED, &creds, &creds_len) == -1)
return NULL;
if (creds_len != sizeof (struct ucred))
return NULL;
pwent = getpwuid (creds.uid);
if (!pwent) {
syslog_write (slog, LOG_WARNING, "Lookup in passwd for UID %d failed", creds.uid);
return NULL;
}
Secondly, you can pass file descriptors down them:
// Transmits @new_sock over @dest_sock using SCM_RIGHTS
int
send_fd (int dest_sock, int new_sock) {
struct msghdr msg = {0};
struct cmsghdr *cmsg;
char buf[CMSG_SPACE (sizeof (new_sock))];
int *fdptr;
msg.msg_control = buf;
msg.msg_controllen = sizeof (buf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
fdptr = (int *)CMSG_DATA(cmsg);
*fdptr = new_sock;
// Sum of the length of all control messages in the buffer:
msg.msg_controllen = cmsg->cmsg_len;
if (sendmsg (dest_sock, &msg, 0) == -1) {
fprintf (stderr, "Failed to write to child: %s\n",
strerror (errno));
return 10;
}
return 0;
}
// Reads a file descriptor from stdin using SCM_RIGHTS
int
get_fd ()
{
char buf[CMSG_SPACE(sizeof (int))];
struct msghdr msg;
struct cmsghdr *cmsg;
msg.msg_control = buf;
msg.msg_controllen = sizeof (buf);
msg.msg_name = NULL;
msg.msg_iov = NULL;
msg.msg_iovlen = 0;
if (recvmsg (0, &msg, 0) != 0)
return -1;
cmsg = CMSG_FIRSTHDR (&msg);
if (cmsg->cmsg_type != SCM_RIGHTS) {
syslog_write (slog, LOG_ERR, "CMSG type was not SCM_RIGHTS");
return -1;
}
return *((int *) CMSG_DATA (cmsg));
}
The webserver is on it's last legs and will almost certainly die over the weekend. (Hint: never use Reiserfs).
IV should still be on http://tweetypie.doc.ic.ac.uk/~agl02/ however. But if the primary server is down, how do you get that URL?
Something to ponder..
God, building packages for apache+php+mod_perl+kitchen sink is so painful. A million paths woven together into one huge diabolical ubermess. Sigh. I guess I'll get there in the end.
http://www.imperialviolet.org/binary/linux-2.4.21-grsecurity-1.9.11-xfs-1.3pre4.patch.bz2
Mail should be working again.
This article on 3d printing was linked to on slashdot. It's a pretty short and dull introduction, but it foreshadows another key battle on the copyright front. Personally, I think that Gilmore expressed it far better in this text. It's going to be a painful few decades while these changes sink in.
sfdisk -s returned a negative number for me today caused by the 2TB limit on 32-bit sector counts. This seems like it's going to be a pretty painful transition as many utilies (even the kernel, until 2.6) have this limit. sfdisk, despite being in util-linux, is actually pretty badly written. It assumes in several places that sizeof (long) = 4. I might end up rewriting large parts of it because cyl/head/sectors have got to go.
Hawk is not getting SMTP, so no email is getting through at the moment.
Use agl02 AT doc.ic.ac.uk if need be.
See, I don't understand what all this filesharing fuss is about. People put so much effort into Kazaa, Gnutella and other weirdly named stuff.
All you need is a user running a buggy version of phpBB, a gigabaud link to the Internet and people will upload stuff to you! 84GB of stuff to be precise onto our primary fileserver. It says something about the systems at Imperial that this was such small fry that it didn't even register for a few days until they setup ftp servers and our webserver was a couple of places higher than normal on the list of hosts by outbound traffic.
What's really amusing is watching the script kiddie's exploit. (Yes, we keep
full packet logs of everything for a couple of weeks, so we just scanned back
and selected that TCP stream). They connected and it's so obvious that they
didn't have a clue. They were pasting commands in (multiple commands in 1
packet) and couldn't use grep. They would ls -lR to find somewhere to
put their files and hit ^C after a while ... before doing it again and trying
to hit ^C at the right place because it had gone off the top of the screen
.
(I would usually lock php right down to stop user level compromises like this. But it's a university and we are ment to give them pretty free run. And yes, the user web and db servers do get buggered silly on a fairly regular basis as scripts run amok.)
I was explaining to someone the importance of using the -print0 argument to find when working in untrusted paths. Often the output of find is piped into a program like xargs using newlines to deliminate files. The -print0 (and -0 option to xargs) uses null bytes insted.
Try this example:
% python
Python 2.2.3 (#1, Jul 12 2003, 15:30:57)
[GCC 3.2.3 20030422 (Gentoo Linux 1.4 3.2.3-r1, propolice)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.mkdir ("foo\n"); os.mkdir ("foo\n/etc");
>>> open ("foo\n/etc/passwd", "w+").close ()
>>>
% find
.
./foo
./foo
/etc
./foo
/etc/passwd
Opps! Where did /etc/passwd come from? Lets hope that that xargs wasn't doing anything nasty.
These results are completely unfair and shouldn't be taken as gospel in any way. Lithium is the dual Operton (it's specs are in a previous post), lithium32 is Lithium running 32-bit code (Mandrake 9.1) and Loch is a dual 2.66Ghz Xeon with only 1GB of memory (Lithium has 4). Lithium only has an ATA disk, while Loch is LVD SCSI. I tried as much as possible to allow both systems to keep everything in buffer cache.
Everything was run with GCC 3.3, but keep in mind that Lithium (in 64-bit mode) is actually building a slightly different kernel (x86-64, not i386).
make 2.6.0-test1, default configure, no -j lithium: 4m33 lithium32: 5m26 loch: 5m41 make 2.6.0-test1, after make clean, -j4 lithium: 2m27 lithium32: 2m48 loch: 2m57 make 2.6.0-test1, after make clean, -j8 lithium: 2m28 lithium32: 2m48 loch: 3m08 md5sum of 512M zero file (in buffer cache) lithium: 3.1s lithium32: 10.6s loch: 3.4s stimpy: 16.8s
Stimpy is another Mandrake box because I didn't quite believe the result for Lithium in 32-bit mode. It seems that Mandrake 9.1's md5sum just sucks, so ignore lithium32's result in that.
This just makes my blood boil. I really shouldn't read these articles, I'm sure it's bad for my health or something
. These idiots will always exist.
Gentoo AMD64 lives! It takes quite a lot of trickery, but it's building KDE at the moment (heck, have to do something with all of those cpu cycles!). I might post a stage1 file at some point, but the semi-offical Gentoo amd64 stage1 files will be out soon. Mostly I did it for the experience.
You know, my home system didn't feel slow till I started using the dual Opteron system. Heck, even the dual Xeon-HT's don't feel as nippy and it's running 32-bit code.
I posted a note to python-dev today about finding the size of types at configure time. Almost nothing except glibc, gcc and binutils works cleanly when cross compiling. GNU autoconf should mean that setting --host and --build makes everything work magically. Does it hell.
(p.s. glibc 2.3.2 cannot be cross compiled, use 2.3.1. And both of these versions misdefine sscanf - you have to correct it in stdio-common/sscanf.c first.)
One of the dumbest things in configure scripts is when they don't try tests because they can't run the compiled code (because it's x86-64 code). The script knows it's a cross and just gives up. In the case of Python it assumes that the sizes of int etc are for 32-bit. (Except for fpos_t, for which it's correct for an 8-bit system). But there's no reason to run compiled code to get this information.
#include <asm/types.h> #include <sys/types.h> const __u8 sizeof_int[sizeof(int)];
And so on. Then compile the code and objdump -t sizeof.o | grep 'sizeof_[^ ]+$' | awk '{ print $5 " " $1; } will give you all the information. Works perfectly for native and cross compilers.
DJB exchanged emails about his call for a disablenetwork() syscall. My point was basically that he was thinking about it the wrong way round. It shouldn't be a disablenetwork call, but a case of "I didn't explictly give you a network capability".
I also remarked that if you were going to go a capability you could also chroot() everything and give it a UNIX domain socket via which it could make its filesystem calls. This would make restricting programs pretty simple as you have one point of access for all filesystem control. (It would be a UNIX domain socket because they can have file descriptors passed between processes over them).
He suggested that few programs really need the filesystem (and would you look at the date on that?) and that it has more than security implications:
A small interface (for example, a descriptor allowing read() or write()) supports many implementations (disk files; network connections; and all sorts of interesting programs via pipes), dramatically expanding the user's power to combine programs. A big interface (for example, a file descriptor that allows directory operations) naturally has far fewer implementations.
Which is actually really cool. Most programs could do without the full fledged filesystem and it would be useful to be able to redirect their access down a pipe or socket. There are a number of problems with being able to do this that would probably need a kernel patch; mmaping for one and the problem of no being able to pass fds between machines.
Just testing...
That should be 3 SVG circles if your browser can handle it. Hopefully nothing explodes too badly.
If all the colours are wrong (it will look grey with lines going down it) then you're hitting a known bug in Mozilla. It's fixed in CVS.
Woooo....
librt.so.1 => /lib64/librt.so.1 (0x0000002a9566d000) libacl.so.1 => /lib64/libacl.so.1 (0x0000002a95785000) libc.so.6 => /lib64/libc.so.6 (0x0000002a9588b000) libpthread.so.0 => /lib64/libpthread.so.0 (0x0000002a95abb000) libattr.so.1 => /lib64/libattr.so.1 (0x0000002a95bd7000) /lib64/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x0000002a95556000)
Yes, that's a 30GB mmap...
open("/dev/hda", O_RDONLY) = 3
mmap(NULL, 32212254720, PROT_READ, MAP_SHARED, 3, 0) = 0x2a9589d000
processor : 0 vendor_id : AuthenticAMD cpu family : 15 model : 5 model name : AMD Opteron(tm) Processor 242 stepping : 1 cpu MHz : 1595.065 cache size : 1024 KB fpu : yes fpu_exception : yes cpuid level : 1 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx mmxext lm 3dnowext 3dnow bogomips : 3178.49 TLB size : 1088 4K pages clflush size : 64 processor : 1 vendor_id : AuthenticAMD cpu family : 15 model : 5 model name : AMD Opteron(tm) Processor 242 stepping : 1 cpu MHz : 1595.065 cache size : 1024 KB fpu : yes fpu_exception : yes cpuid level : 1 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx mmxext lm 3dnowext 3dnow bogomips : 3185.04 TLB size : 1088 4K pages clflush size : 64
Gentoo x86-64 hopefully comming soon...
nfs-utils 1.0.3 and 1.0.4 are buggy (1.0.4 is the one with the new xlog security patch). Use 1.0.1 and get the xlog patch from somewhere else and apply it manually.
If you get a motherboard with a `3COM 3c940' builtin (it doesn't exist in a standalone from at the moment) the driver you need is actually an sk98. I have the patch handy if anyone ever needs it.
Nuclear landmines (and no, it's not the Yanks again this time).
The nForce2 chipset (from nVidia) is popular for AMD systems at the moment, just don't buy one if you're running Linux. nVidia supplies drivers from its website for the builtin network, gfx and audio (possibly others, I didn't get that far) as modules - more than slightly frustrating for a NFS root. Still, I managed to get the driver into the kernel (including the closed source binary part) and it half works - the sending half.
The graphics part doesn't handle VESA DDC calls and seems to freeze completely with the nv driver.
In short, avoid unless you like waiting for nVidia to drip feed you closed source drivers.
Some people may have noticed that there's some documentation that has appeared in the CSG section in the site tree at the bottom. Since I haven't released the code you probably don't want to read it, but the interesting bit it that I just made up the tags. (If you see all the text stuck together then your browser doesn't like this - try Mozilla). Each of the functions looks a little like this:
<function> <name>function_name</name> <args> <arg><type>string</type><name>filename</name></arg> </args> </function>
And then I just define them in CSS:
function { background: #f3f6fd; display: block; margin-bottom: 30px; }
function > name { font-family: monospace; padding-bottom: 10px; display: block; color: #0000dd; }
function > name:before { font-family: Georgia, Times, sans-serif; content: "Name: "; color: #000000; }
function > args { display: block; margin-bottom: 10px; }
function > args:before { content: "Arguments: "; }
...
Mozilla renders it ok, Konqueror doesn't and I've not tried anything else. Is this in the slightest valid in XHTML? It certainly feels XMLish.
And if it is valid, why isn't the XHTML standard just a common CSS stylesheet? I'm pretty sure can define every HTML tag in CSS.
I should write more than I'm going to this entry, maybe I'll write the rest later on tonight.
But the main point is that my phone eloped with my modem and ran off to Nevada to get married over the weekend so:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 My number, current as of 14/7/2003 is +44 (0)7906 332512 AGL -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2 (GNU/Linux) iD8DBQE/Ewm6zaVS3yy2PWARApCVAKCQZvbUIYdzf/ue5Cdl9r3WYGIeYQCgvRM3 H4ki+BlNXHPm29KGiEF4A20= =jG6K -----END PGP SIGNATURE-----
| / | Root |
| Alternate | The Weird and Wonderful |
| Backlinks | What are backlinks |
| John Gilmore | What's Wrong with Copy Protection |
| Archives | Blog Archives |
| One | Archive 1 |
| Two | Archive 2 |
| Three | Archive 3 |
| Four | Archive 4 |
| Five | Archive 5 |
| Six | Archive 6 |
| Seven | Archive 7 |
| Eight | Archive 8 |
| Nine | Archive 9 |
| Ten | Archive 10 |
| Eleven | Archive 11 |
| Twelve | Archive 12 |
| Thirteen | Archive 13 |
| Fourteen | Archive 14 |
| Fifteen | Archive 15 |
| Sixteen | Archive 16 |
| Seventeen | Archive 17 |
| Eighteen | Archive 18 |
| Nineteen | Archive 19 |
| Twenty | Archive 20 |
| Twenty One | Archive 21 |
| Twenty Two | Archive 22 |
| Twenty Three | Archive 23 |
| Twenty Four | Archive 24 |
| Twenty Five | Archive 25 |
| Twenty Six | Archive 26 |
| Twenty Seven | Archive 27 |
| Twenty Eight | Archive 28 |
| Twenty Nine | Archive 29 |
| Thirty | Archive 30 |
| Photos | Poor People Caught on Film |
| Jack and the Beanstalk | Jack and the Beanstalk |
| RIP Scan | Results of a Stage Scan Fire |
| Yosemite | Yosemite National Park |
| Projects | Incomplete things from the lab |
| Seagull's Bane | Linux Automounter |
| bttrackd | BitTorrent Tracker |
| CAPTCHA | CAPTCHA CGI script |
| Conserv | Console Serving |
| Deerpark | Using Tor with Firefox/1.1 (Deerpark) |
| DNSFix | Fixing DNS |
| Xovers | XTA Crossover Control |
| IAFS | Archive Org Storage |
| JBIG2 | JBIG2 Encoder |
| Verify | PGP Key Verifier |
| MaxFlow | Maximal Flow in Python |
| PyBloom | Bloom Filters in Python |
| pyGnuTLS | Python wrapping of GnuTLS |
| Sxmap | Apache SuEXEC Map |
| Hellard | Union Server Notes |
| Recordings | Free recordings |
| ICSM Choir | St Paul's Church |
| School | Ancient School Stuff |
| Writings | Who knows |
| Cap Systems | Capability Systems |
| Intro | Introduction to me |
| Suprema | JMC2 Group Project |
| MP Letters | Letters I've written to my MP |
| Sound | Sound With Dramsoc |
| SyncThreading | The wonders of user-land threads |