Линукс дээрх Cron: түүх, хэрэглээ, төхөөрөмж

Линукс дээрх Cron: түүх, хэрэглээ, төхөөрөмж

Сонгодог нь аз жаргалтай цагийг үздэггүй гэж бичжээ. Тэр зэрлэг цаг үед програмистууд ч, Юникс ч байгаагүй, гэхдээ өнөөдөр програмистууд тодорхой мэддэг: cron тэдний оронд цагийг бүртгэх болно.

Тушаалын шугамын хэрэгслүүд нь миний хувьд сул тал, ажил юм. sed, awk, wc, cut болон бусад хуучин программуудыг манай серверүүд дээр өдөр бүр скриптээр ажиллуулдаг. Тэдгээрийн ихэнх нь 70-аад оны үеийн хуваарьлагч cron-д зориулсан даалгавар болгон бүтээгдсэн.

Удаан хугацааны турш би cron-г нарийн ширийн зүйлгүйгээр өнгөцхөн ашигладаг байсан ч нэг өдөр скрипт ажиллуулах явцад алдаа гарахад би үүнийг сайтар судлахаар шийдсэн. Энэ нийтлэл ингэж гарч ирсэн бөгөөд үүнийг бичиж байхдаа би POSIX crontab, алдартай Linux түгээлтийн үндсэн cron сонголтууд болон тэдгээрийн заримын бүтцийг мэддэг болсон.

Та Линукс ашиглаж, cron даалгавруудыг ажиллуулж байна уу? Та Unix дэх системийн хэрэглээний архитектурыг сонирхож байна уу? Тэгвэл бид явж байна!

Агуулга

Төрөл зүйлийн гарал үүсэл

Хэрэглэгч эсвэл системийн програмуудыг үе үе гүйцэтгэх нь бүх үйлдлийн системд зайлшгүй шаардлагатай байдаг. Тиймээс програмистууд даалгавраа төвлөрсөн байдлаар төлөвлөж, гүйцэтгэх боломжийг олгодог үйлчилгээний хэрэгцээг аль эрт ойлгосон.

Юникстэй төстэй үйлдлийн системүүд нь өнгөрсөн зууны 7-аад онд Белл лабораторид, тэр дундаа алдарт Кен Томпсоны бүтээсэн Unix хувилбар 70-оос эхтэй. Unix-ийн 7 хувилбарт мөн супер хэрэглэгчийн даалгавруудыг тогтмол гүйцэтгэх cron үйлчилгээ багтсан.

Орчин үеийн ердийн cron бол энгийн програм боловч анхны хувилбарын үйлдлийн алгоритм нь илүү хялбар байсан: үйлчилгээ нь минутанд нэг удаа сэрж, нэг файлаас (/etc/lib/crontab) даалгавар бүхий хүснэгтийг уншиж, Одоогийн байдлаар гүйцэтгэх ёстой байсан ажлуудыг супер хэрэглэгч.

Дараа нь энгийн бөгөөд ашигтай үйлчилгээний сайжруулсан хувилбарууд нь Unix-тэй төстэй бүх үйлдлийн системүүдээр хангагдсан.

Crontab форматын ерөнхий тодорхойлолт, хэрэгслийн үйл ажиллагааны үндсэн зарчмуудыг 1992 онд Unix-тэй төстэй үйлдлийн системүүдийн үндсэн стандарт болох POSIX-д оруулсан бөгөөд ингэснээр de facto стандартаас cron нь de jure стандарт болсон.

1987 онд Пол Викси Unix-ийн хэрэглэгчдийн кроныг хүсч буй байдлын талаар асууж үзээд уламжлалт cron-ийн зарим асуудлыг засаж, хүснэгтийн файлуудын синтаксийг өргөжүүлсэн демоны өөр хувилбарыг гаргажээ.

