По ману крон должен раз в минуту перечитывать содержимое crontab, в том числе и /etc/cron.d/*. Он так и делает. Только вот он смотрит на время изменения каталога cron.d а не на время изменения файлов внутри каталога. То есть если файлы внутри cron.d пересоздавать, то они изменяют время модификации каталога и крон их перечитывает. А если просто изменять - то время изменения каталога не меняются и крон считает, что неча ему там смотреть. Возможно это "фича", но, imho, это баг =/
Серёж, не смотрел на текущий часом?
(In reply to comment #1) > Серёж, не смотрел на текущий часом? Этот баг добавляется патчем vixie-cron-4.1.20040916-owl-crond.patch, который, судя по history, обновлялся с 2004 года ровно один раз и по абсолютно другой причине. Так что баг актуален должен быть всё ещё актуален.
2 ldv: баг/фича/багофича/отдам?
(В ответ на комментарий №3) Судя по тому, что баг висит 4 года он явно никому не critical.
Угу.
Благодаря этой баге, задание выполнилось нескорректированным. (Изначально задание было записано в файл /etc/cron.d/rsync, затем подправлено.) По системным логам, изменения задания не были замечены. Только - после рестарта службы crond. Прошу исправить слежку.
(В ответ на комментарий №6) > Прошу исправить слежку. Vixie-cron применяется также в Debian 7 (пакет cron, информация по man). Там такой баг не воспроизводится: задания автоматически корректируются после изменения файла /etc/cron.d/* без дополнительных действий.
В man у Debian написано такое: Like /etc/crontab, the files in the /etc/cron.d directory are monitored for changes. In general, the system administrator should not use /etc/cron.d/, but use the standard system crontab /etc/crontab. То есть хотя поддержка и есть, они предлагают их не использовать почему-то. Ну в Debian есть несколько патчей для правильной поддержки run-parts: https://launchpadlibrarian.net/188407008/cron_3.0pl1-127ubuntu1.diff.gz
Подтверждается на vixie-cron 4.1.20060426-alt10.3. Причина — в патче vixie-cron-4.1.20040916-owl-crond.patch: load_database() считает maxtime только по mtime каталогов (/var/spool/cron, /etc/cron.d) и /etc/crontab, поэтому правка файла в /etc/cron.d на месте (без пересоздания) не замечается до перезапуска crond. Проверено в контейнере Sisyphus: задание в /etc/cron.d/t5910 «* * * * * root echo A >> /tmp/out», через две минуты файл перезаписан на «echo B» (inode и mtime каталога не менялись) — стоковый crond продолжает выполнять A (вывод «A A A»). С патчем ниже (собран как alt10.4 в podman) после перезаписи выполняется B («A A A B»). Пакет по rdb orphaned (ldv@ — 2016, последняя сборка antohami@ — 2022), нужен желающий собрать. Track mtime of files in system crontab directories, not only of the directories crond only re-reads /etc/cron.d when the mtime of the directory itself changes, i.e. when a file is created, removed or renamed. Editing a file in place (which is what most editors and "cat > file" do) leaves the directory mtime untouched, so the change is silently ignored until crond is restarted. Take the newest mtime among the files of every tracked directory into account as well. --- a/usr.sbin/cron/database.c +++ b/usr.sbin/cron/database.c @@ -48,6 +48,38 @@ static void process_crontab(const char *, const char *, const char *, struct stat *, cron_db *, cron_db *); +/* Return the newest of MAXTIME and the mtimes of the regular files in + * directory PATH. Editing a crontab in place does not touch the mtime + * of the directory, so the directory mtime alone is not enough to + * notice the change. + */ +static time_t +dir_files_mtime(const char *path, time_t maxtime) +{ + struct stat st; + DIR_T *dp; + DIR *dir; + char tabname[MAXPATHLEN]; + + if (!(dir = opendir(path))) + return maxtime; + + while (NULL != (dp = readdir(dir))) { + if (dp->d_name[0] == '.') + continue; + if (snprintf(tabname, sizeof tabname, "%s/%s", path, + dp->d_name) >= sizeof(tabname)) + continue; + if (stat(tabname, &st) < OK || !S_ISREG(st.st_mode)) + continue; + if (st.st_mtime > maxtime) + maxtime = st.st_mtime; + } + closedir(dir); + + return maxtime; +} + void load_database(cron_db *old_db) { struct stat statbuf, syscron_stat; @@ -74,6 +106,7 @@ load_database(cron_db *old_db) { } if (statbuf.st_mtime > maxtime) maxtime = statbuf.st_mtime; + maxtime = dir_files_mtime(p->path, maxtime); p++; }