Search Results: "nate"

5 January 2009

Ben Hutchings: Searching for invalid object code

J r my Bobbio suggested that I should explain how I looked for packages affected by a compiler bug (Debian bug 506713; gcc bug 38287). I don't claim that this is a particularly good way to do it, but here it is: First, I identified a pattern to search for. Unfortunately I don't really understand the cause or fix for the bug, but I did have the example which led to this bug report: Debian bug 490999. The bad code was a stack-pointer-relative load immediately after a stack allocation (SPARC save instruction) where the offset was not adjusted for the stack allocation:
save  %sp, -112, %sp
ld  [ %sp + 0x40 ], %i5
I generalised this to:
save  %sp, offset1, sp
...
ld  [ %sp + offset2 ], register
where offset1 + offset2 < 0. Of course, this may be valid if the intervening instructions include a restore, branch or store to the effective stack location that the last instruction loads from. I ended up allowing up to 10 intervening instructions and examining a disassembly to work out which cases were valid. I looked up the instruction encoding for these two instructions. Thankfully SPARC is RISC so they are simple and regular: I took the dumb but effective approach of scanning entire files for this pattern rather than only scanning their code sections. This seemed to work - I got no false hits for non-code - but might not work for other patterns that could match ASCII text. I wrote the scanning program in Python, which is my default choice of language unless I know it's going to be too slow. I was hoping to be able to read the code files into arrays, but unfortunately the Python array type only supports the native byte-order (SPARC is big-endian and I was intending to use an x86 which is little-endian). I tried reading into a tuple using struct.unpack, which does support explicit byte-ordering, but this used so much memory for larger files that the program swapped to a crawl. So finally I resorted to reading the file into a string, doing a string search for '\x9d\xe3', rejecting matches that weren't appropriately aligned, then unpacking and comparing the code words from the point of the string match. (In Python 3.0 I would have to use the bytes type for this, as str is a Unicode string type.) So that's how I scanned single files. The next step was to find, unpack and scan all the SPARC shared libraries in the archive. (This particular code generation bug is understood to affect only PIC code, and that is normally only used in shared libraries.) I wrote functions to search Contents-sparc for shared library files - assumed to match the pattern ([^\s]*/lib[^/\s]+\.so(?:\.[^/\s]*)?) - and to parse Packages to find the filenames for the packages containing those files. The latter uses the debian_bundle.deb822 module from python-debian. The last key function downloads and unpacks a package using wget and dpkg-deb. I could have used the httplib module for downloading but I correctly anticipated that I'd need to restart the script several times so I wanted to cache the packages which was easier to do using wget. So, that's the explanation. If you really want to see it, here's the code.

Adrian von Bidder: I want one

Christmas is over, and unfortunately it comes with an Nvidia graphics chip, and I doubt the color calibration feature works under Linux. Nonetheless: I want one. Dual screen on a Laptop! Who wouldn't want that? And, in addition, a keyboard with a numeric keypad.

4 January 2009

Andrew Pollock: [tech] Feed breakage, Blosxom's shiteful RSS 0.91 implementation

(or echo "blosxom hold" sudo dpkg --set-selections) A few people had pointed out to me that my blog was appearing weirdly in Google Reader. I myself read my blog via Planet Debian and Planet Linux Australia, where it appears fine, so I hadn't noticed the problem first hand. I did some digging tonight with the Feed Validator, and I think I've figured it out. Funnily enough, it all started with a previous session with the Feed Validator... I wanted my blog to be UTF-8, with it being the new hotness and all. Blosxom was spitting it out as ISO-8859-1. I've just learned from this evening's debugging, that this is the behaviour of CGI.pm's header() function if not provided with the -charset parameter. I'd previously worked around this by defining my own content_type for the RSS and HTML flavours. In this file, I just put text/xml; charset=utf-8and text/html; charset=utf-8, respectively. Unfortunately, this then breaks Blosxom's internal HTML-escaping-for-RSS-feed code, which is conditional on the content type being XML:
if ($content_type =~ m \Wxml$ )  
        # Escape <, >, and &amp;, and to produce valid RSS
        my %escape = ('<'=>'&lt;', '>'=>'&gt;', '&'=&gt;'&', '"'=>'&quot;');  
        my $escape_re  = join ' ' => keys %escape;
        $title =~ s/($escape_re)/$escape $1 /g;
        $body =~ s/($escape_re)/$escape $1 /g;
       
