Terminal, zsh & [Process Completed]

This is mostly a “me too!” post, but it’s been bugging me. Every other time I open a new Terminal window (under OS X Tiger, anyway), I get a [Process Completed] message instead of my shell. According to other people, this happens more if you use zsh, and especially if you close the window using ⌘-W. Interestingly, the same problem occurs in iTerm.

Well, I spent some time with ktrace, zsh, bash and Terminal. Sadly, the results aren’t terribly informative (so far).

First of all, I traced both bash and zsh exiting when ⌘-W was pressed. Neither was particularly interesting. There were no cleanups that one performed that the other did not.

Next, I traced Terminal (and its child processes) when starting up zsh. Twice. The first time everything worked, the second time everything broke. Now the trace makes the point of breakage plainly clear. The broken one gets stuck in a loop reading EOF from file descriptor 17, whereas the working one does not.

Looking back through the trace, file descriptor 17 is opened to /dev/ptyp4. According to pty, that’s a master pseudo terminal. It’s opened inside the Terminal process itself, which then forks, dup2’s the master pty to fd 0 (stdin) and then exec’s /usr/libexec/pt_chown (pt_chown source in FreeBSD should be similiar, judging by strings output).

We don’t see any output for pt_chown as it’s setuid root. But Terminal waits for it to finish, after it’s presumably corrected the ownership of the slave tty. Next, fd 18 is opened by Terminal as the slave tty4, Terminal forks and it’s then dup’d to stdin, stdout and stderr. fd 17 is then closed in that process and login is called.

At this point, Terminal’s got pty4 open, and login’s got tty4 and it’s basically a pipe between the two processes. Except that the kernel is making it look like a genuine 70’s era serial connection to the slave.

Anyway, it’s here that the two traces diverge (coming back to the original problem). The good session reads from the master pty, and then calls stat(2) on tty4. But it’s weird as the trace shows no return value for the read call. OTOH, the broken trace just shows a return value of EOF (0 bytes read) and loops around doing that for a few thousand times.

Funnily enough, the trace looks pretty much identical to that which would be produced by program 19.3 in Rich Steven’s APUE (best book I ever bought).

Sadly, it still hasn’t gotten me to the bottom of the problem. But I have refreshed my memory about how pseudo-terminals work. 🙂 I suspect that to make further progress, I’d have to run login under ktrace as well. I imagine that something is going wrong in there causing it to exit early, which is why the read in the parent returns EOF. Even then, I’m not sure if running it all as root would affect the outcome. Probably is my guess…

And no, I will not stop using zsh!

Update: A useful tip for debugging what your shell is doing at startup under osx. Add these lines to the top of ~/.zshrc (or ~/.bashrc if you’re a luddite 😉 ):

  lsof -p $$ > ~/lsof.out.$$
  ktrace -p $$ -f ~/ktrace.out.$$

This still doesn’t capture what’s going on in the parent process (login), but it does give you an idea of what the shell is getting up to.


XSLT Character Creation

I’ve just spent most of the afternoon on a character building exercise. I have some XML like this:

  <symbol unicode="2103"/>

And I need to turn that into the numeric character reference . It’s perfectly possible to do so with a bit of fudging around with <xsl:text disable-output-escaping="yes"/>. But there’s a slight caveat: You’re not creating a numeric character reference. You’re just creating something that looks like one. Really, it’s the characters “&”, ”#”, “x”, “2”, “0”, “1”, “3” and ”;”.

Now most of the time, this doesn’t matter. You just output XML that looks correct and the next parser along (probably a browser) will interpret it correctly. But it’s sleight of hand.

Today, I needed to copy the text contents of a node into an attribute. Unfortunately, that text content contained one of these symbol tags. But because it’s only a string, XSLT feels (correctly) that it needs to escape the leading ampersand. So, with this input:

  <name>Fred <symbol unicode="2013"/> Bloggs</name>

I get this output:

  <name attrib="Fred &amp;#x2013; Bloggs">Fred – Bloggs</name>

Yes, I know that the input data is completely stupid. I can’t help that. Unfortunately I also have the restriction that I can’t do this in multiple passes.

I’ve looked at the standard XSLT functions and the standard XPath functions. I’ve looked at the EXSLT functions. All I want is something that works like Perl’s chr.

I noticed that Saxon has the saxon:entity-ref function, but annoyingly, libxslt doesn’t support it.

All I really need is some way of re-invoking the XML parser over a string of my choosing. That way I could just wrap the characters in an element, parse it and call text() to get the character I need.

Right now, the only way that I can see of doing this is to turn UnicodeData.txt into one big XML lookup table, and lookup the numbers in that. Bleeeaaargh.

Thankfully, it’s not my project and the person doing it has just hacked around this in the output layer. But it bugs me that there’s no good way to achieve this.


A Month of Mac

It’s now been a month since my shiny new Mac arrived. Overall, I’m still really, really happy with it. I’ve bought NetNewsWire for feed reading and textmate for editing. I’m a little concerned that I don’t have the source code for my editor, but we’ll see how that goes.

I’m normally a devout Emacs or Vim user, but Aquamacs turned out to be just too different, despite what Tim Bray says about it. Carbon Vim was a bit better, but still felt a little clunky. TextMate just felt right, and after the recommendations from the rails people, it seemed like a good idea.

The main irritation that I’ve been having is with the keyboard. Apple keyboards don’t come easily to UK Unix users. The tilde is in the wrong position to start with (it’s been swapped with backslash), and I find myself continually hitting the wrong one. Worse is the fact that there’s no hash key on the keyboard in the UK layout. Oh all right, you can hit ⌥-3, but that pastes into the shell as UTF-8 meaning that you can’t comment things out properly in Vim. Why? I have no idea. But it’s meant that I’ve stuck to the US keyboard layout for now, which sucks.

By far and away the worst problem, though is the simple fact that you can’t copy CDs easily. The damned machine comes with a CD burner. It should be a piece of cake to say “take the bits off of this one, then right them on to this blank disk instead”. But no. The only option is to import into iTunes (converting into MP3) and then write the low-fi tracks out from iTunes again. With a 2-second gap between tracks. That really, badly sucks. Particularly when I found out that a previous version of OSX used to come with a “disk copy” utility. Thanks a bunch, Apple.


Server Move

Well, after a couple of very long and frustrating evenings, I’ve finally managed to replicate the setup of my old, decrepit server onto a shiny new (and hopefully more reliable) dell box. I thought that this would be easy, as I was under the impression that I had everything under version control. But it’s only when you start on an endeavour like this that you realise just how much tweaking you have done to a box. Some particular highlights of this move:

  • I had been installing my squid.conf to the wrong place for about 2 years.
  • I discovered I’d been running clamscan (command line) instead of calling clamd (daemon) for a year. Slow mail ‘r’ us.
  • I discovered that my PostgreSQL backups had not been running for over a year.
  • I noticed that my trac installation had been wikispammed a few days ago (I didn’t notice when it happened). Trac needs a “revert to previous version” button.
  • Rails has caused me the most grief, surprisingly. getting typo up and running has been a pain. Firstly, because I didn’t have FastCGI installed. But I didn’t get an error for some reason. But whe I did install it, all I got was “FastCGI: incomplete headers (35 bytes) received from server”. I have now learned that this means “something went wrong but I’m not going to tell you what is. In my case, it was needing to install the ruby-postgres drivers. But rails isn’t kind enough to tell you that it can’t load the db drivers you’ve requested, instead it just silently fails. Which is a bit of a nuisance. I’ll have to check the trunk to see if it’s been fixed…

Anyway, now I can finally get on with the other more important tasks that I have to do. I gave up being a sysadmin 5 years ago for a damned good reason.