Vixie cron-ийн гурав дахь хувилбар нь POSIX-ийн шаардлагыг хангаж эхэлсэн бөгөөд үүнээс гадна програм нь либерал лицензтэй байсан, эс тэгвээс README дахь хүслээс бусад тохиолдолд лиценз огт байхгүй байсан: зохиогч баталгаа өгдөггүй, зохиогчийн нэр устгах боломжгүй бөгөөд програмыг зөвхөн эх кодын хамт зарах боломжтой. Эдгээр шаардлагууд нь тухайн жилүүдэд түгээмэл болж байсан үнэгүй програм хангамжийн зарчмуудтай нийцэж байсан тул 90-ээд оны эхээр гарч ирсэн Линуксийн гол түгээлтийн зарим нь Vixie cron-ийг өөрийн систем болгон авч, өнөөг хүртэл хөгжүүлсээр байна.

Ялангуяа Red Hat болон SUSE нь Vixie cron - cronie-ийн сэрээ хөгжүүлдэг бол Debian болон Ubuntu нь олон засвартай Vixie cron-ийн анхны хувилбарыг ашигладаг.

Эхлээд POSIX-д тайлбарласан crontab хэрэглэгчийн хэрэглүүртэй танилцацгаая, үүний дараа бид Vixie cron-д өгсөн синтакс өргөтгөлүүд болон Linux-ийн түгээмэл тархацуудад Vixie cron-ийн хувилбаруудыг ашиглах талаар авч үзье. Эцэст нь, бялуу дээрх интоор нь cron demon төхөөрөмжийн шинжилгээ юм.

POSIX crontab

Хэрэв анхны cron нь үргэлж супер хэрэглэгчийн төлөө ажилладаг байсан бол орчин үеийн хуваарьчид ихэвчлэн энгийн хэрэглэгчдийн даалгаврыг гүйцэтгэдэг бөгөөд энэ нь илүү найдвартай, тохиромжтой байдаг.

Кроныг хоёр програмын багц хэлбэрээр нийлүүлдэг: байнгын ажиллагаатай cron дэмон ба хэрэглэгчдэд ашиглах боломжтой crontab хэрэгсэл. Сүүлийнх нь систем дэх хэрэглэгч бүрт тусгайлан зориулсан даалгаврын хүснэгтүүдийг засах боломжийг олгодог бол демон нь хэрэглэгчийн болон системийн хүснэгтээс даалгавруудыг ажиллуулдаг.

В POSIX стандарт демоны зан төлөвийг ямар ч байдлаар тайлбарлаагүй бөгөөд зөвхөн хэрэглэгчийн програмыг албан ёсны болгосон Crontab. Хэрэглэгчийн даалгаврыг эхлүүлэх механизм байгаа нь мэдээжийн хэрэг, ойлгомжтой боловч нарийвчлан тайлбарлаагүй болно.

Crontab хэрэглүүрийг дуудсанаар та засварлагчийн хэрэглэгчийн даалгаврын хүснэгтийг засварлах, файлаас хүснэгтийг ачаалах, одоогийн даалгаврын хүснэгтийг харуулах, даалгаврын хүснэгтийг арилгах гэсэн дөрвөн зүйлийг хийх боломжтой. Crontab хэрэгсэл хэрхэн ажилладаг жишээнүүд:

crontab -e # редактировать таблицу задач
crontab -l # показать таблицу задач
crontab -r # удалить таблицу задач
crontab path/to/file.crontab # загрузить таблицу задач из файла

Дуудсан үед crontab -e стандарт орчны хувьсагчд заасан засварлагчийг ашиглана EDITOR.

Даалгавруудыг өөрөө дараахь хэлбэрээр тайлбарласан болно.

# строки-комментарии игнорируются
#
# задача, выполняемая ежеминутно
* * * * * /path/to/exec -a -b -c
# задача, выполняемая на 10-й минуте каждого часа
10 * * * * /path/to/exec -a -b -c
# задача, выполняемая на 10-й минуте второго часа каждого дня и использующая перенаправление стандартного потока вывода
10 2 * * * /path/to/exec -a -b -c > /tmp/cron-job-output.log

Бичлэгийн эхний таван талбар: минут [1..60], цаг [0..23], сарын өдрүүд [1..31], сар [1..12], долоо хоногийн өдрүүд [0. .6], 0 нь Ням гараг. Сүүлийн зургаа дахь талбар нь стандарт командын тайлбарлагчаар гүйцэтгэх мөр юм.