This block of code was being ignored because the regex was anchored. "text/xml; charset=utf-8" didn't match "\Wxml$". Whenever I last had an attempt to make my blog's feed pass the Feed Validator, I must have edited the Blosxom source code to make this regex not be anchored. Then on November 11, 2008, I updated my Blosxom package to 2.0-14+etch1, to address CVE-2008-2236 (incidentally, there doesn't appear to be a Debian Security Advisory for this?), and my local modification got clobbered. That'll teach me to make local modifications and not put the package on hold. Blah. It seems I'm screwed, there's no way to have a well-formed UTF-8 RSS feed without requiring a source-code modification to Blosxom. I've either got to change the way the header() function is being called, or I've got to change the regex to allow me to specify a charset in the flavour file, and not disable HTML escaping. Speaking of screwed, Blosxom seems incapable of making a well-formed RSS 0.91 feed anyway. It wants to put the <pubDate> tag inside an <item>, which is a violation of the DTD. There's supposed to be one for the whole <channel>, not one per item (or "story" in Blosxom-flavour-speak). You can't just move that from the story flavour file to the head flavour file, because a pile of variables that you'd otherwise use seem to only get set on a per-story basis. Double blah. I'm starting to feel like Blosxom is outliving its usefulness, but I really do not feel like embarking on a wholesale move to a new blogging platform, I'm fairly entrenched.

Andrew Pollock: [tech] Mixing electricity and water: monitoring the cat water bowl with Nagios

(this is something I've had "in production" for many months now, I just haven't had the time or energy to do a proper write up about what I did) We have a cat water bowl, it looks like this: The cat water bowl Under "normal" circumstances, it usually lasts about seven days. So when our weekly routine is happening, we'll refill it on a Saturday whilst doing house chores, and it'll last until the following Saturday when it gets refilled. Unfortunately, sometimes our routine gets disrupted, and we forget. Sometimes, we travel and have a house-sitter, who may not pay as close attention to such things as ourselves. Once, one of our cats was licking the condensation off a chilled bottle of soft drink that was on the kitchen counter one evening, before we realised the water bowl needed refilling. Naturally, we felt like terrible pet owners. So I think it was some time around the 2008 Maker Faire, that I hatched the idea of having some sort of water sensor on the cat bowl, which would communicate to one of the various computers in house. At the Maker Faire, I bought a copy of Making things talk, and an Arduino starter kit, which consisted of a Diecimila board and a make-it-yourself proto shield. I also bought a little electronics starter kit, which consisted of a breadboard and various components, and a USB-TTL cable. I decided to use Bluetooth to communicate with the board, as I already had my MythTV setup using a Bluetooth keyboard and mouse, and it was within range of the water bowl. I decided against using Zigbee, because I didn't know anything about it, and I didn't want to add (or learn about) yet another wireless infrastructure just for this project. I should point out that I know very little about electronics. I'd never owned (or really used) a soldering iron until I embarked on this project. I took a basic soldering class at the Tech Shop, but I'd already assembled the proto shield by the time I took the class, so I'd pretty much figured it out. I had a very naive vision that I could just basically shove two wires in some water and it'd close a circuit and that would be my water sensor. Of course this didn't work, so I started hunting around on the Internet for a circuit that would do this. I happened upon a circuit (I don't seem to have retained the URL, so I can't link to it), which just consisted of a couple of transistors and some resistors. So I headed off to Fry's to try and buy the transistors I needed. I quickly discovered that I didn't have sufficient information to identify the transistors that I wanted, but I did happen to stumble upon a cheap assemble-it-yourself water alarm. It consisted of a PCB, and a transistor and some resistors and a buzzer. I bought a couple of these instead. Between studying the PCB and the circuit diagram that came with the alarm, I was able to reproduce it on my breadboard instead of on the PCB. Sure enough, placing the two probes in water closed the circuit. I replaced the buzzer with an LED so I could see what was going on. I attached the circuit to the Arduino proto shield, and had it feed into one of the digital I/O ports. I wrote some quick and dirty Wiring code so that when water not present (i.e. the circuit was open and no current was detected on that I/O port) the LED was switched on. Really at this point, I didn't need a microcontroller, I could have presumably achieved the same thing with a NOT gate. At this point, I wanted to make the sensor remotely queryable. I bought a BlueSMiRF Silver Bluetooth modem, which I attached to the TX and RX lines of the board (I first configured it by attaching the USB-TTL cable to it and using Minicom on my laptop). I extended the Wiring code to provide a rudimentary prompt, and accept a command to check if water was present. I think around this time it also dawned on me that I could use the digital I/O pins as a switch. When they're "high" they provide power. So rather than constantly running a current through the water, I only needed to briefly power up the water detection circuit, see if the circuit closed or not, and then report if water was present if it did. I much preferred this, as at the time, I was endeavouring to power the whole sensor off a 9 volt battery. I figured I'd get much better battery life if I wasn't running a current through the water the entire time. I should point out that I did some "tongue tests" in a glass of water while the circuit was powered up, and couldn't detect a difference between when the circuit was on or off. The last thing I wanted to be doing was zapping the cats! At this point, the Wiring and Arduino work was pretty much complete. I setup ser2net on the MythTV server, so that I could just connect to port 4000, and be connected to the water sensor.
apollock@icarus:~$ telnet teevee 4000
Trying 172.16.0.9...
Connected to teevee.andrew.net.au.
Escape character is '^]'.
ser2net port 4000 device /dev/rfcomm0 [9600 N81] (Debian GNU/Linux)
waterbowl> s
Water is present
waterbowl>
telnet> q
Connection closed.
apollock@icarus:~$
The Wiring code running on the Arduino board is checked in here. Next, I wanted to monitor this with Nagios. One thing I found with the Bluetooth connection was that it wasn't all that reliable. Not every connection to port 4000 resulted in a connection with the water sensor. I elected to write some standalone code that submitted results to Nagios by way of a passive check, rather than having Nagios try to actively monitor it. Again, trying to conserve energy, I decided to only check the sensor once every 8 hours. So I wrote a Python daemon, which tried to be as robust as possible. If at first it doesn't make a connection on its 8 hourly schedule, it keeps trying until it does. Nagios itself has some freshness detection for this monitor, so if no passive result is submitted within 8 hours and one minute, Nagios alerts that something is possibly wrong with the sensor itself. (The original intent was to deal with the situation where the battery went flat) This is the Nagios service definition I've got. Some of it may be unnecessary or redundant:
define service  
        host_name                       teevee
        service_description             Cat water bowl
        check_command                   check_stale!2!"Check water bowl monitor is on and reachable"
        normal_check_interval           480
        notification_interval           240
        active_checks_enabled           0
        check_freshness                 1
        freshness_threshold             28860
        max_check_attempts              1
        check_period                    24x7
        use                             generic-service
        stalking_options                o,w,c
        contact_groups                  everyone
 
The code for the Python daemon is checked in here. So everything was going swimmingly, apart from I couldn't get even 24 hours of monitoring on my conservative 3 times a day schedule, and the Bluetooth modem configured for all of its power saving options, and the water sensor itself only being powered on when it was performing a check. There wasn't much more I could do to try and reduce power consumption, at least with my limited electronics knowledge. Perhaps using Zigbee instead of Bluetooth would have helped, but I still think I'd have been going through 9 volt batteries more quickly than I'd have liked. I also had a brief foray into solar powering the board. I thought maybe the lighting in the house would be sufficient to power the board. Of course this didn't work out. I'd also have needed to make the code running on the board more self-sufficient, and have it just provide a water status indication whenever it had enough power to do so, instead of being a fairly dumb device like it currently is. This all felt a whole level more complicated, and out of my league, and I wasn't interested in attempting this sort of remote-sensing exercise at this time. The Arduino board can also be powered by USB, so as I already had some long USB type A to type B cables (that had funky lights in them to boot), I decided to just get a wall wart that had a USB type A receptacle, and powered the Arduino board that way. So much for being completely "wireless". (I could have also gotten a general purpose DC power supply that was capable of spitting out 9 volts, but I doubted I'd get one with a sufficiently long cable, which is why I went for the USB-powered option, as I already had a cable long enough) Speaking of wires, the most challenging part was the probes for the water sensor. As they were going to be permanently in the cats' drinking water, I didn't want to contaminate the water with them. I figured plain untinned copper wire would be okay, since water pipes are copper. Finding untinned, unstranded copper wire was a real challenge. I started out using some FM antenna cable, but that was stranded, and the shielding was a nightmare to strip. It was also reasonably difficult to make go where I wanted it. What I really wanted was something more solid, that would flex and stay where I put it. I cannibalised a spare IEC power cable, but it was also stranded copper wire. I finally managed to obtain some solid-core CAT-5 cable from a hardware store, and this has worked exactly as I wanted. I haven't done any further work on the setup since getting the CAT-5 cable for the probe. Further improvements that I'd like to do at some point: The finished product I had a lot of fun with this project. I had a real sense of achievement, being able to go from concept to completion, and learn a few things about electronics along the way. I'm normally not a fan of messing around with hardware. Some photos of the project are here.

Christian Perrier: [life] Keeping the running pace during holidays

Christmas holidays in France are not a good season for runners: too much champagne, foie gras, cheese, wine and food in general. So, while visiting my mom and sister in the region of St-Etienne last week, I wanted to keep my sports pace to a sufficient level as we're now 3 months ahead from this marathon I've been crazy enough to apply for. That went good: 3 days after my first run over 30km, my brother in law convinced me to enjoy the big snow fall in Le Bessat, the ski station of my young years, 30 minutes away from the city of St-Etienne. That was the second time ever I'm doing croos-country skiing in skating technique. But, being supposedly used to skiing in general (20 years of ski are supposed to help), we went on the longest and hardest track: 16km and over 200m positive slope....which I completed in less than 2 hours, so a lot more than the same distance by running. Cross-country skiing in skating technique is awfully hard, particularly when you have no technique at all..:-)) To complete this, I went running for about 12 km on New Year, 3 hours after partying for New Year's Eve. Interesting way to eliminate the weight surplus..:-) And, finally, today, I went out for a 19km run in the frozen country around my place (-8 degrees) for a wonderful discovery of woods covered with ice and the climbing of the highest "mountain" in the Paris area (280m height, still !) and a great view of the neighbourhood in white, under the sun. These are the joys of running in winter, really.

3 January 2009

John Goerzen: Garmin Nuvi 500

