Posts in category 'hacking'
Again with the NetBSD
Well, it’s been a couple days now, and I continue to fiddle around with NetBSD… it’s definitely not going to be displacing Ubuntu any time soon, but it’s definitely an amusing project to play around with.
Most recently, as I was testing out Evolution (my email client) compiled from pkgsrc, I discovered that it started up incredibly slowly. Like, 5 minutes from invocation to a window popping up on my desktop. So, a little Google-fu, and I found myself here. It turns out that one of the things Evolution does a lot is attempt to open shared libraries that don’t exist. Unfortunately, those failures are very expensive, and as of 5.0.2, NBSD’s linker doesn’t cache the failures.
And this is where that blog post comes in. The author of that post wrote up a negative lookup cache and incorporated it into the NBSD dynamic linker. By itself, that’d be interesting, but what’s deeply cool about this is that I was able to get a patch representing his change, tweak them, apply them to my local copy of the NBSD source, and then build out and install a new version of the dynamic linker. Result: startup times went from minutes to seconds. I’d call that a huge win.
What this fundamentally speaks to is just how open and easy it is to fiddle around with the internals of NetBSD. The entire system is designed to make it trivial to alter the base and rebuild it out from scratch, which makes it possible to do the kinds of things I just did. Very cool!
Next up: Attempt to hack nouveau DRI support into the kernel so I can get reasonable video performance.
BSD-Curious
So for no particular reason at all, I recently got the urge to try out a BSD variant on my laptop. Now, historically I’ve been a die-hard Linux user, having cut my teeth on Slackware back when you needed dozens of floppies to install the thing (as a quick aside, I didn’t have internet access at home at the time, and so I used a PC at school to download Slack from a local BBS, which meant trucking dozens of floppies there and back… which was really fun when, say, disk 12 of 20-something had a bad sector, requiring me to return to school the next day (leaving the install process up and in limbo in the mean time) to write out a new disk). Since then, I’ve worked with Redhat, Debian, Fedora, and Ubuntu, but have never strayed outside the realm of Linux, and so, in a fit of boredom, I decided to address that little shortcoming in my technical upbringing.
Of course, there are multiple BSDs out there, each with their own focus and vision, and chosing one is often a matter of taste. My initial choice was FreeBSD, which I threw on a 10GB partition on my laptop, after which I found myself facing the familiar command prompt (well, not quite familiar… it was straight sh instead of bash, which was… annoying), and a fairly barebones system. At this point I discovered an important difference between the BSDs and, say, Ubuntu: out of the box, they tend to provide a very bare-bones system, enough to get you bootstrapped so you can build the system you need. But you have to build it. Not that I mind, I’m a tinkerer at heart.
I then spent the next couple days fiddling around with the system and configuring it as necessary, which was a very different experience from what you see in Linux. You see, in FreeBSD (and NetBSD, which I’ll get to later), the primary system configuration, which includes network configuration, system daemon selection, and so forth, is all stored in a single file in etc called ‘rc.conf’. In contrast, Linux distros tend to manage things in varying ways, which means you to need to learn individual platform quirks and tools, something which is always a bit tedious. And so, by playing with the rc.conf, I was easily able to get networking up and running, including my wireless card, various system daemons, and so forth. And after that, it was off to install some interesting programs.
And this was where I discovered my next surprise. In the Linux world, package managers are really king, with two main contenders vying for the top spot: deb and rpm. Of course, there are a few outliers (Slackware’s tgz’s, Gentoo’s portage system, etc), but for the most part, modern distros are based on one of these two package management systems. Not so with FreeBSD. FBSD uses a system called ‘ports’, which should be familiar to a Gentoo user, as portage is really a rip-off of ports. In essence, ports is a gigantic set of scripts, where each supported application is represented by a directory containing Makefiles, patches, and so forth, which can be used to install the application. A simple ‘make install’ in the directory results in the source for the package being downloaded, patched, configured, built, and installed. It’s really quite slick, if you’re interested in building everything from source (which can take quite a while). Of course, FBSD also has binary package support, but building from ports is the most common way people install software in the FBSD world.
Unfortunately, I finally hit a brick wall with FBSD on my laptop when I attempted to suspend it. Big mistake. You see, it turns out that, even now, with FreeBSD 8.0, support for suspend/resume is incredibly weak. So while Linux has stumbled along and finally reached a point where things kinda sorta work most of the time, FBSD is, I’d wager, at least 5 years behind. Which is a real shame, as I use suspend all the time with my laptop. And thus it was that FBSD as a possible OS alternative was nixed.
So, what next? Well, in my mind, the most obvious alternative contender was NetBSD (I eventually chose the 32-bit version for reasons I won’t get in to here). Like FreeBSD, NetBSD installs to a very barebones system, though even more barebones than FBSD, if that can be believed. In fact, the ISO for the installation media is a mere 250MB, give or take, which is pretty diminutive beside FBSD’s 2GB DVD image (though, to be fair, FBSD’s DVD ships with a ton of pre-compiled packages, while NetBSD leaves you having to download all that software from the intertubes). Similar to FBSD, the entire system is configured through /etc/rc.conf, and basic configuration was equally easy. Once that was done, again my thoughts turned to software.
The NetBSD package system shares a lot of commonalities with the FreeBSD system. Which shouldn’t be surprising because NetBSD’s system, pkgsrc, was forked from ports back in 1997. As such, they share an underlying philosophy, and so the two systems operate very similarly. I will say, though, that ports does have one significant advantage over pkgsrc: Much better OS integration. See, pkgsrc is really a sister project to NetBSD. As such, it can actually be run on myriad operating systems, including Linux, among many others. But that means that the system doesn’t tie into the OS all that well. So while a ports package, once built, will populate /etc/rc.conf will configuration values, throw itself into /usr/local/etc/rc.d, and so forth, a pkgsrc package requires the user to perform extra work to integrate the software into the OS. Additionally, I do prefer the way ports actively prompts the user for configuration directives for packages that provide them, but that’s probably just a matter of taste.
Of course, I once again made the mistake of investing a fair bit of time into installing packages before I decided to test out suspend, and once again I was disappointed, though somewhat less so (which is why NetBSD is still on my laptop). Suspending the laptop worked flawlessly, and was incredibly fast. Honestly, I’ve never seen a laptop go to sleep that quickly. But on resume, oddly enough, my videocard doesn’t get initialized properly (this is a known problem with nVidia graphics chips in general, and on my laptop model in particular). On the other hand, everything else works perfectly (the OS is actually fully responsive under the hood, the display simply doesn’t come on). Some hacking got things sorta working, but not reliably, so for now suspend on NetBSD will have to wait. But at least there appears to be a chance.
So for now I’ve decided to stick with NetBSD. Naturally I expect there to be more problems and limitations (at minimum, I’ll be stuck with nv as my X driver, as nVidia’s binary blob isn’t supported on NetBSD), and I doubt it’ll displace my Ubuntu install, but it should be fun seeing if it can!
And quick aside: I was very impressed to discover that both Free and NetBSD supported essentially all the hardware on my laptop, without exception (well, save for ACPI suspend, of course), straight out of the box. Very nice!
Amusing Nerd Statistic For The Day
At work, I’m more or less the sole custodian of a major software component, and I’ve switched my day-to-day operations over to using git as a frontend to the corporate Subversion repository. Now, part of this work involves managing three different product branches (a trunk version, a legacy version, and a current stable), plus now that I’m using git, I’ve started creating lots of topic branches for features I want to include, but am not ready to commit yet.
Well, I got curious about disk space usage, as git is supposed to be really efficient. Here’s what I found:
- Trunk and current stable checked out from SVN. Total disk space, 118M.
- Git tree containing complete code and history for trunk, legacy, current stable, and five topic branches: 42M.
Now that’s what I call efficient!
Using Git as a Bridge to SVN
So, Lenore complained that I haven’t been blogging much lately, so I thought I’d throw together a little something that would bore her to tears. :) Now, as quick prelim, if you don’t know what Git or Subversion is, I’d just skip this one.
Now, this whole thing is really more of a note-to-self, as I’m still getting used to git. But I figured it might be useful to other developers. Now I should say this isn’t going to be a generic discussion about how to bridge Git to SVN. That’s be done to death all over the web. What I’m particularly interested in is how to use git-svn when your Subversion repository has an… unusual topology. See, the typical Subversion repository is laid out something like this:
projectA trunk branches projectA-1.0 tags projectB trunk branches projectB-1.0 tags
In a case like this, importing the tree into git-svn is trivial. However, at work, we have a Subversion repository that looks something like this:
trunk projectA projectB branches projectA-1.0 projectB-1.0
This layout requires some hacking to get git-svn working. First off, you need to initialize a standard git repository:
mkdir git cd git git init
Note, you’ll probably also want to use “git config” to set a few parameters while you’re at it (if you’re on Windows, setting “filemode” and “autocrlf” to false is a very good idea). Once the basic repo is set up, you can now add the SVN repositories you plan to fetch. For example, to pull projectA and projectA-1.0, we’d run these commands
git config --add svn-remote.projectA.url svn+ssh://path/to/svn/ git config --add svn-remote.projectA.fetch trunk/projectA:refs/remotes/projectA git config --add svn-remote.projectA-1.0.url svn+ssh://path/to/svn/ git config --add svn-remote.projectA-1.0.fetch branches/projectA-1.0:refs/remotes/projectA-1.0
Basically, we instruct git-svn what the mappings are between various tree names and their SVN equivalents. This includes a URL to the repository, along with a definition of where to fetch the code from. Once this is done, you need to populate your repository. Note, I think the first fetch becomes the master branch (I’m not actually sure about this, but it seems that way), so it’s best to yank trunk first (you can move the master moniker around, but why bother with such machinations if you can do it right the first time?):
git svn fetch projectA git svn fetch projectA-1.0
Note, somehow, and I have no idea how, git even manages to figure out the 1.0 branch parent, so the essential structure is preserved, even though we perform separate fetches to populate the trees.
So now we have the trees downloaded, and as a bonus, the master tree is set up and tracking trunk. Next, we need to create local branches tracking any remote branches we’re interested in:
git checkout projectA-1.0 # Switch into the remote branch git checkout --track -b 1.0 # Create a local branch named 1.0 tracking the projectA-1.0 remote branch
There, the tree is populated. Finally, if you have svn:ignore properties set up, here’s how you mirror them locally (note, you’ll have to do this for each branch). Now, in git, the ignore rules are stored in .gitignore files. This is fine, except that, by default, git wants to include those files in the git repository, and thus they’d get pushed upstream in a dcommit. Thus, we have to go through a bit of gymnastics to make sure that doesn’t happen, and that the .gitignore files remain local.
First, open up .git/info/exclude and add these lines:
.gitignore .gitmodules
This instructs git to ignore the .gitignore files (and .gitmodule files) on “git status” calls and so forth. Next, create the ignore files.
git checkout master git svn create-ignore
Of course, when this happens, git-svn goes and does a “git add” for all the .gitignore files. This is exactly what we don’t want. :) So, last but not least, we undo the adds:
git reset HEAD
And your tree should now be ready for hacking. Now for a few basic recipes. First, to switch between branches:
git checkout 1.0 # Switch to our projectA-1.0 tracking branch git checkout master # Switch back to master
Second, here’s how we update the current local branch to sync up with it’s corresponding remote SVN branch:
git svn rebase
Third, to commit a change to the local git branch:
git commit -a
Next, to push the changes in the local git branch out to the Subversion repository:
git svn dcommit
Note, a dcommit pushes each individual local commit to the Subversion tree as individual SVN commits. However, there may be times when you want to roll together a series of local changes into a single SVN checkin (perhaps your code went through a lot of churn before the final version was reached). Luckily, git makes it possible to do just that. Imagine you’ve made some changes to trunk you want to check in as a single commit (I assume you’ve got the master branch checked out):
git reset --soft refs/remotes/projectA # Reset to the remote HEAD git commit -c ORIG_HEAD # Commit our original HEAD node into this tree.
Voila, the changes will now be combined into a single commit, and the old commits will be gone (well, technically they exist they’re just orphaned). Note, this does change “the past”, and of course fiddling around with history is generally not a good idea. But given we’re talking about a local repository, here, I don’t see a big problem with it.
Of course, a better alternative is to make all your changes in a local branch. Then, when you’re ready, you can merge the changes into the originating branch, and then commit them there. That way, you can opt to delete the working branch if you don’t care about the history, or keep it around if you think you might need it.
So there ya go. Basic git-svn bridging on a non-standard tree layout. And if you’ve read this sentence, congrats! Your ability to stay awake against all odds is, without a doubt, stunning.