Эхний таван талбарт утгуудыг таслалаар тусгаарлаж жагсааж болно:

# задача, выполняемая в первую и десятую минуты каждого часа
1,10 * * * * /path/to/exec -a -b -c

Эсвэл зураасаар:

# задача, выполняемая в каждую из первых десяти минут каждого часа
0-9 * * * * /path/to/exec -a -b -c

Даалгаврын хуваарьт хэрэглэгчийн хандалтыг POSIX-д cron.allow болон cron.deny файлуудаар зохицуулдаг бөгөөд энэ нь crontab-д хандах эрхтэй болон програмд ​​хандах эрхгүй хэрэглэгчдийг жагсаасан байна. Стандарт нь эдгээр файлуудын байршлыг ямар ч байдлаар зохицуулдаггүй.

Стандартын дагуу эхлүүлсэн програмуудад дор хаяж дөрвөн орчны хувьсагч дамжуулагдах ёстой.

  1. HOME - хэрэглэгчийн гэрийн лавлах.
  2. LOGNAME — хэрэглэгчийн нэвтрэх.
  3. PATH бол стандарт системийн хэрэгслүүдийг олох зам юм.
  4. SHELL — ашигласан командын орчуулагч руу очих зам.

POSIX нь эдгээр хувьсагчийн утгууд хаанаас ирдэг талаар юу ч хэлдэггүй.

Шилдэг худалдагч - Vixie cron 3.0pl1

Алдартай cron хувилбаруудын нийтлэг өвөг нь 3.0 онд comp.sources.unix захидлын жагсаалтад танилцуулагдсан Vixie cron 1pl1992 юм. Бид энэ хувилбарын гол онцлогуудыг илүү нарийвчлан авч үзэх болно.

Vixie cron нь хоёр програмтай (cron болон crontab) ирдэг. Ердийнх шиг, демон нь системийн даалгаврын хүснэгт болон хэрэглэгчийн бие даасан даалгаврын хүснэгтээс даалгавруудыг уншиж, ажиллуулах үүрэгтэй бөгөөд crontab хэрэгсэл нь хэрэглэгчийн хүснэгтийг засварлах үүрэгтэй.

Даалгаврын хүснэгт болон тохиргооны файлууд

Супер хэрэглэгчийн даалгаврын хүснэгт нь /etc/crontab дотор байрладаг. Системийн хүснэгтийн синтакс нь Vixie cron-ийн синтакстай тохирч байгаа бөгөөд үүн дэх зургаа дахь багана нь даалгаврыг эхлүүлсэн хэрэглэгчийн нэрийг заасныг эс тооцвол:

# Запускается ежеминутно от пользователя vlad
* * * * * vlad /path/to/exec

Ердийн хэрэглэгчийн даалгаврын хүснэгтүүд нь /var/cron/tabs/username-д байрладаг бөгөөд ижил синтакс ашигладаг. Та crontab хэрэгслийг хэрэглэгчээр ажиллуулахад эдгээр нь засварлагдсан файлууд юм.

Crontab-д хандах эрхтэй хэрэглэгчдийн жагсаалтыг /var/cron/allow болон /var/cron/deny файлуудаар удирддаг бөгөөд та хэрэглэгчийн нэрийг тусдаа мөрөнд оруулахад л хангалттай.

Өргөтгөсөн синтакс

POSIX crontab-тай харьцуулахад Пол Виксигийн шийдэл нь уг хэрэгслийн даалгаврын хүснэгтүүдийн синтаксийн хэд хэдэн маш хэрэгтэй өөрчлөлтүүдийг агуулдаг.

Шинэ хүснэгтийн синтакс боломжтой болсон: жишээлбэл, та долоо хоногийн өдрүүд эсвэл саруудыг нэрээр нь зааж өгч болно (Даваа, Мягмар гэх мэт):

# Запускается ежеминутно по понедельникам и вторникам в январе
* * * Jan Mon,Tue /path/to/exec

Та даалгавруудыг эхлүүлэх үе шатыг тодорхойлж болно:

# Запускается с шагом в две минуты
*/2 * * * Mon,Tue /path/to/exec

Алхам ба интервалыг хольж болно:

# Запускается с шагом в две минуты в первых десять минут каждого часа
0-10/2 * * * * /path/to/exec

Ердийн синтаксийн ойлгомжтой хувилбаруудыг дэмждэг (дахин ачаалах, жил бүр, жил бүр, сар бүр, долоо хоног бүр, өдөр бүр, шөнө дунд, цаг тутамд):

# Запускается после перезагрузки системы
@reboot /exec/on/reboot
# Запускается раз в день
@daily /exec/daily
# Запускается раз в час
@hourly /exec/daily

Даалгаврыг гүйцэтгэх орчин

Vixie cron нь ажиллаж байгаа програмуудын орчныг өөрчлөх боломжийг танд олгоно.

USER, LOGNAME болон HOME орчны хувьсагчдыг дэмоноос өгөөгүй бөгөөд файлаас авсан болно. passwd. PATH хувьсагчийг "/usr/bin:/bin" гэж тохируулсан ба SHELL хувьсагчийг "/bin/sh" гэж тохируулсан. LOGNAME-аас бусад бүх хувьсагчийн утгыг хэрэглэгчийн хүснэгтэд өөрчилж болно.

Зарим орчны хувьсагчдыг (ялангуяа SHELL болон HOME) даалгаврыг гүйцэтгэхийн тулд cron өөрөө ашигладаг. Захиалгат даалгавруудыг ажиллуулахын тулд стандарт sh-ийн оронд bash ашиглах нь дараах байдалтай байна.

SHELL=/bin/bash
HOME=/tmp/
# exec будет запущен bash-ем в /tmp/
* * * * * /path/to/exec

Эцэст нь хүснэгтэд тодорхойлсон орчны бүх хувьсагч (cron ашигладаг эсвэл процесст шаардлагатай) ажиллаж байгаа даалгаварт шилжих болно.

Файлуудыг засварлахын тулд crontab нь VISUAL эсвэл REDİTOR орчны хувьсагчд заасан засварлагчийг ашигладаг. Хэрэв crontab-г ажиллуулсан орчинд эдгээр хувьсагч тодорхойлогдоогүй бол "/usr/ucb/vi"-г ашиглана (ucb нь Калифорнийн их сургууль, Беркли байж магадгүй).

Debian болон Ubuntu дээр cron

Debian болон дериватив түгээлтийн хөгжүүлэгчид гарлаа маш их өөрчлөгдсөн хувилбар Vixie cron хувилбар 3.0pl1. Хүснэгтийн файлуудын синтаксийн хувьд ялгаа байхгүй, хэрэглэгчдийн хувьд энэ нь ижил Vixie cron юм. Хамгийн том шинэ онцлог: Дэмжлэг syslog, SELinux и PAM.

Бага зэрэг мэдэгдэхүйц боловч мэдэгдэхүйц өөрчлөлтүүд нь тохиргооны файлууд болон даалгаврын хүснэгтүүдийн байршлыг агуулдаг.

Debian дахь хэрэглэгчийн хүснэгтүүд нь /var/spool/cron/crontabs санд байрладаг, системийн хүснэгт нь /etc/crontab дотор байдаг. Debian багцын тусгай даалгаврын хүснэгтүүдийг /etc/cron.d дотор байрлуулсан бөгөөд тэндээс cron дэмон автоматаар уншдаг. Хэрэглэгчийн хандалтын хяналтыг /etc/cron.allow болон /etc/cron.deny файлуудаар удирддаг.

Анхдагч бүрхүүл нь /bin/sh хэвээр байгаа бөгөөд энэ нь Debian-д POSIX-д нийцсэн жижиг бүрхүүл юм. Зураас, ямар ч тохиргоог уншихгүйгээр эхлүүлсэн (интерактив бус горимд).

