1

I have a daemon that opens a file and writes to it throughout operation (typically for many days at a time). In order to support log rotation, I want to be able to identify when the file the handle refers to is in a new location from the original.

Is this possible? fstat() doesn't give me anything useful for this situation.

My current solution is, in the log-writing function, testing the existence of the log file and if it's not there, closing the old handle and opening a new handle. This works, but is a hack and has limitations. In my case, our systems group uses a tool for log rotation that requires them to touch the file after rotating it out, which causes my daemon to continue thinking that its file handle points to the correct place.

Mark
  • 999
  • 9
  • 19
  • Have a look at this thread and see if there is a comparable function in the php manual. http://stackoverflow.com/questions/1188757/getting-filename-from-file-descriptor-in-c – Jake Oct 20 '11 at 18:36

3 Answers3

3

Here's a thought. It's not portable, I'm not totally sure if it works or is reliable, and it makes me cringe a little, but you can probably use readlink on /proc/%d/fd/%d, where the first %d is the result of getpid(), and the second is your file descriptor.

There are some caveats here, though. First, the whole "get path + do something with that path" approach will have a race condition in the face of a rename happening concurrently. Also, your log file could have other links. I'm not sure what the behavior is for the links in /proc in the face of a rename, either.

asveikau
  • 39,039
  • 2
  • 53
  • 68
  • The proc file gets at the file descriptor; it's not going to give you a different answer from `fstat` – mkj Oct 20 '11 at 19:06
  • @mkj Are you sure of this? Last I knew `struct stat` did not have a name field. – asveikau Oct 20 '11 at 19:59
  • It's not a name field, it's an `st_ino` field that gives you the inode number. – mkj Oct 20 '11 at 22:03
  • @mkj He's not asking for the inode, he wants the name. The inode would not change via a rename anyway. – asveikau Oct 20 '11 at 23:43
  • This is an interesting approach, @asveikau. I still don't like it since, as you pointed out, there's still a race condition, but writing one entry to the old file is preferable to what's happening now (continuing to write to the wrong file perpetually when the condition is reached). – Mark Oct 21 '11 at 12:59
  • @asveikau I understand the question. I'm saying that if `fstat` on the file descriptor and `lstat` on the file name produce a different inode number, then the file has been moved. He's not asking for the name, he's asking whether the name is different from what it used to be. – mkj Oct 21 '11 at 22:21
  • @mkj - That makes sense when you put it that way, except that earlier you didn't. :-) – asveikau Oct 22 '11 at 18:51
0

You can simply periodically re-acquire your file handle (with mode a), for example every 24 hours. That allows you to continue logging despite the presence of the moronic and buggy(since there is an inevitable race condition between renaming the file and re-touching it) log rotation utility.

phihag
  • 278,196
  • 72
  • 453
  • 469
0

fstat gives you an inode number, which will change when the log is rotated.

See http://php.net/manual/en/function.fstat.php and http://www.php.net/manual/en/function.lstat.php

You can compare the inode number from fstat with the inode number from lstat; if they are different, reopen.

The standard way of handling this for Unix daemons in the past has been to catch SIGHUP and use it as a signal to reopen the log file, and have the log rotation script send SIGHUP.

mkj
  • 1,274
  • 11
  • 8
  • From my testing, the inode does not change when a file is moved. Since there doesn't seem to be a good, reliable solution, I think handling SIGHUP may be the way I end up going. – Mark Oct 21 '11 at 12:48
  • Exactly, the inode number does not change when a file is moved. If `fstat` on your file descriptor produces a different inode number than `lstat` on the name of the file as you open it, then the file has been moved or deleted since you opened it. All that said, implementing `SIGHUP` handling is The Unix Way. Checking `lstat` vs. `fstat` is a backup strategy in case someone forgets to send `SIGHUP`. – mkj Oct 21 '11 at 22:18