I ve owned two different GPSs in the past: a Garmin GPS III, and the Garmin eMap. Both are based on similar underlying firmware. This week, I did some research on more modern GPS units and decided to buy a Garmin nuvi 500. Here s my review. Overview The Garmin nuvi 500 is one of only two models in the nuvi line that are waterproof. The nuvi 500 and 550 are both designed as hybrid units: useful both in the car and outdoors. The 500 includes street-level maps (they appear to be the same quality as Google) for the entire United States, detailed topographical maps for the entire United States, and a global basemap. It also includes a microSD slot (or is it miniSD - I forget) for additional maps that you can buy anything from marine maps to other countries. It also includes a default POI (points of interest) database containing over 5 million points: restaurants, gas stations, parks, hospitals, you name it. Most contain an address and a phone number in additional to the coordinates. Unlike GPS units that you find built in to some cell phones, this is all stored on flash memory on the unit: no Internet connection required. The nuvi 500 is a portable yellow pages, topographical map, and incredibly detailed street atlas all in one. Car Use The nuvi 500 comes with a car charger and suction cup windshield mount in the box. (It doesn t come with an AC charger, but it can charge over USB.) It also comes with yay a user-replaceable battery. The windshield mount is very sturdy and I am happy to have one that isn t permanent. In the car, the device performs admirably. I have read some other reviewers that have compared its routing to other GPSs and found that the nuvi generally picks the same route as Google, and almost always a better route than other GPSs. If you deviate from the selected route, it automatically re-calculates a new route for you. It will show you the next turn coming up, and has either 3D or flat map displays. There s a one-touch where am I feature. It displays your current coordinates, some sort of street address suitable to read to someone ( 1234 S. Main or I-95 exit 43 type of thing), along with buttons to show you the nearest police stations and hospitals. The unit also features multi-stop routing. You can either tell it where all you re going in a defined order, or tell it all your stops and let it create an optimal route. This feature works, but it your stops are close by (and involve some of the same roads), it may wind up skipping some stops thinking you ve made your first one. The speaker announces upcoming maneuvers, though it doesn t have a synthesizer for street names. It s also supposed to work with Bluetooth headsets, though I haven t tested that feature. I found the map quality to be excellent. It seems to be on par with Google (in fact, I think both use data from Navteq). I was surprised with how many country dirt roads and side roads it knows about and of course, regular city streets are all on there, with one-way indications and the whole lot. In fact, the quality of coverage was so good that I was surprised when it missed roads or got things wrong. Out in rural areas, or small towns, this happens from time to time: it thought that an abandoned railbed was an unnamed road and wanted me to drive on it (it was clearly not drivable), and in some other cases also thought some abandoned roads were still drivable. I don t think this is a device issue though; it s an underlying data issue, and everyone else probably has the same problem. Its arrival time estimates are quite accurate, and its interface is smooth and easy. It has some optional accessories I haven t tried, such as real-time traffic reports from wireless sources, boating mode, etc. Outdoor and Geocaching Mode Our other main use for the device is outdoor hiking and geocaching. It really shines here. It has special support for the GPX files from geocaching.com. The device supports paperless caching . Not only can it put caches on the map, but if you download the GPX file for your caches, you ll also get the full description, hint (behind a separate button, of course), most recent 5 logs, and the like right there on your screen. You can also log your finds on the device, and upload a file from it to geocaching.com later to log them on the site. This is an incredible time saver over my old method: printing out a bunch of maps, downloading waypoints to the eMap, taking notes, then logging things later. I found outdoor mode not quite as refined as the auto mode, however. It kept forgetting that I wanted to use an arrow as my current position indicator (the default hiking boots for walking mode didn t provide an accurate enough direction indication for my tastes). Finally realized that saying don t ask me about the configuration was the key to getting it to remember the configuration. It sometimes took a surprisingly long time to realize we weren t standing still any longer. On the other hand, the quality of the GPS receiver was amazing. It even got a strong signal in my house. And I wasn t even sitting at a window. The topographical maps are a nice addition, and the breadcrumb mode is always helpful when geocaching and hiking, too. My natural way of holding it meant that I accidentally turned it off a few times, because I had a finger holding it right over the power button. But it powers back up and re-obtains the signal quite rapidly. The different modes (automobile, outdoor, bicycle, and scooter) are mainly different collections of settings: 3D map or flat, what indicator to use, to navigate off-road or along roadways, to ignore one-way indications or heed them, etc. PC link The nuvi 500 has a USB port. Plug it into the PC, and you see its internal flash drive, vfat formatted. You can upload and download GPX files there, store photos if you like. Be careful what you mess with though, because its built-in maps and system data are also on that drive. If you have the SD card inserted, that will also be presented to your computer when you plug the device in. Garmin has some Windows software to make it easier to upload/download stuff, but I haven t tried it. Annoyances As you can tell, I really like this GPS, but there are a few things about it that annoy me. The #1 thing that annoys me isn t actually the GPS itself, but Garmin s website. I went to register the device online, but it wouldn t let me because I don t have the Windows-only browser plugin on my Linux machine, and it wanted to talk to the GPS for some reason. I went to send them a support request about that, only to discover after I had typed in the request that their email us form is broken in Firefox on all platforms. Bad show, Garmin. The on-screen keyboard (it s a touch-screen device with only one hard button for power) isn t QWERTY layout; it s alphabetical layout, and it makes me inefficient when entering data. I found myself logging my finds on the unit, but taking notes about them on paper because that was faster. Garmin has a feature listed on their website for a toggle between QWERTY and alphabetical layout, which they apparently offer on only their more expensive GPSs. What? There is no reason to not but that in all your firmware. The device lacks a few features I was used to on my GPS III and eMap. It doesn t support any kind of real-time position indication to the PC; all communications is just accessing stored data on the internal flash drive. I used to think that was a nice feature, but in reality, I haven t used it in years. It also lacks the display of the exact location of each GPS satellite, though the incredible quality of its receiver means that I don t really care any more. (I used to use that information to help figure out which window to put it by if in a car/train or something.) It also lacks the level of configuration that was present in the settings screens on the older units. There s no battery saver mode (sample every 5 seconds when going at a constant velocity instead of every 1) like the older units had. The sun and moon screen likewise is gone, but added is awareness of timezones; the Nuvi 500 can show you the local time at your present position synced up with the GPS satellites. The compass is not the most helpful screen, though after some practice, it is functional. The documentation about it is confusing, but really the thing that was more confusing was this: in walking mode, the arrow that indicates what direction you re walking in updates faster than the arrow that indicates what direction you should be walking in. Once I realized what was going on there, it was easier to use. The compass does tell you what your bearing is, in degrees, but only when you are not seeking a destination. It will not tell you the bearing to the destination, though you can estimate it from the simulated compass face on the display. When seeking a specific point, especially through terrain with obstacles such as trees, it is useful to be able to use a compass for the final approach because a GPS unit can t tell you which direction it s pointed only which direction it s moving, so when you re not moving or moving slowly, it s not helpful. I did some experimentation today with the compass screen, as well as my real compass, and was able to navigate to my destination rather precisely using the combination of them. That said, a more functional compass screen would still be better. Conclusion Overall, I m very happy with the nuvi 500. It s not the same as a top-of-the-line device in either the outdoor or automotive category, but on the other hand, it s cheaper and more convenient than buying two devices with similar features. The geocaching features are excellent, the build quality is excellent as well. The system is stable and performs well. (Some other reviews worried about whether the case is solid enough; it seems quite solid to me.) I wish there were a faster way to toggle between 3D and flat map views, and forgetting about my walking mode icon is annoying, but other than that I have very little to complain about. Garmin s geocaching features (found on this unit and several other in their lineup) is great.

2 January 2009

Michael Casadevall: Notes from Underground, Part 1

For those following d-devel, you may notice that I've recently been working on improving one of the cornerstones of Debian infrastructure; the Debian Archive Kit, or dak for short. Most DDs and DMs don't notice dak exists expect when trying to determine why their latest upload was rejected, and then yelling at the powers that be. I'm here to shead some light on this mythicial beast.

First off, a quick history lesson:

dak (also known as projectb) is a replacement for Debian's original archive software, known simply as dinstall. dinstall itself was a fairly large perl script that does what dak process-unchecked/process-accepted does today. James Troup did a fairly decent summary of dinstall, and its issues

James Troup's README.new-incoming (from dak's git repo):

The old system:
---------------
o incoming was a world writable directory

o incoming was available to everyone through http://incoming.debian.org/

o incoming was processed once a day by dinstall

o uploads in incoming had to have been there > 24 hours before they
were REJECTed. If they were processed before that and had
problems they were SKIPped (with no notification to the maintainer
and/or uploader).

dak's first commits were in 2000, and rolled out onto ftp-master.d.o sometime in 2001 or 2002 (I can't find an exact date for this). Since then, dak is also used on security.d.o, and on backports.org (fun fact for bpo people; the dak installation there is now up to date, and tracking git's tip).

So now that you know the history lesson, what specificially does dak do is the next question. Simply put, dak is the glue that binds the rest of the Debian's backends together; both britney and wanna-build/buildd depend on it. It handles management of uploads to the archive, handles stable release updates, as so forth. It is also the only Debian archive software that uses an actual database backend, and scales fairly well handling over 10,000 packages, and 12 architectures. Unfortunately, there are also a lot of issues with dak as it stands.

Sections of the code base have bitrotted over the years; legacy and legacy-mixed support have died, the import-archive function is shot (more so now than ever, see below), the test suite is non-functional (never a good sign), the docs are out of date, and in many places non-existant, doing a release (both point and full) requires editing the database and so forth.

In addition, dak, while written in python, is written in a fairly procedural style, and and some very ugly code in some places. For instance, the original Debian Maintainer code was handled by having the uid's in the database prefixed by dm: vs having a flag somewhere, and had some hardcoded variables like checking for "unstable", as well as quite a few bugs which caused interesting behavior when uploading to a non-unstable suite such as experimental or one of the proposed queues. (for those of curious, I recommend checking the dak git tree to see what the old DM code looked like, and then aside from the design, find the two major bugs which caused a lot of the weirdness with DMs). It should be stated that the last merge from redid the DM code and design sanely using the new update framework.

These issues have lead to the genesis of the dak v2 project, which is an attempt to replace dak with a module, rewritten from the ground up to be more secure and modular, although its not gotten very far as of writing. I personally don't believe that the current iteration of dak is so bad as scrapping and rewritting is necessary. Instead, I've been working to implement v2 features in dak by aggressive refactoring and cleanup, with the hope of negating the need for a rewrite.

So now thats out of the way, I bet you probably are interested in my .plan for dak. Well, lets go over I've implemented so far.

* An update database framework for dak, which will allow for easy database upgrade and migration, vs the "does it work yet?" approach to applying schema updates. Simply type dak update-db, and your done!

* 822 formatted output for queues (http://ftp-master.debian.org/new.822); this information is now used on DDPO pages

* Rewriting DM management code to have more of a brain than the previous implementation.

What's next on the TODO list

* Content file generation from the database (part of removal of apt-ftparchive, but thats another blog post ;-)).

Oh, as a side note to my current readers, my blog has changed names to "Notes from Underground", after one of my favorite novels, and futher in reference to exploring the mysterious underground that is Debian's backend code. We're also now on Planet Debian :-).