Cron өөрөө Debian-ийн хамгийн сүүлийн хувилбарууд нь systemd-ээр нээгддэг бөгөөд эхлүүлэх тохиргоог /lib/systemd/system/cron.service дээрээс харж болно. Үйлчилгээний тохиргоонд онцгой зүйл байхгүй; илүү нарийн даалгаврын удирдлагыг хэрэглэгч бүрийн crontab дээр шууд зарласан орчны хувьсагчаар дамжуулан хийж болно.

RedHat, Fedora болон CentOS дээр cronie

крони - Vixie cron 4.1 хувилбарын сэрээ. Debian-ийн нэгэн адил синтакс өөрчлөгдөөгүй боловч PAM болон SELinux-ийн дэмжлэг, кластерт ажиллах, inotify ашиглан файлуудыг хянах болон бусад функцуудыг нэмсэн.

Өгөгдмөл тохиргоо нь ердийн газруудад байна: системийн хүснэгт нь /etc/crontab, багцууд хүснэгтүүдээ /etc/cron.d, хэрэглэгчийн хүснэгтүүд /var/spool/cron/crontabs-д ордог.

Демон нь системийн удирдлага дор ажилладаг бөгөөд үйлчилгээний тохиргоо нь /lib/systemd/system/crond.service.

Red Hat-тэй төстэй тархалтууд дээр /bin/sh нь анхдагчаар эхлэх үед ашиглагддаг бөгөөд энэ нь стандарт bash юм. /bin/sh-ээр дамжуулан cron ажлуудыг ажиллуулах үед bash shell POSIX-д нийцсэн горимд ажиллаж эхлэх бөгөөд интерактив бус горимд ажилладаг нэмэлт тохиргоог уншдаггүй гэдгийг тэмдэглэх нь зүйтэй.

SLES болон openSUSE дахь cronie

Германы түгээлтийн SLES болон түүний үүсмэл openSUSE нь ижил cronie ашигладаг. Энд байгаа демоныг мөн systemd доор ажиллуулсан бөгөөд үйлчилгээний тохиргоо нь /usr/lib/systemd/system/cron.service дээр байрладаг. Тохиргоо: /etc/crontab, /etc/cron.d, /var/spool/cron/tabs. /bin/sh нь POSIX-д нийцсэн интерактив бус горимд ажилладаг ижил bash юм.

Vixie cron төхөөрөмж

Орчин үеийн кроны удам угсаа нь Викси кронтой харьцуулахад эрс өөрчлөгдөөгүй боловч хөтөлбөрийн зарчмуудыг ойлгоход шаардлагагүй шинэ шинж чанаруудыг олж авсан хэвээр байна. Эдгээр өргөтгөлүүдийн ихэнх нь муу зохион бүтээгдсэн бөгөөд кодыг төөрөгдүүлдэг. Пол Виксигийн бичсэн cron эх кодыг уншихад таатай байна.

Тиймээс би хөгжлийн хоёр салбарт нийтлэг байдаг cron програмын жишээг ашиглан cron төхөөрөмжийг шинжлэхээр шийдсэн - Vixie cron 3.0pl1. Уншихад хүндрэл учруулдаг ifdef-г арилгаж, жижиг нарийн ширийн зүйлийг орхигдуулах замаар би жишээнүүдийг хялбарчлах болно.

Чөтгөрийн ажлыг хэд хэдэн үе шатанд хувааж болно.

  1. Хөтөлбөрийг эхлүүлэх.
  2. Ажиллуулах ажлуудын жагсаалтыг цуглуулж, шинэчилж байна.
  3. Үндсэн крон гогцоо ажиллаж байна.
  4. Даалгавраа эхлүүл.

Тэдгээрийг дарааллаар нь харцгаая.

Эхлүүлэх

Эхлэх үед процессын аргументуудыг шалгасны дараа cron нь SIGCHLD болон SIGHUP дохионы зохицуулагчийг суулгадаг. Эхнийх нь хүүхдийн процессыг дуусгах тухай бүртгэлийн бичилт хийдэг, хоёр дахь нь бүртгэлийн файлын файлын тодорхойлогчийг хаадаг.

signal(SIGCHLD, sigchld_handler);
signal(SIGHUP, sighup_handler);

