Make fatal() and debug() macros atomic

Previously these used printf(), which buffers by default in glibc. Since we
actually want that buffering in the rest of the program, use snprintf() to
generate messages, and invoke the raw write() syscall to write those messages
to the screen.