31 December 2008

Andrew Pollock: [tech] Goodbye Vonage, hello T-Mobile@Home

When we first moved to the US, I wanted to try and do the telecoms and Internet stuff as cheaply as possible, while still trying to be technologically "fun" as well. I elected to get the cheapest home phone line (local calls only) I could get with AT&T (then SBC) (which is still remarkably expensive) so that I could get DSL (which, while three times faster than what I'd had previously in Australia, was still not that fast). (I went for DSL over cable because I'd heard horror stories about Comcast's reliability, and also they weren't cool with running servers or inbound services, Sonic is, and is a great ISP). I chose Vonage for US long-distance, I think because I'd heard of them previously, and was interested in trying out VoIP. We initially used Vonage for calling Australia as well, until I played around with Engin, and then deployed Asterisk. Anyway, I've been a loyal Vonage customer for exactly three years. The truth is, we hardly make any US long distance calls. We've got friends in Phoenix (hi Craig and Sarah!) that we call infrequently. I guess there might be the odd cell phone that isn't considered a local call, but we tend to use our cell phones more than the home phone anyway... So we were a very cheap $14.99 a month for Vonage. So when I called T-Mobile to purchase a SIM card for the Android Dev Phone 1 I'd been recently given, the opportunity to have their T-Mobile @Home in place of Vonage, for an extra $9.99 on top of what I was paying for the cell phone line seemed like worthwhile cost saving. I have no attachment to the incoming number for the Vonage line, we give out the AT&T land line number to people as our "primary" home number. Later that day, Vonage announced they were increasing their monthly fee from $14.99 to $17.99, which made the decision seem all the more prodigious. I did a spot of research while I was waiting for the @Home box to ship to me, and it turns out that they have a wireless router and non-wireless router option. They hadn't specified what I was getting at order time, and I was hoping I'd get the non-wireless router, since I already had an access point I was perfectly happy with it. As luck would have it, I received the wireless router model (a Linksys WRTU54G-TM). I'd mentally prepared myself to be receiving just another Linksys RTP300, like what Vonage used, and so I was quite surprised by the differences in technology used. It's been a while since I tried to do any reverse-engineering of the Vonage ATA, but I think from memory, it was essentially that: an ATA. It talked SIP back to Vonage. My DSL provider gave me a few static IP addresses, so when I got it, I just allocated one for Vonage, and did a static NAT through my firewall to for it, and everything just worked. It was fairly apparent that the WRTU54G-TM was nothing at all like this (given it was also an access point). It takes a GSM SIM card (up to two in fact), which I presume has all of the provisioning information on it. I was initially worried that I was going to need to completely rejig my network to accommodate it. I guess the SIM card approach means there's no customer specific provisioning that presumably otherwise needs to be done to the device itself, and they can just ship vanilla devices. I presume the Vonage RTP300 had some sort of customer-specific configuration, because I never had to do anything. I briefly toyed with the idea of running two access points, and having a "guest" wireless network, but I am interested in reducing heat and power consumption in my linen cupboard, so I decided to try and just swap over to using the WRTU54G-TM as my access point, retiring my Linksys WAP54G. So that's exactly what I sat down to do last night. Sometimes in their efforts to make these things "simple", they end up making things more complicated. What I wanted to do was just plug the "Internet" side of the device into my internal network, have it get an IP address with DHCP, and then let me get on with configuring it. The "advanced" setup instructions talked about the box having a default IP address of 192.168.0.1 ("or try 192.168.24.1 if that doesn't work"). I figured the DHCP IP address would override that, so I was trying to hit the IP address I could see the unit had picked up from my DHCP server. No response from the HTTP server. I could see it replying to ARP requests, and I could see what appeared to be an IPsec NAT-T connection. After some fiddling around, I twigged that I was trying to manage it over the Internet port, and any device worth its salt was going to be very hardened out of the box on what it expected to be the raw Internet-facing side, so I plugged my laptop directly into one of the four Ethernet ports that it also had, and then I could hit the 192.168.0.1 IP address and access the management interface. It never occurred to me prior to fighting with getting the WRTU54G-TM configured, that the RTP300 might have been more than a black box, as I'd never tried plugging anything into the "inside" ports on it, mainly because I'd never intended to use it as a router or a switch. Out of the box, the WRTU54G-TM was configured to be a router, which I didn't need, and it was configured to be a DHCP server for 192.168.0.0/24, which I definitely didn't want. An interesting side-effect of putting it into bridging mode was the MAC address changed (to the one that was printed on the unit, which was not how out of the box it presented itself). I have no need or intention of plugging anything into the "inside" Ethernet ports on the WRTU54G-TM, as I have a separate switch for that, and indeed I run my wireless network on a different interface of my firewall to my wired network. Fortunately I was able to enable the management interface via the "Internet" interface. The added benefit of the device doing NAT-T is I don't need to allocate an IP address to it for the VoIP stuff it work, it all just works fine without it, so I've freed up an IP address, removed two devices from my linen cupboard, added one new one, and saved some money. Woot! Next, just because I can, I'm going to try and break into the RTP300 and see if I can reconfigure it as a general purpose ATA to talk to Asterisk. There's evidence it's possible. It's otherwise of no further use to me. Even if I get it working with Asterisk, it's not of a lot of use to me. Maybe I can send it to a family member, and they can call us over the Internet for free instead of for the cost of a call to Brisbane...

Joachim Breitner: Handling explicit and implicit recusion in Haskell data

For a while I have been pondering over a problem that arises when your functionally written program has some state with cross references for example a list of users, each of which uses a number of computers, and a list of computers, each having an owner. Implicit referencing For doing queries on such data, it would be convenient if every reference is just the referenced object itself. Although we would visualize this as a graph, semantically, it is more like an infinite tree. This is possible in Haskell, due to laziness, and if you create the data structure cleverly, it even uses constant memory, no matter how deep you enter this infinite tree (a recent post of mine talks about this). A possible data definition would be:
data User = User  
userName :: String,
uses :: [Computer]

data Computer = Computer
computerName :: String,
owner :: User -- references the Users

data State = State [User] [Computer]

testState = let user = User "Conrad" [computer]
computer = Computer "Z3" user
in State [user] [computer]
Explicit referencing But such a representation is very unsuitable for updates (at least I can t think if a nice way of updating such a graph without breaking the internal cross-references) and serialization, which is a must for a HAppS based application. So what one would probably start with is this data structure:
data User = User  
userId :: Int,
userName :: String,
uses :: [Int] -- references the Computers

data Computer = Computer
computerId :: Int,
computerName :: String,
owner :: Int -- references the Users

data State = State [User] [Computer]

testState = State
[User 0 "Conrad" [1]]
[Computer 1 "Z3" 0]
I think the semantics of this are clear. Note that the referencing is currently not type-safe, but this can be provided by phantom types. Maybe I ll write more about that later. Now imaging you want to display the information about the first computer with your web application. You extract the information with let State _ cs = testState in head cs and pass that to your templating engine. But what if your template wants to display the name of the owner? It only has access to his userId. You would either need to know what information the template will ever need, extract that from the state beforehand and pass it along, or give the template access to the whole state. In that case, though, there has to be lookup-logic in your output code, which is also not nice. Woudln t it be nice if you could, in your application logic, work with the explicit references, which are easy to modify and store, but somehow turn that into the implicit referencing? Duplicated representation One way would be to have two unrelated sets of data structures, ExplicitState, ExplicitUser, ExplicitComputer, which use explicit identifiers to reference each other, and ImplicitState,... which are defined as the first representation of our state. It is then mostly trivial to write a function that converts ExplicitState to ImplicitState. The big disadvantage of this is that you have to maintain these two different hierarchies. It also means that every function on the state has to be defined twice, which often almost identical code. Clearly, this is not desirable. Annotated representation It would be more elegant if the state is stored in one data type that, controlled by a type parameter, comes in the one or the other representation. To do that, we need two types: One that contains a value, and one that contains just a reference:
newtype Id v = Id v deriving (Show, Typeable, Data)
newtype Ref v = Ref Int deriving (Show, Typeable, Data)
Then we need to adjust our data definitions, to make use of these. (I ll leave out the names, to keep the code smaller)
data User ref = User  
userId :: Int,
uses :: [ref (Computer ref)]