Крон демон нь систем дээр үргэлж ганцаараа ажилладаг, зөвхөн супер хэрэглэгчийн хувьд болон үндсэн cron лавлахаас ажилладаг. Дараах дуудлагууд нь демон процессын PID код бүхий түгжих файлыг үүсгэж, хэрэглэгчийн зөв эсэхийг шалгаад одоогийн лавлахыг үндсэн рүү нь өөрчилнө.

acquire_daemonlock(0);
set_cron_uid();
set_cron_cwd();

Процессыг эхлүүлэхэд ашиглах үндсэн замыг тохируулсан:

setenv("PATH", _PATH_DEFPATH, 1);

Дараа нь процессыг "даемонжуулсан": энэ нь fork-ыг дуудаж, хүүхдийн процесст (setsid дуудах) шинэ сессийг дуудаж процессын хүүхдийн хуулбарыг үүсгэдэг. Эцэг эхийн процесс шаардлагагүй болсон бөгөөд энэ нь гарна:

switch (fork()) {
case -1:
    /* критическая ошибка и завершение работы */
    exit(0);
break;
case 0:
    /* дочерний процесс */
    (void) setsid();
break;
default:
    /* родительский процесс завершает работу */
    _exit(0);
}

Эцэг эхийн үйл явцыг дуусгавар болгосноор түгжээний файл дээрх түгжээг суллана. Нэмж дурдахад файл дахь PID-г хүүхдэд шинэчлэх шаардлагатай. Үүний дараа даалгаврын мэдээллийн санг бөглөнө:

/* повторный захват лока */
acquire_daemonlock(0);

/* Заполнение БД  */
database.head = NULL;
database.tail = NULL;
database.mtime = (time_t) 0;
load_database(&database);

Дараа нь cron үндсэн ажлын мөчлөг рүү шилждэг. Гэхдээ үүнээс өмнө даалгаврын жагсаалтыг ачаалах талаар үзэх нь зүйтэй.

Ажлын жагсаалтыг цуглуулж, шинэчилж байна

load_dabase функц нь даалгаврын жагсаалтыг ачаалах үүрэгтэй. Энэ нь үндсэн системийн crontab болон хэрэглэгчийн файл бүхий директорийг шалгадаг. Хэрэв файл, лавлах өөрчлөгдөөгүй бол даалгаврын жагсаалтыг дахин уншихгүй. Үгүй бол даалгаврын шинэ жагсаалт үүсч эхэлнэ.

Тусгай файл болон хүснэгтийн нэр бүхий системийн файлыг ачаалж байна:

/* если файл системной таблицы изменился, перечитываем */
if (syscron_stat.st_mtime) {
    process_crontab("root", "*system*",
    SYSCRONTAB, &syscron_stat,
    &new_db, old_db);
}

Хэрэглэгчийн хүснэгтүүдийг гогцоонд ачаалж байна:

while (NULL != (dp = readdir(dir))) {
    char    fname[MAXNAMLEN+1],
            tabname[MAXNAMLEN+1];
    /* читать файлы с точкой не надо*/
    if (dp->d_name[0] == '.')
            continue;
    (void) strcpy(fname, dp->d_name);
    sprintf(tabname, CRON_TAB(fname));
    process_crontab(fname, fname, tabname,
                    &statbuf, &new_db, old_db);
}

Үүний дараа хуучин мэдээллийн баазыг шинээр солино.

Дээрх жишээнүүдэд process_crontab функцийн дуудлага нь хүснэгтийн файлын нэртэй тохирох хэрэглэгч байгаа эсэхийг (хэрэв энэ нь супер хэрэглэгч биш бол) шалгаж, дараа нь load_user гэж дууддаг. Сүүлийнх нь аль хэдийн файлыг өөрөө мөр мөрөөр уншдаг:

while ((status = load_env(envstr, file)) >= OK) {
    switch (status) {
    case ERR:
        free_user(u);
        u = NULL;
        goto done;
    case FALSE:
        e = load_entry(file, NULL, pw, envp);
        if (e) {
            e->next = u->crontab;
            u->crontab = e;
        }
        break;
    case TRUE:
        envp = env_set(envp, envstr);
        break;
    }
}

