The "statute of limitations" must have passed long ago, so I confess to having been the author of the original tac (cat in reverse). I was working on a project that wrote log files, but the logs were very "bursty". Minutes might go by without any activity, followed by a burst of logging activity. We often wanted to see the most recent burst of activity, so "tail -f" wouldn't do the job. It would show the next burst of activity, which might not occur for quite some time. Somebody posted a functional equivalent on some netnews group, but it was ghastly. I think it did seeks of -1 characters at a time to accumulate each line. That would have been fast enough to feed our pathetic 1200 baud terminals, but it would have beat the system to death, and that would have been a disservice to other users. My version did reads of 512 bytes on 512-byte boundaries, so it put much less load on the system. I couldn't bear to see something like the netnews version
get adopted. The software release process at the Labs was a bureaucratic nightmare, so I "tossed my version over the wall", into the arms of Andy Tanenbaum, as I recall. He made it public, attributed to "an unknown author".
I don't know how Rob Pike got ahold of it, but he recognized that mailbox files had the same bursty growth. Unlike our log files, whose contents were acceptably understandable in reverse order, mail messages were hard to read in reverse order, so he proposed making it possible to recognize the headers at the start of each mail message, and put the entire message out in readable order. I think that was a useful option, but the irony of Rob adding an option to "tac" was hard to overlook.
The version out there now was rewritten by Jay Lepreau, it seems:
/*
* tac.c - Print file segments in reverse order
*
* Original line-only version by unknown author off the net.
* Rewritten in 1985 by Jay Lepreau, Univ of Utah, to allocate memory
* dynamically, handle string bounded segments (suggested by Rob Pike),
* and handle pipes.
*/
Dynamic buffer allocation rather than relying on the time-honored 512-bytes-is-enough assumption was a positive, as was supporting Rob's suggestion. Handling pipes strikes me as a waste of code, but hey, anything is better than that version I replaced.