data Computer ref = Computer
computerId :: Int,
owner :: ref (User ref)

data State ref = State [User ref] [Computer ref]
Here we introduce a type parameter ref , which will later be either Id or Ref. Note that now a reference also states the object it is a reference for, which greatly increases type safety. Functions on these data types that don t work with the references will be polymorphic in the ref type parameter, so only need to be written once. A User Id is a complete user with all related data, while User Ref is a user with only references. And a Ref (User Ref) is reference to a user, which contains references... Not so kind kinds Did you notice the lack of a deriving clause? Our data structures have the relatively peculiar kind ((* -> *) -> *), which makes it hard for the compiler to derive instances for things like Show. But we already know that we will only use Id or Ref for the type variable, so we can use ghc s StandaloneDeriving language extension and have these instances created:
deriving instance Show (User Id)
deriving instance Show (User Ref)
deriving instance Show (Computer Id)
deriving instance Show (Computer Ref)
deriving instance Show (State Id)
deriving instance Show (State Ref)
Toggling a type parameter The next step is to write the conversion function. It will have type
unrefState :: State Ref -> State Id
For that, and for later, we need lookup functions:
unrefUserRef :: State Id -> Ref (User Ref) -> Id (User Id)
unrefUserRef (State l _) (Ref i) = Id $ fromJust $
find (\u@(User i' _) -> i == i') l
unrefComputerRef :: State Id -> Ref (Computer Ref) -> Id (Computer Id)
unrefComputerRef (State _ l) (Ref i) = Id $ fromJust $
find (\u@(Computer i' _) -> i == i') l
These expect a State (with implicit referencing) and a reference, and look up this reference. The function unrefState then looks like this:
unrefState :: State Ref -> State Id
unrefState (State us cs) =
let unrefState = State (map (unrefUser unrefState) us)
(map (unrefComp unrefState) cs)
in unrefState
where unrefUser :: State Id -> User Ref -> User Id
unrefUser s (User i refs) = User i (map (unrefComputerRef s) refs)

unrefComp :: State Id -> Computer Ref -> Computer Id
unrefComp s (Computer i ref) = Computer i (unrefUserRef s ref)
Note how we tie the knot in the let expression. This is the trick that ensures constant memory consumption, because every reference points back to the same place in memory. Satisfied already? So what do we have? We have no duplication of data types, we can write general functions, and we can resolve the explicit referencing. We can also easily write functions like unrefUser :: State Ref -> User Ref -> User Id, which transform just a part of the state. But writing unrefState is very tedious when the State becomes more complex. Each of the other unrefSomething functions are very similar, but need to be written anyways. This is unsatisfactory. What we want, is a generic function, something like
gunref :: State Ref -> a Ref -> a Id
which, given a state with explicit references, replaces all explicit references in the first argument (which could be State Ref or User Ref or anything like that) with implicit ones. This function can not exist, because we would not know anything about a and b. But maybe we can do this:
gunref :: (Data (a Id), Data (a Ref)) =>  State Ref -> a Ref -> a Id
Typeable and Data Before being able to do so, we need to derive Data for our types. We can start with
deriving instance Data (User Id)
deriving instance Data (User Ref)
deriving instance Data (Computer Id)
deriving instance Data (Computer Ref)
deriving instance Data (State Id)
deriving instance Data (State Ref
but that will complain about missing Typeable instances. Unfortunately, ghc s deriver for Typeable (even the stand-alone-one), does not handle our peculiar kind, so we need to do it by hand. With some help from quicksilver on #haskell, I got it to work:
instance Typeable1 ref => Typeable (User ref) where
typeOf _ = mkTyConApp (mkTyCon "User") [typeOf1 (undefined :: ref ())]
instance Typeable1 ref => Typeable (Computer ref) where
typeOf _ = mkTyConApp (mkTyCon "Computer") [typeOf1 (undefined :: ref ())]
instance Typeable1 ref => Typeable (State ref) where
typeOf _ = mkTyConApp (mkTyCon "State") [typeOf1 (undefined :: ref ())]
everywhere is not enough Turning to the documentation of Data.Generics, I notice with some disappointment that there is no function that is able to change a type they all seem to replace a value by another value of the same type. But the functions gfoldl and gunfold sounded like they could be used for this. Warning: What comes now is a very non-haskellish hack that subverts the type system, just to get the job done. Please read it with a healthy portion of distrust. If you know of a cleaner way of doing that, please tell me! Wrapped Data I want to do some heavy type hackery, so I need to disable haskell s type system. There is Data.Dynamic, but not even that is enough, as we need to carry a type s Data instance around as well. So let s wrap that up:
data AData where AData :: Data a => a -> AData
instance Show AData where show (AData a) = "<" ++ show (typeOf a) ++ ">"

fromADataE :: forall b. Data b => AData -> b
fromADataE (AData d) = case cast d of
Just v -> v
Nothing -> error $ "Type error, trying to convert " ++
show (typeOf d) ++ " to " ++
show (typeOf (undefined :: b)) ++ "."
There is also a function that converts an AData back to a normal type, if possible. If it s not possible, then there is a bug in our code, so we give an informative error message. AData transformers Similar to everywhere, we want to have transformers that combinable. They need to have the change to convert an arbitrary value, but also signal that they could not convert something (and this something has to be recursed into). I came up with this:
type ADataT = AData -> Maybe AData

extADT :: forall a b. (Data a, Data b) => ADataT -> (a -> b) -> ADataT
extADT at t a@(AData v) = case cast v of
Just x -> Just (AData (t x))
Nothing -> at a

doNothing :: ADataT
doNothing = const Nothing
ADataT is the type for such a transformer. doNothing will not transform anything, and extADT can be used to add any function to the list of tried transformers, in the spirit of extT. The ugly part To apply such a transformer, I want to use this function, which I ll describe in the code comments:
everywhereADT :: forall a b. (Data a, Data b) => ADataT -> a -> b

-- first check if we can transform this value already
everywhereADT f v = case f (AData v) of
-- if so, coerce it to the users requested type, which hopefully goes well
Just r -> fromADataE r
-- if not, we need to recurse into the data structure
Nothing -> recursed

-- for that, we first need to figure out the arguments to the
-- constructor. We store them in the untyped list
where args :: [AData]
(Const args) = gfoldl k z v
-- gfoldl lets us have a look at each argument. We wrap it in AData
-- and append it to the list
k (Const args) arg = Const (AData arg : args)
z start = Const []

-- We need the data constructor of the input data type. If the user did not want
-- it to be transformed, it will be the same
c = toConstr v

-- To give better error messages, we make sure that the outmost type constructor
-- of the requested type actually has the data constructor we were given. Otherwise
-- gunfold will complain in a non-helpful way
input_type = dataTypeRep (constrType c)
output_type = dataTypeRep (dataTypeOf (undefined :: b))

recursed = if input_type /= output_type
then error $ "Can not convert <" ++ show input_type ++ ">"++
" to <" ++ show output_type ++ ">."
-- the types match, so we assemble the output type, using gunfold
else snd (gunfold k' z' c)
k' :: forall b r . Data b => ([AData], b -> r) -> ([AData],r)

-- we start by reversing the input list
z' start = (reverse args,start)

-- then we call us recursively on the argument and feed the result
-- to the output constructor
k' ((AData a) : args, append) = (args, append (everywhereADT f a))

-- Used for folding (we don t need to retain the original constructor)
data Const a b = Const a
What a beast! But surprisingly, it works. Here are some examples. Note that I always have to specify the requested output type:
bool2Int :: Bool -> Int
bool2Int False = 0
bool2Int True = 1

*Main> everywhereADT (doNothing extADT bool2Int) True :: Int
1
*Main> everywhereADT (doNothing extADT bool2Int) True :: ()
*** Exception: Type error, trying to convert Int to ().
*Main> everywhereADT (doNothing extADT bool2Int) (True,False) :: (Int,Int)
(1,0)
*Main> everywhereADT (doNothing extADT bool2Int) ([True,False],True,()) :: ([Int],Int,())
([1,0],1,())
*Main> everywhereADT (doNothing extADT bool2Int) ([True,False],True,()) :: [()]
*** Exception: Can not convert to .
*Main> everywhereADT (doNothing extADT bool2Int) [True] :: [Bool]
[*** Exception: Type error, trying to convert Int to Bool.
I hope this code does not inflict too much pain on any Haskell-loving reader. I know I violated the language, but I didn t know how to do it better (at least not without using Template Haskell). I also know that this is not very good performance wide: Every single value in the input will be deconstructed, type-compared several times and re-assembled. If that is an issue, then this function should only be used for prototyping. Almost done To apply this to our state, we only need to glue it to our lookup functions from above:
gunref :: (Data (a Id), Data (a Ref)) =>  State Ref -> a Ref -> a Id
gunref s w = let unrefState = gunref' unrefState s
in gunref' unrefState w

gunref' :: (Data (a Id), Data (a Ref)) => State Id -> a Ref -> a Id
gunref' unrefState = everywhereADT unref'
where unref' = doNothing extADT
unrefUserRef unrefState extADT
unrefComputerRef unrefState
Now we have a generic unreferencer. I set the type a bit more specific than necessary, to make it safe to use (under the assumption that the list of lookup functions is complete and will not leave any Ref in the output).
*Main> testState 
State [User userId = 0, uses = [Ref 1] ] [Computer computerId = 1, owner = Ref 0 ]
*Main> gunref testState testState
State [User userId = 0, uses = [Id (Computer computerId = 1, owner = Id (User userId = 0,
uses = [Id (Computer computerId = 1, owner = Id (User userId = 0, uses = ..
Oh, and by the way, if you want to test this code, you ll need at least:
 -# LANGUAGE DeriveDataTypeable, FlexibleInstances, GADTs,
FlexibleContexts, StandaloneDeriving, ScopedTypeVariables #-

29 December 2008

David Moreno: Good looking Irb

Irb is a pain to work with when you don t know it enough. Fortunately, it can be configured extensively enough to make your Ruby interactive sessions much smoother. Pocahontas asked me to post my Irb configuration:
# ~/.irbrc
IRB.conf[:AUTO_INDENT] = true
IRB.conf[:USE_READLINE] = true
IRB.conf[:SAVE_HISTORY] = 5000
IRB.conf[:HISTORY_FILE] = "# ENV['HOME'] /.irb_history"
IRB.conf[:PROMPT_MODE] = :SIMPLE
require 'irb/completion'
require 'irb/ext/save-history'
require 'pp'
# load rubygems and wirble
require 'rubygems' rescue nil
require 'wirble'
require 'utility_belt'
# load wirble
Wirble.init
Wirble.colorize
Which makes Irb to look much much better: irb But it is not only coloring the features you are getting, but also Readline support, command history saving, tab completion, libraries loaded by default, persistent history with Wirble, etc, etc. as you can see yourself on the very self-explanatory configuration file. Enjoy. Update: I have to thank my co-worker Galin for pointing me most of these neat features.

28 December 2008

Theodore Ts'o: Debian, Philosophy, and People

Given the recent brouhaha in Debian, and General Resolution regarding Lenny s Release policy as it relates to Firmware and Debian s Social Contract, which has led to the resignation of Manoj Srivastava from the position of Secretary for the Debian Project, I m reminded of the following passage from Gordon Dickson s Tactics of Mistakes (part of Dickson s Childe Cycle, in which he tells the story of the rise of the Dorsai):
No, said Cletus. I m trying to explain to you why I d never make an Exotic. In your calmness in the face of possible torture and the need to kill yourself, you were showing a particular form of ruthlessness. It was ruthlessness toward yourself but that s only the back side of the coin. You Exotics are essentially ruthless toward all men, because you re philosophers, and by and large, philosophers are ruthless people. Cletus! Mondar shook his head. Do you realize what you re saying? Of course, said Cletus, quietly. And you realize it as well as I do. The immediate teaching of philosophers may be gentle, but the theory behind their teaching is without compunction and that s why so much bloodshed and misery has always attended the paths of their followers, who claim to live by those teachings. More blood s been spilled by the militant adherents of prophets of change than by any other group of people down through the history of man.
The conflict between idealism and pragmatism is a very old one in the Free and Open Source Software Movement. At one end of the spectrum stands Richard Stallman, who has never compromised on issues regarding his vision of Software Freedom. Standing at various distances from this idealistic pole are various members of the Open Source Community. For example, in the mid-1990 s, I used to give presentations about Linux using Microsoft Powerpoint. There were those in the audience that would give me grief about using a non-free program such as MS Powerpoint, but my response was that I saw no difference between driving a car which had non-free firmware and using a non-free slide presentation program. I would prefer to use free office suite, but at the time, nothing approached the usability of Powerpoint, and while dual-booting into Windows was a pain, I could do a better job using Powerpoint than other tools, and I refused to handcap myself just to salve the sensibilities of those who felt very strongly about Free Software and who viewed the use of all non-Free Software as an ultimate evil that must be stamped out at all costs. It is the notion of Free Software as a philosophy, with no compromises, which has been the source of many of the disputes inside Debian. Consider, if you will, the first clause of the Debian Social Contract:
Debian will remain 100% free We provide the guidelines that we use to determine if a work is free in the document entitled The Debian Free Software Guidelines. We promise that the Debian system and all its components will be free according to these guidelines. We will support people who create or use both free and non-free works on Debian. We will never make the system require the use of a non-free component.
This clause has in it no room for compromise. Note the use of words such as 100% free and never make the system require the use of a non-free component (emphasis mine). In addition, the Debian Social Contract tends to be interpreted by Computer Programmers, who view such imperatives as constraints that must never be violated, under any circumstances. Unfortunately, the real world is rarely so cut-and-dried. Even the most basic injunctions, such as Thou shalt not kill have exceptions. Few people might agree with claims made by the U.S. Republican Party that the war in Iraq qualified as a Just War as defined by Thomas Aquinas, but rather more people might agree that the July 20, 1944 plot to assassinate Hitler would be considered justifiable. And most people would probably agree most of the actions undertaken by the Allied Soldiers on World War II battlefields that involved killing other soldiers would be considered a valid exception to the moral (and for those in the Judeo-Christian tradition, biblical) injunction, Thou shalt not kill . As another example, consider the novel and musical Les Mis rables, by Victor Hugo. One of the key themes of this story is whether or not Thou shalt not steal is an absolute or not. Ultimately, the police inspector Javert, who lived his whole life asserting that law (untempered by mercy, or any other human considerations) was more important than all else, drowns himself in the Seine when he realizes that his life s fundamental organizing principle was at odds with what was ultimately the Right Thing To Do. So if even the sixth and eighth commandments admit to exceptions, why is it that some Debian developers approach the first clause of the Debian Social Contract with a take-no-prisoners, no-exceptions policy? Especially given the fourth clause of the Debian Social contract:
Our priorities are our users and free software We will be guided by the needs of our users and the free software community. We will place their interests first in our priorities. We will support the needs of our users for operation in many different kinds of computing environments. We will not object to non-free works that are intended to be used on Debian systems, or attempt to charge a fee to people who create or use such works. We will allow others to create distributions containing both the Debian system and other works, without any fee from us. In furtherance of these goals, we will provide an integrated system of high-quality materials with no legal restrictions that would prevent such uses of the system.
This clause does not have the same sort of absolutist words as the first clause, so many Debian Developers have held that the needs of the users is defined by 100% free software . Others have not agreed with this interpretation but regardless of how needs of the users should be interpreted, the fact of the matter is, injuctions such as Thou shalt not kill are just as absolute and yet in the real world, we recognize that there are exceptions to such absolutes, apparently unyielding claims on our behavior. I personally believe that 100% free software is a wonderful aspirational goal, but in particular with regards to standards documents and firmware, there are other considerations that should be taken into account. People of good will may disagree about what those exceptions should be, but I think one thing that we should consider as even higher priority and with a greater claim on how we behave is the needs of our users and fellow developers as people. For those who claim Christianity as their religious tradition, Jesus once stated,
Thou shalt love the Lord thy God with all thy heart, and with all thy soul, and with all thy mind. This is the first and great commandment. And the second is like unto it: Thou shalt love thy neighbour as thyself. On these two commandments hang all the law and the prophets.
Even for those who do not claim Christianity as their religious tradition, most moral and ethical frameworks have some variant on the Golden Rule: Do unto others as you would have them do unto you . I would consider, for example, that the Golden Rule is at least a high priority claim on my behavior as the notion of free speech, and in many cases, it would be a higher priority claim. The recent controversy surrounding Josselin Mouette was started precisely because Joss has taken a something which is a good thing, namely Free Speech, and relegated it to a principle more important than all else, and claiming that any restraint on such a notion was equivalent to censorship. I think the same thing is true for free software, although it is a subtler trap. Philosophical claims than 100% free software as most important consideration is dangerously close to treating Free Software as the Object of Ultimate Concern or in religious terms, idolotry. For those who are religious, it s clear why this is a bad thing; for those who aren t if you are unwilling to worship a supernatural being, you may want to very carefully consider whether you are willing to take a philosophical construct and raise it to a position of commanding your highest allegiance to all else, including how you treat other people. Ultimately, I consider people to be more important than computers, hardware or software. So over time, while I may have had some disagreements with how Mark Shuttleworth has run Canonical Software and Ubuntu (but hey, he s the multimillionaire, and I m not), I have to give him props for Ubuntu s Code of Conduct. If Debian Developer took the some kind of Code of Conduct at least as seriously as the Social Contract, I think interactions between Debian Developers would be far more efficient, and in the end the project would be far more successful. This may, however, require lessening the importance of philosophical constructs such as Free Speech and Free Software, and perhaps becoming more pragmatic and more considerate towards one another.

26 December 2008

Chris Lamb: Unfortunately, we get parallel octaves at the end

A reel from Glenn Gould's 1955 recording of the Goldberg Variations contains the following dialogue between the 22-year-old pianist and the recording engineer after a take of the 30th variation, a quodlibet:
By the way, I have a quodlibet of my own which came to me in the bathtub the other night. One of these days I will be asked to perform on the fourth of July, I'm sure, and when I do I figured out that by leaving out the repeats in the Star Spangled Banner and starting your entry on the thirteenth bar of God Save The King and then playing God Save the King over again and altering the harmony in the second half of The King to modulate to the supertonic region, it has the most marvelous effect. Listen to this.. (202KiB Ogg Vorbis).

24 December 2008

Daniel Burrows: aptitude-gtk updates: dpkg progress bar, choosing columns, more

It's been a long time since I wrote about aptitude-gtk. Mostly that's because I haven't been doing any work on it, due to a combination of several holidays, sickness and (last but certainly not least) an unfortunate relapse of WoW-addiction. But we have moved the ball forward since the 0.5.0 release. Some of the changes since then are just polishing, with no major changes in functionality, but there are a few things that are very visible: Status pipe support aptitude now supports the dpkg status pipe. This means that it can display a progress bar showing how far through the install process it is. In fact, if you are using the Gnome frontend for Debconf, you don't even need to display the terminal at all, unless a package is so uncouth as to prompt directly on standard input. I'd like to thank the Synaptic developers -- although this is all my own code, their implementation of this functionality was very valuable documentation of how apt frontends use the status pipe in practice. Incidentally, the aptitude implementation is modularized and available in src/generic/apt/parse_dpkg_status.cc and src/generic/apt/parse_dpkg_status.h. If you want to parse dpkg messages in your own GPL project, you might want to take a look at that code. And if I don't forget, I'll ask about including this in apt once the lenny freeze is lifted. [0] Here's the dpkg progress bar in action, showing that dpkg is configuring libmad0: aptitude dpkg progress bar Clicking the "View Details" button on the dpkg progress bar will pop up a terminal in a new tab; you can close the tab and dpkg will go back to running in the background. And yes, I know that the progress bar for the download shouldn't hang around after the download completes. :-) Searching for partial strings As noted in the release notes for 0.5.0, incremental searching from the curses frontend was broken by the 0.5.0 release. I've created a new match term named ?term-prefix which matches against any extension of the term; for instance, searching form ?term-prefix(comp) will find any package that matches the term compiler, the term computer, the term compromise, or any other extension of comp. The upshot is that incremental searching should work again. Editing the list of visible columns The current package list doesn't show very much information. That's deliberate: I don't want to clutter the default view with a lot of stuff that's only necessary from time to time. But until now, there was no way to change which columns were visible. Now there is: aptitude 'Edit Columns' dialog This is a very rough proof-of-concept dialog that I've just checked into the source tree. The checkboxes are fully functional (clicking them shows and hides columns), but the buttons to save the current setup or to apply it to all the active tabs are not working. With this in place, we can think about creating columns for most of the interesting information about a package (archive, maintainer, etc). [0] By which I mean, I'll say does anyone object if I add this utility code to apt?, and when no-one says no I'll commit it. :-)

23 December 2008

Wouter Verhelst: Root on NBD, now with partitions

A while ago, I wrote an initrd script and hook that would allow one to run a system with root on a Network Block Device (NBD), that I maintain both upstream and in Debian. Since then, Laurent Vivier submitted a kernel patch that got merged, and which will allow one to partition an NBD device. I had a patch for my initrd script that would support running root off a partitioned NBD device, but did not yet have the time to test and debug it. Until today, that is. Well... not really. I made the time, but I didn't really have it. For reference, the time is 07:25 right now, and yes, I did stay up all night. But, well, who cares, right? Right. I'd really love to get this into lenny still, but since we're in deep freeze... not keeping my breath. We'll see, I guess. The upload is going to unstable, anyway after this one final test. So how does it work? Unfortunately, no d-i support as of yet. I'd been working on that, but then it turned out that in order to support root-on-NBD, I'd have to somehow, somewhere, teach partman that NBD is this strange thing which can be formatted, but not partitioned. I was way far in my research (but nowhere in code, yet) on that when Laurent sent in his partitioning patch, so it got postponed then, and I didn't get a chance to pick it up anymore in time. But if you're willing to use debootstrap manually, it's really simple to set up:
# apt-get install nbd-client
# nbd-client server port /dev/nbd0
# fdisk /dev/nbd0
[... create partitions ...]
# mkfs -t ext3 /dev/nbd0p1
# mkdir /mnt/tmp
# mount /dev/nbd0p1 /mnt/tmp
# debootstrap --include=nbd-client sid /mnt/tmp
# echo KILLALL=false >> /mnt/tmp/etc/nbd-client
The "KILLALL" is necessary, since otherwise the nbd-client initscript will do nasty things with your root filesystem. Note that you still need nbd-client installed and run the initscript, even if it only uses nbd-client inside the initrd; because the initscript writes the nbd-client PID to /lib/init/rw/sendsigs.omit.d, which is also required if you don't want sendsigs to shoot the root filesystem from under your nose. This might see some changes in the future. Now boot with your kernel and initramfs, and boot it with the following arguments:
nbdroot=server,port root=/dev/nbd0p1
Obviously, in the above two examples, you should replace 'server' by the IP address or hostname of your server, and 'port' by the port number on which your nbd-server is running. It is of course also possible to use nbd1p2 or nbd0p4, should you want that. And that's all there is to it. Well, almost; due to the way the network configuration is written in initramfs, I had to choose between reinventing the wheel, or hardcoding the NIC name to 'eth0'. I chose the latter. What this means is that if you want to boot off an NBD blockdevice that is only available on eth1 or wlan0 or some such, you lose. Other than that, go ahead and try. Should be on a DMNY (Debian Mirror Near You) RSN. Update: fill in the link to git.kernel.org, and mention the KILLALL thing. Oops.

Wouter Verhelst: Cantilene "Jeugdkoor van het jaar"

or, "Youth choir of the year" Between my 16th and 25th birthday, I was a happy member of this particular choir; and today, five years later, there are still many members of this choir that I know personally including, of course, their conductor. It's not the first time Cantilene joined the race for "Choir of the year". The first two times, I was still a member. However, it is the first time they won in the category "youth choirs"; the first time, Cantilene came up second; the second time, we unfortunately did not make it to the finals. The fact that they did make it this time around, gives me mixed feelings; of course I'm happy that they won, but I'm sad that I couldn't be part of it this time. Well, that's part of getting older, I guess. In any case, here's a big contratulations to Cantilene! For those who care, if you do a search on youtube for "Cantilene", "Koor van het jaar", or "Luc Anthonis" (the conductor), you'll find a number of films most of them from the Canvas belgian TV station. In related news, with Caljent (the choir that I am a member of, today) we had two concerts last weekend. They were a success, but unfortunately no thanks to me; I lost my voice somewhere during the evening of the 20th, and thus was quite unable to sing most of what we were going to sing. That did not stop me from being on stage and singing anyway, but I had to playback about half that time... Here's for hoping that my voice will be better on christmas, since we're singing in mass then... I'm mostly there, but not quite entirely yet.

21 December 2008

Uwe Hermann: 256 Creative Commons Christmas Songs

Christmas Tree Yes, it's that time of the year again... it's almost Christmas, which means that I once again updated my 10 + 100 Creative Commons Christmas Songs blog article I originally wrote in 2005. That's a collection of a lot of freely downloadable, Creative Commons licensed Christmas music. Some of the older entries in the list are no longer available unfortunately, some only needed a URL update, and I also added more than 30 new songs this year. This currently makes a total of 256 CC Christmas songs (more will probably be added over the next few days), so head over to the full song list and get those downloads started... (Photo: Wikipedia. Author: Malene Thyssen. License: GFDL 1.2 / CC-BY-SA 2.5)

Neil Williams: Debian Quality and Releases

Sticking with the theme that blogs are all about completely biased and probably controversial opinion and not much else, I'm glad that Thomas has made his thoughts clear. Thomas - I fully agree (but your blog doesn't support comments, so I'm putting it here).

Debian, to me, needs to about Quality over quantity (being very aggressive over orphaned packages and their reverse dependencies) and about everyone working towards the releases. Not to pick arbitrary time-based deadlines for releases but actively fixing release-critical bugs, so that the release can proceed smoothly with stable, reliable packages. Debian developers who feel unable to fix release critical bugs maybe should not be developers any more - or at least be banned from mailing lists on lists.debian.org which appear to be the only "contribution" being made.

There's no reason to continue using Gtk1.2 and no point in complaining about it because there is no prospect of anyone stepping up to maintain gtk1.2 itself. There is therefore no point in the long threads complaining about removing gtk1.2 because nobody is going to do any work to retain gtk1.2.

If you aren't prepared to do the work, you should not feel you have any rights to complain about the lack of such work being done. We're all volunteers - don't expect someone else to sift the wheat from the chaff, get rid of your own cruft. Debian needs to be an association of people who do, not the current association of people who complain, moan and generally fight amongst themselves. The answer to this negativity is a can-do attitude - it is not as if there aren't enough problems out there to fix, get out there and raise the quality. (First though, get Lenny released.)

Not everyone can do the same amount of workload but within the work that you are able to do, there must be a balance between the work you do for yourself and the work you do for the distribution. I'm not expecting people to have to match my levels of output, I am expecting people to match the proportion of time that they allocate to fixing problems outside their own limited niche. If that proportion approaches zero then maybe Debian doesn't need you any more.

There is no reason to have project members who do not contribute to either quality or releases - that doesn't just mean not fixing bugs, it means not being a part of any team or other group in Debian that provides support for general quality or the release.

If you aren't fussed about the quality of packages (in general, not just your own) and aren't willing to contribute just a small amount of your time to use your privileges to fix release-critical issues, then those privileges should be removed - you obviously don't need them. (Also, if you aren't a DD yet and you want sponsorship, these rules apply to you too. I won't sponsor people who have no feel for quality or want to help Debian make releases. I'm beginning to wish other sponsors would do the same. Quality is far more important than quantity - merely adding packages because they exist and because someone posts a request for a sponsor is insufficient. Completely insufficient, counter-productive too. See my sponsorship requirements.)

Note: this post is entirely opinionated and I don't care if you disagree. I will take a particularly brutal approach to comments that do not grasp this fact.

19 December 2008

Julian Andres Klode: Short review: Fedora 10 and Ubuntu 8.10


After I tried OpenSolaris 2008.11, I also tried Fedora 10 and Ubuntu 8.10, each for almost one day. Creation of bootable USB stick: For both distributions, I created a bootable USB stick because it is faster to install from USB than from CD/DVD. The creation was easy in both cases. Fedora ships a shell script and Ubuntu a graphical program for this task. Both very equally easy to use. Booting from USB: Both distributions booted perfectly from USB. But there was a big difference in boot speed: Fedora 10 booted in about the same time Ubuntu needed to find the USB stick. Installation from USB to HDD: Installation of both systems went very well, without any problems. Fedora s installer is far more powerful than Ubuntu s, e.g. it allows to use LVM or encrypted partitions. To setup LVM and encrypted volumes with Ubuntu, you need to use the text installer on Ubuntu s alternate disk (It s debian-installer). Ubuntu s graphical installer received a new partioning screen. Boot: Fedora s boot time seems to have improved a lot since the last release. Ubuntu s boot time seems to be roughly the same as in 8.04. Both distributions provide a progress bar, whereas Ubuntu s usplash looks better. But this may change once kernel-based modesetting works on Intel cards in Fedora, because Fedora s splash program needs it for graphics. Else, it only displays ASCII progress bar. Login: Fedora 10 shipped with GDM 2.24, which means that there are no themes yet. But this was no problem, as the non-themed design of GDM has improved a lot. I even like it more than any themed GDM I have seen. It reminds me a bit of OSX. Desktop: Both distributions ship with GNOME 2.24. The default themes look good, whereas Fedora s uses more GNOME-like icons, whereas Ubuntu uses Human, which is based on Tango. And that is important for me, since I normally do not change any aspect of my desktop, except for adding cpu frequency and tomboy applets to the panel. Hardware support: Both distributions provide good hardware support. Ubuntu leads here, at the cost of having non-free drivers included on the disk.For users needing windows wireless LAN drivers, Ubuntu is the right choice, as it ships ndiswrapper and the graphical frontend (ndisgtk) on the installation medium. Fedora does not include ndiswrapper, because of what it is used for (installing non-free Windows drivers). Both distributions ship firmware, and consider firmware images as free enough, as they do not run on the CPU. EXT4: Fedora 10 ships with patches for EXT4 backported from Kernel 2.6.28. It also supports the installation on ext4 partitions, but only using the DVD and if booted with the ext4 option. The Live discs do not support installation to ext4. Package management: Both distributions ship with good package managment software. YUM really improved since the early times, where it downloaded an extra metadata file for every package. Nowadays, yum and apt seem to be on a nearly equal level, but aptitude lets Ubuntu win, because it can handle problems much better (ie. it proposes ways to solve problems) than YUM. Graphical package management: Ubuntu wins here. Fedora only ships PackageKit for package managment, which, in my opinion, is not able to really compete with Synaptic and gnome-app-install. Conclusion: Both distributions are very solid. Ubuntu still has the better package managment, and a bigger selection of packages. This has only been possible due to Debian, which is the base of Ubuntu. I tried to write this blog post not as an Ubuntu member. I always liked Red Hat and Fedora, and one of my first Linux distributions was Red Hat 9. Links: Posted in General, Ubuntu

16 December 2008

Biella Coleman: Speaking of the Tactile/Tactical



razer my new keyboard, which i LOVE, originally uploaded by the biella.
Speaking of the tactile and the tactical, after seeking some input, I settled on this keyboard a few months ago and I simply love it so much so, today I got another one for my office. I love the key strokes simply cuz they have just the right feel. It takes some, but not too much, pressure to type and it feels great on my finger tips. The fancy blue lighting is a plus but not a central feature. The overview/description on their website is pretty dramatic but I tend to agree it provides for some pretty hefty power, allowing me to launch my email assaults with perfection :

With an awesome host of features, the Razer Lycosa is on an unstoppable mission to destroy and dominate. Execute complex combat maneuvers with swift dexterity. Launch your assaults timed to perfection. Annihilate your enemies and reign supreme on the battlefield. You now have the tactical advantage on every terrain, and your enemies fates are in your hands.
<
I dare say I am fully content with the keyboard but I am still searching, however, for the perfect pen

Jon Dowland: wodim sums

Thanks to Daniel for suggesting I try burning my ISO image with brasero in response to my problems burning images using nautilus. Unfortunately brasero won't offer me a burn ISO option 497226: brasero: Burn button disabled. No indication of why.. I just tried wodim directly and ended up with the same (wrong) sum for the burnt disc as with nautilus cd burner (not suprising really). I wondered if I was being bitten by 386640: wodim doesn't fixate DVD+R with premastered ISO, but trying to fix the disc did not update the sum. Taking an image of the burnt disc, I notice that the burnt image is longer size-wise than the input ISO by 10240 bytes. This turns out to be 10240 of zeroes appended to the image.

Next.

Previous.