Энд load_env / env_set функцуудыг ашиглан орчны хувьсагчийг тохируулсан (VAR=утга хэлбэрийн мөрүүд), эсвэл load_entry функцийг ашиглан даалгаврын тайлбарыг (* * * * * /path/to/exec) уншина.

load_entry-ийг буцаадаг оруулга нь бидний даалгавар бөгөөд үүнийг даалгаврын ерөнхий жагсаалтад байрлуулсан болно. Функц нь өөрөө цаг хугацааны форматыг нарийвчлан задлан шинжилдэг боловч бид орчны хувьсагч болон даалгаврын эхлүүлэх параметрүүдийг бүрдүүлэхийг илүү сонирхож байна.

/* пользователь и группа для запуска задачи берутся из passwd*/
e->uid = pw->pw_uid;
e->gid = pw->pw_gid;

/* шелл по умолчанию (/bin/sh), если пользователь не указал другое */
e->envp = env_copy(envp);
if (!env_get("SHELL", e->envp)) {
    sprintf(envstr, "SHELL=%s", _PATH_BSHELL);
    e->envp = env_set(e->envp, envstr);
}
/* домашняя директория */
if (!env_get("HOME", e->envp)) {
    sprintf(envstr, "HOME=%s", pw->pw_dir);
    e->envp = env_set(e->envp, envstr);
}
/* путь для поиска программ */
if (!env_get("PATH", e->envp)) {
    sprintf(envstr, "PATH=%s", _PATH_DEFPATH);
    e->envp = env_set(e->envp, envstr);
}
/* имя пользовтеля всегда из passwd */
sprintf(envstr, "%s=%s", "LOGNAME", pw->pw_name);
e->envp = env_set(e->envp, envstr);

Үндсэн давталт нь одоо байгаа ажлуудын жагсаалттай ажилладаг.

Үндсэн гогцоо

Хувилбар 7 Unix-ийн анхны cron нь маш энгийнээр ажилласан: энэ нь тохиргоог давталтаар дахин уншиж, одоогийн минутын даалгавруудыг супер хэрэглэгчийн хувьд эхлүүлж, дараагийн минут эхлэх хүртэл унтдаг. Хуучин машин дээрх энэ энгийн арга нь хэтэрхий их нөөц шаарддаг.

SysV-д өөр хувилбарыг санал болгосон бөгөөд үүнд демон нь даалгавар тодорхойлогдсон хамгийн ойрын минут хүртэл эсвэл 30 минутын турш унтдаг байв. Энэ горимд тохиргоог дахин уншиж, даалгавруудыг шалгахад бага нөөц зарцуулсан боловч даалгаврын жагсаалтыг хурдан шинэчлэх нь тохиромжгүй болсон.

Викси крон минут тутамд нэг удаа даалгаврын жагсаалтыг шалгадаг байсан бөгөөд азаар 80-аад оны эцэс гэхэд стандарт Unix машинууд дээр илүү их нөөцтэй болсон:

/* первичная загрузка задач */
load_database(&database);
/* запустить задачи, поставленные к выполнению после перезагрузки системы */
run_reboot_jobs(&database);
/* сделать TargetTime началом ближайшей минуты */
cron_sync();
while (TRUE) {
    /* выполнить задачи, после чего спать до TargetTime с поправкой на время, потраченное на задачи */
    cron_sleep();

    /* перечитать конфигурацию */
    load_database(&database);

    /* собрать задачи для данной минуты */
    cron_tick(&database);

    /* перевести TargetTime на начало следующей минуты */
    TargetTime += 60;
}

cron_sleep функц нь ажил гүйцэтгэхэд шууд оролцдог бөгөөд job_runqueue (даалгавруудыг тоолж, ажиллуулах) болон do_command (даалгавар тус бүрийг ажиллуулах) функцуудыг дууддаг. Сүүлийн функцийг илүү нарийвчлан судлах нь зүйтэй.

Даалгаврыг гүйцэтгэж байна

