<?xml version="1.0" encoding="UTF-8"?>
<essay xml:lang="en" version="pto" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:gal="http://norman.walsh.name/rdf/gallery#">
<info>
    
    
    
    
    
    
    
    
    
    
<title>chroot X!</title><biblioid class="uri">http://norman.walsh.name/2003/08/22/chroot</biblioid>
<volumenum>6</volumenum>
<issuenum>73</issuenum>
<pubdate>2003-08-22</pubdate>
<date>$Date: 2005-09-11 10:27:02 -0400 (Sun, 11 Sep 2005) $</date>
<author>
      <personname>
<firstname>Norman</firstname>
	<surname>Walsh</surname>
</personname>
    </author>
<copyright>
      <year>2003</year>
      <holder>Norman Walsh</holder>
    </copyright>
<abstract>
<para>The perils of proprietary hardware and how I worked around a particularly
irksome bug.</para>
</abstract>
<dc:subject rdf:resource="http://norman.walsh.name/knows/taxonomy#Linux"/>
</info>

<epigraph>
<attribution>Britt Blaser</attribution>
<para xml:id="p1">Proprietary data is the root of tyranny.</para>
</epigraph>

<para xml:id="p2">I've had my laptop for several years now. It's a
<link xlink:href="/knows/what#tecra-8200">Toshiba Tecra 8200</link> and for the
most part I've been quite happy. I use my laptop all the time, it's
the only computer I use at home or on the road.</para>

<para xml:id="p3">One of my requirements for a laptop is a display wider than 1280
pixels. I like to have an Emacs window and a couple of shell windows
up side-by-side without any overlap and enough space left over for a
few little desktop monitors, like the desktop switching applet.</para>

<gal:photo rdf:resource="images/screenshot"/>

<para xml:id="p4">What drew me to the 8200 then was partly the 1400x1050 display.
Sweet. A nice compromise, actually, between 1280x1024 which isn't big
enough and 1600x1200 which can make for some eye-strainingly small
details on a laptop-sized LCD.</para>

<para xml:id="p5">So it's a nice laptop, but the damn thing has three bits of
proprietary hardware. Proprietary hardware, that is to say, hardware
for which the vendors will not publish reasonable, open API
specifications, sucks. Avoid it if you can.</para>

<para xml:id="p6">In the case of the 8200, the modem is some
<quote>winmodem</quote> piece of junk; not one of the ones for which
I've yet seen a Linux driver. But I don't care, a $30 PCMCIA modem card
on eBay fixed that problem. There's also never been a driver for the irDA
chipset. It would be nice if that worked, but I can live without it.
And then there's the video card.</para>

<para xml:id="p7">The XFree folks have worked hard to get a working driver for the
Trident family of cards, but in the case of the
<quote>CyberBlade/XP</quote> card in this laptop, they've met with
only partial success. The best XFree driver out there will only run at
1400x1050 with a very odd <quote>left shift</quote> problem. The
left-most 16 pixels of the display appear on the right-hand side of
the screen. Yeah, it's just as odd as it sounds. I tried for about a
day to get used to it and decided that I couldn't.</para>

<para xml:id="p8">So how do I use my laptop? The answer is that I bought a commercial
X server, the <application>Accelerated X</application> product from
<link xlink:href="http://www.xig.com/">Xi Graphics</link>.</para>

<para xml:id="p9">All fine and dandy until I switched from Debian
<quote>Woody</quote> to <quote>unstable</quote>. A week or so ago,
a new libc was released on unstable. It's not
<quote>binary API</quote> compatible with the old libc. You can see it
coming, right?</para>

<para xml:id="p10">You guessed it, the X server no longer runs because of the
binary incompatibility in libc. And Xi no longer supports the product
I'm using because they have a new product line. And their new product
line doesn't support the Trident hardware I've got because they can't get
Trident to reveal the <emphasis>[expletive deleted, ed.]</emphasis> specs to
them either.</para>

<para xml:id="p11">Backing out the libc upgrade got things working again, but left my machine
in an intolerable state where some apps ran and some didn't, according to what
level of the libc library they depended on.</para>

<note>
<para xml:id="p12">At this point, the essay is going to take a decidedly technical
turn. If you're not using Linux or some Unix variant, the words may
cease to be meaningful at any point. Avoid proprietary hardware, that's
the takeaway<footnote>
	<para xml:id="p13">In all honesty,
I suppose I'm over simplifying things. If you're content to run a proprietary
operating system and you're confident that the proprietary hardware you have
will always be supported by that operating system and you'll never want to
try another operating system for which that isn't true, what difference
does it make to you if it's proprietary or not?</para>
      </footnote>.
Commercial, closed-source software leaves you screwed too,
if you need updates and the vendor isn't supplying them. But I figure you
already know that lesson.</para>
</note>

<para xml:id="p14">What to do? Saving the old libraries and updating the
<envar>LD_LIBRARY_PATH</envar> didn't work.
<personname>
      <firstname>Rob</firstname>
      <surname>Weir</surname>
    </personname>
pointed me in the right direction, use <command>chroot</command>, and
<personname>
      <firstname>Sebastian</firstname>
      <surname>Kapfer</surname>
    </personname>
provided the clue I needed to get it running. (Both of these guys
responded to messages I posted on the
<email>debian-user@lists.debian.org</email> list. Thanks, guys.)</para>

<para xml:id="p15"><command>chmod</command>, <command>chown</command>,
<command>chgrp</command>, <emphasis>chroot</emphasis>???</para>

<para xml:id="p16">Yes, <command>chroot</command>. What it does is change the root
directory for a given program. If you run <command>chroot /dir
<replaceable>command</replaceable></command>, what happens is
<replaceable>command</replaceable> runs with its root directory set to
<quote>
      <literal>/dir</literal>
    </quote>. That means that while the program
is running <filename>/path/file</filename> actually refers to
<filename>/dir/path/file</filename> on disk. Neat, huh? <quote>And this
is useful, why,</quote> you ask?</para>

<para xml:id="p17">It's useful because it means that I can setup a separate
directory with all the old libraries and run <application>Accelerated
X</application> in there. This will insulate the old application from
any changes to the system libraries. And the client/server nature of
<application>X</application> means that all the new apps will be able
to display on the old server with no problems.
(<application>X</application> may be a little clumsy to configure, but
it rocks!)</para>

<para xml:id="p18">First I created a new directory, the future root directory, for
<application>Accelerated X</application> and copied the binaries and
configuration files that it uses into that directory, mirroring the directory
hierarchy of the real root. (In other words <filename>/usr/X11R6/bin/Xaccel</filename>
got copied to <filename>/AccelX/usr/X11R6/bin/Xaccel</filename>, etc.)</para>

<para xml:id="p19">Then I copied the old libc files into the new root. I also copied
<filename>/bin/bash</filename>, <filename>/bin/ls</filename> and a few other
things over so that I could run:</para>

<screen>chroot /AccelX /bin/bash</screen>

<para xml:id="p20">to check things out.</para>

<para xml:id="p21">Next the question is, what other libraries will I need? Remember, after
<command>chroot</command>, only the files under <filename>/AccelX</filename>
will be visible. The <command>ldd</command> command helps here. For example:</para>

<screen>$ ldd /bin/bash
        libncurses.so.5 =&gt; /lib/libncurses.so.5 (0x40014000)
        libdl.so.2 =&gt; /lib/libdl.so.2 (0x40050000)
        libc.so.6 =&gt; /lib/libc.so.6 (0x40053000)
        /lib/ld-linux.so.2 =&gt; /lib/ld-linux.so.2 (0x40000000)</screen>

<para xml:id="p22">Tells me that to run <command>bash</command>, I need to copy
over the libncurses and libdl libraries in addition to the libc
library (which I've already copied).</para>

<para xml:id="p23"><quote>Repeat until done,</quote> as the saying goes.</para>

<para xml:id="p24">After I got all the libraries in place for all the commands that
I wanted to be able to run, I was able to try it out. It didn't work,
of course. I was able to <command>chroot /AccelX /bin/bash</command>,
but when I ran <command>Xaccel</command>, it died.</para>

<para xml:id="p25">The next step was <command>strace</command>. The <command>strace</command>
command shows you all the system calls that an application attempts.
For example, here's the start of a trace of <command>ls</command> (I've
edited the output a bit to make it fit neatly in the column):</para>

<screen>$ strace ls
execve("/bin/ls", ["ls"], [/* 85 vars */]) = 0
uname({sys="Linux", node="mercury", ...}) = 0
brk(0)                                  = 0x8059d50
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE,
      MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40013000
open("/etc/ld.so.preload", O_RDONLY)    = -1 ENOENT
     (No such file or directory)
open("/usr/local/soadabas/lib/i686/mmx/cmov/librt.so.1",
     O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/usr/local/soadabas/lib/i686/mmx/cmov",
     0xbfffe2a0) = -1 ENOENT (No such file or directory)
...</screen>

<para xml:id="p26">All those <errorname>ENOENT</errorname> errors show attempts by
<command>ls</command> to open files that don't exist. By examining the
trace of <command>Xaccel</command>, I was able to determine what other
files it wanted to access, and by copying the ones that actually
existed on my system over into the <filename>/AccelX</filename> root,
I was able to get the program to run.</para>

<para xml:id="p27">(Actually, I had to use <command>mknod</command> to setup some
devices and do a few other things, but there turned out to be a better
way.)</para>

<para xml:id="p28">Success! Almost.</para>

<para xml:id="p29">I could run <application>X</application> now, but nothing could
talk to it. The problem, informally, is that the server communicates
some vital information to the rest of the world through a special file
under <filename>/tmp</filename>. But the server's
<filename>/tmp</filename> is really <filename>/AccelX/tmp</filename> so
applications aren't seeing the server's file.</para>

<para xml:id="p30">The last little trick turns out to be a feature of
<command>mount</command> that I didn't know about. The
<option>--bind</option> option allows you to make the same directory
appear in two different places. Why do you want to do that? For
occasions just like this one. Running:</para>

<screen>mount --bind /tmp /AccelX/tmp</screen>

<para xml:id="p31">makes <filename>/AccelX/tmp</filename> the same as the real
<filename>/tmp</filename>. So now the <filename>/tmp</filename> that
<command>Xaccel</command> sees when it's been chrooted is exactly the
same <filename>/tmp</filename> seen by the rest of the
applications on my laptop.</para>

<para xml:id="p32">So instead of making devices in <filename>/AccelX/dev</filename>,
I can just bind <filename>/dev</filename>. The same is true for:
<filename>/proc</filename>,
<filename>/var</filename>, <filename>/usr/share</filename>,
and <filename>/usr/X11R6/lib/X11/fonts</filename>. The last two assure
that I get the right fonts.</para>

<para xml:id="p33">With the right mounts and the right libraries, I can now run
<command>chroot /AccelX /usr/X11R6/bin/Xaccel</command> to start
<application>X</application> and everything works just fine, even with
the rest of my system upgraded to the latest libraries.</para>

<para xml:id="p34">(I did have a few moments consternation when I was trying to run
X with output redirected. Apparently that doesn't work, it interferes
with interprocess communication too.)</para>

<para xml:id="p35">In any event, success! Whew!</para>

</essay>

