Somewhat pedantically, I discovered a bug where a daemon (which did this very similar code) started killing random processes. The issue turned out to be that it was test run as root once and the pid_file was owned by root, group root. So the write_pid() function failed (silently) and the cleanup script always took the pid that was in pid_file and sent it a kill 9, which was now stuck. Sometimes kill 9 would return invalid pid, sometimes it would kill some process. Fixed by removing the pid_file, letting the daemon create it, and checking that the write succeeded.
You should always put a break statement at the end of a default branch. The default case is put at the end as a convention but no one (certainly not the C standard) prevents you from adding a new case after, which will be promptly executed even though probably it's what you want. I think this is mentioned a best practice in the K&R.
smart-ass comment: you should put two breaks in for when some programmer removes one of them six months from now. ;)
edit: i know it's not totally analogous since removing the exit and not noticing there's no break is a lot more likely than just randomly removing a break, but the "let's prevent someone clumsy from screwing this code up in the future" argument always makes me laugh a little.
Sure, you could have pid = fork(); switch (pid) if you prefer. I find that the inline assignment-and-condition style is clearer since it reads to me as "switch on the result of fork, and cache that value somewhere" whereas the separate statements read to me as "call fork" and "switch on the process ID".
daemon(3) isn't part of POSIX, and the OS X man page says "the use of this API is discouraged in favor of using launchd(8)", so who knows what might happen here in the future.
If you don't care about portability, it's an easier call to make.
I'm kinda surprised that the assignment-during-test thing doesn't generate a warning in the case of a switch statement. It does in other cases (if and while do under gcc and clang, at least).
Assignment-during-test is flagged because it's common for a typo to conflate assignment and equality-testing. Equality-testing is very common in an if or while, so an assignment inside an if or while has a fairly high likelihood of actually being a mis-typed equality-test. Switch, on the other hand, is very rarely used with an equality-test (since equality-test only returns true or false, why would you use a switch when an if would suffice?). So an assignment inside a switch is much less likely to be a mis-typed equality-test.
Careful with that example. The parentheses here don't just remove the warning. They remove a bug. This code:
if (buf = malloc(buflen) == NULL)
goto outofmemory;
is actually equivalent to that code:
if (buf = (malloc(buflen) == NULL))
goto outofmemory;
So, malloc gives you a pointer, which is compared to the null pointer, giving you either 0 or 1. And that is assigned to buf. Hopefully your compiler will warn you about the type error that spawns from such dark magic.
I was originally going to comment saying exactly that — under gcc and clang, at least, just the extra parens will disable the warning; no comparison necessary — but thought to test that the warning is generated in case of a switch statement (and is then disabled by the extra set of parens), which led to realizing the behavior is different.