do_command функцийг Unix-ийн сайн загвараар гүйцэтгэдэг, өөрөөр хэлбэл даалгаврыг асинхроноор гүйцэтгэхийн тулд сэрээ хийдэг. Эцэг эхийн үйл явц нь даалгавруудыг үргэлжлүүлэн ажиллуулж, хүүхдийн процесс нь даалгаврын процессыг бэлтгэдэг:

switch (fork()) {
case -1:
    /*не смогли выполнить fork */
    break;
case 0:
    /* дочерний процесс: на всякий случай еще раз пробуем захватить главный лок */
    acquire_daemonlock(1);
    /* переходим к формированию процесса задачи */
    child_process(e, u);
    /* по завершению дочерний процесс заканчивает работу */
    _exit(OK_EXIT);
    break;
default:
    /* родительский процесс продолжает работу */
    break;
}

Child_process-д маш их логик байдаг: энэ нь стандарт гаралт болон алдааны урсгалыг хүлээн авч, дараа нь шуудан руу илгээдэг (хэрэв MAILTO орчны хувьсагчийг даалгаврын хүснэгтэд заасан бол), эцэст нь даалгаврын үндсэн процессыг хүлээнэ. бүрэн.

Даалгаврын процесс нь өөр сэрээгээр үүсгэгддэг:

switch (vfork()) {
case -1:
    /* при ошибки сразу завершается работа */
    exit(ERROR_EXIT);
case 0:
    /* процесс-внук формирует новую сессию, терминал и т.д.
     */
    (void) setsid();

    /*
     * дальше многословная настройка вывода процесса, опустим для краткости
     */

    /* смена директории, пользователя и группы пользователя,
     * то есть процесс больше не суперпользовательский
     */
    setgid(e->gid);
    setuid(e->uid);
    chdir(env_get("HOME", e->envp));

    /* запуск самой команды
     */
    {
        /* переменная окружения SHELL указывает на интерпретатор для запуска */
        char    *shell = env_get("SHELL", e->envp);

        /* процесс запускается без передачи окружения родительского процесса,
         * то есть именно так, как описано в таблице задач пользователя  */
        execle(shell, shell, "-c", e->cmd, (char *)0, e->envp);

        /* ошибка — и процесс на запустился? завершение работы */
        perror("execl");
        _exit(ERROR_EXIT);
    }
    break;
default:
    /* сам процесс продолжает работу: ждет завершения работы и вывода */
    break;
}

Энэ бол үндсэндээ бүх cron юм. Би зарим сонирхолтой нарийн ширийн зүйлийг орхигдуулсан, жишээлбэл, алсын хэрэглэгчдэд зориулсан нягтлан бодох бүртгэл, гэхдээ би гол зүйлийг тоймлов.

Дараах үгс

Cron бол Unix ертөнцийн шилдэг уламжлалаар хийгдсэн гайхалтай энгийн бөгөөд хэрэгтэй програм юм. Тэр нэмэлт зүйл хийдэггүй ч хэдэн арван жилийн турш ажлаа гайхалтай хийж байна. Ubuntu-д дагалдаж ирдэг хувилбарын кодыг олж авахад нэг цаг гаруй хугацаа зарцуулагдсангүй, би маш их хөгжилтэй байсан! Та бүхэнтэй хуваалцаж чадсан гэж найдаж байна.

Би та нарын тухай мэдэхгүй ч хэт төвөгтэй, хэт хийсвэрлэх хандлагатай орчин үеийн программчлал удаан хугацааны туршид ийм энгийн байдлыг хангахад тус дөхөмгүй байсныг ойлгоход би бага зэрэг гунигтай байна.

Cron-ийн орчин үеийн олон хувилбарууд байдаг: systemd-таймерууд нь хамаарал бүхий цогц системийг зохион байгуулах боломжийг олгодог, fcron нь нөөцийн зарцуулалтыг даалгавараар илүү уян хатан зохицуулах боломжийг олгодог. Гэхдээ хувь хүнийхээ хувьд хамгийн энгийн crontab надад үргэлж хангалттай байсан.

Товчхондоо, Unix-д дуртай, энгийн програмуудыг ашигла, платформдоо зориулж мана уншихаа бүү мартаарай!

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх