mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-10-29 01:38:37 -04:00
cache_bust() in web/includes/functions.php symlinks every css and js file to a name with the source file's mtime in it, so each time a source changes a new link appears and the old one is left behind. Nothing has ever removed them. The install this was written on had 8346 entries going back to April 2020, 1562 of them pointing at files that no longer exist -- one of which was the log.js deleted in the log panel refactor, still being served because the skin auto-includes views/js/<view>.js whenever that file is present. The directory inode had grown to 823KB, which every lookup in that directory has to scan. misc/zoneminder-tmpfiles.conf.in did not mention the directory at all, so systemd neither created nor cleaned it. Add it as a d entry with a 30d age, which the daily systemd-tmpfiles-clean.timer then acts on. On the age, and why it is generous rather than a day or two: a symlink's mtime and ctime are fixed when it is created, and neither being served nor having its target read refreshes them -- verified here that traversing a symlink does not update its atime either. So an age removes entries whether or not they are in use, rather than only the unused ones. That is safe, because the directory is derived and not authoritative: a link removed while still wanted is recreated by the next page render, so the worst case is one missing asset on a page that was already open. 30d keeps about a month of source versions for a few recreated symlinks a month, where a short age would churn the whole set repeatedly for no further benefit. d and not D: D empties the directory at boot, which would throw away every current entry on every reboot. Tests: tests/php/test_tmpfiles_conf.php, 12 checks. Nothing exercises this file during a build or a test run, and a mistake in it is quiet in both directions -- a malformed line is skipped with a log message nobody reads, and a missing age field just means a directory grows forever, which is how this one got to 8346 entries. So the fields are parsed and checked, and the entry is checked to name the same cmake variable that config.php.in defines ZM_DIR_CACHE from, since if those two drift systemd would clean a directory nothing writes to and nothing would report it. The last check hands the file to systemd-tmpfiles itself, with every path rewritten into a temporary directory first so that running a clean cannot touch anything real. That check skips where systemd-tmpfiles is not installed. Confirmed separately that a d entry with an age does remove symlinks, which is what this directory is made of. Verified the checks fail when the age is dropped, when d becomes D, when the entry names a variable config.php.in does not use, and on an age systemd would reject. Ran: tests/php/test_tmpfiles_conf.php (12 passed), the rest of tests/php and tests/js, npx eslint . (clean), utils/check-homoglyphs.py (clean). test_bandwidth_clamp.php fails on this box for an unrelated reason: it cannot read /etc/zm/conf.d/03custom.conf and the permission warning lands in its captured output. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JpiSWBmtQkR5bcgpHWY4ME