tmpwatchが機能しない問題

/tmp以下のファイルが10日たっても削除されず、tmpwatchが機能していないようだった。
/tmp以下のmtime, atime, ctimeを ls -l, ls -ul, ls -cl でそれぞれ見ていくと、ctimeがtmpwatchがcronで動いた時間になっていた。

tmpwatchがctimeを常に書き換えてしまい、tmpwatchが機能しない問題は、Red Hat Bugzillaに原因が書いてあった。
https://bugzilla.redhat.com/show_bug.cgi?id=51325

Preston Brown

2001-08-13 15:40:52 EDT

The mtime for a file or directory is updated by the filesystem each time the file is modified. Prior to modifying a file, an application can save the file's mtime, and then reset it after the modification using the utime(2) system call.

The atime for a file or directory is updated by the filesystem each time the file is accessed (read or write). Prior to accessing a file, an application can save the file's atime, and then reset it after the file access using the utime(2) system call.

The ctime for a file or directory is updated each time the file or directory's inode is changed; examples of this are changing permissions, ownership, link-counts, etc. The ctime for a file or directory can NOT be saved before and reset after a change. Another significant fact is that the ctime of a file or directory is CHANGED when resetting the mtime and atime (using the utime(2) system call) for the file.

When tmpwatch reads the data for a file to determine whether or not it should be removed, it does not affect the file modification time, but does affect the file's access time. For this reason, NetBackup saves the file's atime and mtime prior to reading the file, and resets the atime and mtime using the utime(2) system call. By "covering it's tracks", tmpwatch does not cause grief for HSM products or administrator scripts that are utilizing file access times (atime) as criteria for their operations. While this benefit is obvious, a side effect is that it does update the file's ctime.

There is no way around this while maintaining compatibility with UNIX standards.

要は、tmpwatchがatimeを元に戻す時にutime(2) system callを使用するが、そのせいでctimeが変わってしまうらしい。
tmpwatchがファイルを確認し、また確認の結果削除するときに、ディレクトリに読み書きするとmtimeとatimeが変わってしまうので、それを元に戻している。

対策を考える前に、念のためtmpwatchの仕組みを確認する。

tmpwatchの仕組み

tmpwatch [option] [hours] [dirs]

削除ルール

  • シンボリックリンクはたどらない
  • ファイルシステムを超えて処理しない
  • root がオーナの lost+found は処理しない
  • 空のディレクトリ、通常のファイル、シンボリックリンクのみ削除

オプション

  • -u:最終アクセス時刻
  • -m:最終ファイル変更時刻
  • -c:最終i-node変更時刻
  • -x:指定したパスを対象外とする
  • -X:指定したパターンにマッチしたパスを対象外とする
  • -f:rootが書き込み権限を持っていなくても削除する(rm -fと同様)

/etc/cron.daily/tmpwatch

cronで毎日tmpwatchが起動するようになっている。

$ cat /etc/cron.daily/tmpwatch
#! /bin/sh
flags=-umc
/usr/sbin/tmpwatch "$flags" -x /tmp/.X11-unix -x /tmp/.XIM-unix \
        -x /tmp/.font-unix -x /tmp/.ICE-unix -x /tmp/.Test-unix \
        -X '/tmp/hsperfdata_*' 10d /tmp
/usr/sbin/tmpwatch "$flags" 30d /var/tmp
for d in /var/{cache/man,catman}/{cat?,X11R6/cat?,local/cat?}; do
    if [ -d "$d" ]; then
        /usr/sbin/tmpwatch "$flags" -f 30d "$d"
    fi
done

tmpwatchのcron解説

flags=-umcと記載があり、tmpwatch に -umc オプションが付加される。
-u, -m, -c が同時に指定されると、最大値(最新時刻)が判定条件になる。

-x オプションで「/tmp/.X11-unix」等が、-X オプションでワイルドカード指定により「/tmp/hsperfdata_」から始まるパスが、tmpwatchの処理対象外になっている。

/tmpは10日経っていると(10d)削除される。/var/tmpは30日経っていると(30d)削除される。
ちなみに、/tmpと/var/tmpの違いは、/tmpが「再起動するとファイルが消える」領域であるのに対して、/var/tmpは「再起動してもファイルが消えない」領域である、という点にある。

/var/{cache/man,catman}/{cat?,X11R6/cat?,local/cat?}は、それぞれディレクトリであれば([ -d "$d" ])、30日経っていると w 権限がrootについていなくても強制的に(-f)削除される。

$ ls -d /var/{cache/man,catman}/{cat?,X11R6/cat?,local/cat?}
/var/cache/man/X11R6/cat1  /var/cache/man/X11R6/cat9  /var/cache/man/cat7        /var/cache/man/local/cat5
/var/cache/man/X11R6/cat2  /var/cache/man/X11R6/catn  /var/cache/man/cat8        /var/cache/man/local/cat6
/var/cache/man/X11R6/cat3  /var/cache/man/cat1        /var/cache/man/cat9        /var/cache/man/local/cat7
/var/cache/man/X11R6/cat4  /var/cache/man/cat2        /var/cache/man/catn        /var/cache/man/local/cat8
/var/cache/man/X11R6/cat5  /var/cache/man/cat3        /var/cache/man/local/cat1  /var/cache/man/local/cat9
/var/cache/man/X11R6/cat6  /var/cache/man/cat4        /var/cache/man/local/cat2  /var/cache/man/local/catn
/var/cache/man/X11R6/cat7  /var/cache/man/cat5        /var/cache/man/local/cat3
/var/cache/man/X11R6/cat8  /var/cache/man/cat6        /var/cache/man/local/cat4

tmpwatchがctimeのせいで機能しない問題への対策

tmpwatchの仕組みを踏まえた上で、tmpwatchがctimeのせいで機能しない問題への対策を考えると、/etc/cron.daily/tmpwatchのflags=-umcflags=-umにすべきということになる。

あと、今回の問題とは関係ないが、/tmpや/var/tmpでも、書き込み権限がなくても削除したいなら -f オプションをつけるといい。

参考
http://shobon.hatenablog.com/entry/2014/07/30/223550
http://shobon.hatenablog.com/entry/2014/10/15/213154