Cron sa Linux: kasaysayan, paggamit at device

Cron sa Linux: kasaysayan, paggamit at device

Isinulat ng klasiko na ang mga masayang oras ay hindi nanonood. Noong mga panahong iyon ay walang mga programmer o Unix, ngunit ngayon ay alam na ng mga programmer: ang cron ay susubaybayan ang oras sa halip na sila.

Ang mga utility sa command line ay parehong kahinaan at isang gawaing-bahay para sa akin. Ang sed, awk, wc, cut at iba pang mga lumang programa ay pinapatakbo ng mga script sa aming mga server araw-araw. Marami sa mga ito ay idinisenyo bilang mga gawain para sa cron, isang scheduler na orihinal noong 70s.

Sa loob ng mahabang panahon ay ginamit ko ang cron nang mababaw, nang hindi naglalagay ng mga detalye, ngunit isang araw, nang makatagpo ako ng isang error sa pagpapatakbo ng isang script, nagpasya akong suriin ito nang maigi. Ganito lumabas ang artikulong ito, habang isinusulat ito ay naging pamilyar ako sa POSIX crontab, ang mga pangunahing opsyon ng cron sa mga sikat na pamamahagi ng Linux at ang istraktura ng ilan sa mga ito.

Gumagamit ka ba ng Linux at nagpapatakbo ng mga gawain sa cron? Interesado ka ba sa arkitektura ng system application sa Unix? Tapos papunta na kami!

nilalaman

Pinagmulan ng mga species

Ang pana-panahong pagpapatupad ng mga programa ng user o system ay isang malinaw na pangangailangan sa lahat ng mga operating system. Samakatuwid, napagtanto ng mga programmer ang pangangailangan para sa mga serbisyong nagbibigay-daan sa kanila na magplano at magsagawa ng mga gawain sa gitna ng mahabang panahon.

Sinusubaybayan ng mga operating system na katulad ng Unix ang kanilang mga pinagmulan pabalik sa Bersyon 7 Unix, na binuo noong 70s ng huling siglo sa Bell Labs, kasama ang sikat na Ken Thompson. Kasama rin sa Bersyon 7 Unix ang cron, isang serbisyo para sa regular na pagpapatakbo ng mga gawain ng superuser.

Ang isang tipikal na modernong cron ay isang simpleng programa, ngunit ang operating algorithm ng orihinal na bersyon ay mas simple: ang serbisyo ay nagising isang beses sa isang minuto, nagbasa ng isang talahanayan na may mga gawain mula sa isang file (/etc/lib/crontab) at gumanap para sa superuser ang mga gawain na dapat ay ginanap sa kasalukuyang sandali.

Kasunod nito, ang mga pinahusay na bersyon ng simple at kapaki-pakinabang na serbisyo ay ibinigay kasama ng lahat ng mga operating system na katulad ng Unix.

Ang mga pangkalahatang paglalarawan ng format ng crontab at ang mga pangunahing prinsipyo ng pagpapatakbo ng utility ay kasama sa pangunahing pamantayan ng mga operating system na katulad ng Unix - POSIX - noong 1992, at sa gayon ang cron mula sa isang de facto na pamantayan ay naging isang de jure na pamantayan.

Noong 1987, si Paul Vixie, na nag-survey sa mga user ng Unix tungkol sa kanilang mga kagustuhan para sa cron, ay naglabas ng isa pang bersyon ng daemon na nagwasto ng ilan sa mga problema ng tradisyonal na cron at nagpalawak ng syntax ng mga file ng talahanayan.

Sa ikatlong bersyon ng Vixie cron ay nagsimulang matugunan ang mga kinakailangan ng POSIX, bilang karagdagan, ang programa ay may liberal na lisensya, o sa halip ay walang lisensya, maliban sa mga kagustuhan sa README: ang may-akda ay hindi nagbibigay ng mga garantiya, ang pangalan ng may-akda ay hindi matatanggal, at ang programa ay maaari lamang ibenta kasama ng source code. Ang mga kinakailangang ito ay naging tugma sa mga prinsipyo ng libreng software na nagiging popular sa mga taong iyon, kaya ang ilan sa mga pangunahing distribusyon ng Linux na lumitaw noong unang bahagi ng 90s ay kinuha ang Vixie cron bilang kanilang system at patuloy pa rin itong ginagawa ngayon.

Sa partikular, ang Red Hat at SUSE ay bumuo ng isang tinidor ng Vixie cron - cronie, at ginagamit ni Debian at Ubuntu ang orihinal na edisyon ng Vixie cron na may maraming patch.

Kilalanin muna natin ang user utility crontab na inilarawan sa POSIX, pagkatapos nito ay titingnan natin ang mga extension ng syntax na ibinigay sa Vixie cron at ang paggamit ng mga variation ng Vixie cron sa mga sikat na distribusyon ng Linux. At sa wakas, ang cherry sa cake ay ang pagsusuri ng cron daemon device.

POSIX crontab

Kung ang orihinal na cron ay palaging gumagana para sa superuser, ang mga modernong scheduler ay madalas na humaharap sa mga gawain ng mga ordinaryong user, na mas ligtas at maginhawa.

Ang mga crons ay ibinibigay bilang isang set ng dalawang programa: ang patuloy na tumatakbong cron daemon at ang crontab utility na magagamit sa mga user. Ang huli ay nagpapahintulot sa iyo na i-edit ang mga talahanayan ng gawain na partikular sa bawat user sa system, habang ang daemon ay naglulunsad ng mga gawain mula sa mga talahanayan ng user at system.

В Pamantayan ng POSIX ang pag-uugali ng daemon ay hindi inilarawan sa anumang paraan at tanging ang programa ng gumagamit ay pormal crontab. Ang pagkakaroon ng mga mekanismo para sa paglulunsad ng mga gawain ng gumagamit ay, siyempre, ipinahiwatig, ngunit hindi inilarawan nang detalyado.

Sa pamamagitan ng pagtawag sa crontab utility, magagawa mo ang apat na bagay: i-edit ang task table ng user sa editor, i-load ang table mula sa isang file, ipakita ang kasalukuyang task table, at i-clear ang task table. Mga halimbawa ng kung paano gumagana ang crontab utility:

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

Kapag tumatawag crontab -e gagamitin ang editor na tinukoy sa karaniwang variable ng kapaligiran EDITOR.

Ang mga gawain mismo ay inilarawan sa sumusunod na format:

# строки-комментарии игнорируются
#
# задача, выполняемая ежеминутно
* * * * * /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

Ang unang limang field ng mga talaan: minuto [1..60], oras [0..23], araw ng buwan [1..31], buwan [1..12], araw ng linggo [0. .6], kung saan ang 0 ay Linggo. Ang huli, ikaanim, na field ay isang linya na isasagawa ng karaniwang command interpreter.

Sa unang limang field, maaaring ilista ang mga value na pinaghihiwalay ng mga kuwit:

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

O may gitling:

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

Ang access ng user sa pag-iiskedyul ng gawain ay kinokontrol sa POSIX ng cron.allow at cron.deny file, na naglilista ng mga user na may access sa crontab at mga user na walang access sa program, ayon sa pagkakabanggit. Hindi kinokontrol ng pamantayan ang lokasyon ng mga file na ito sa anumang paraan.

Ayon sa pamantayan, hindi bababa sa apat na variable ng kapaligiran ang dapat ipasa sa mga inilunsad na programa:

  1. HOME - home directory ng user.
  2. LOGNAME — login ng user.
  3. Ang PATH ay ang landas kung saan makakahanap ka ng mga karaniwang kagamitan ng system.
  4. SHELL — landas patungo sa ginamit na command interpreter.

Kapansin-pansin, walang sinasabi ang POSIX tungkol sa kung saan nagmula ang mga halaga para sa mga variable na ito.

Pinakamabenta - Vixie cron 3.0pl1

Ang karaniwang ninuno ng mga sikat na variant ng cron ay ang Vixie cron 3.0pl1, na ipinakilala sa mailing list ng comp.sources.unix noong 1992. Isasaalang-alang namin ang mga pangunahing tampok ng bersyon na ito nang mas detalyado.

Ang Vixie cron ay may dalawang programa (cron at crontab). Gaya ng dati, ang daemon ay may pananagutan sa pagbabasa at pagpapatakbo ng mga gawain mula sa talahanayan ng gawain ng system at mga talahanayan ng gawain ng indibidwal na user, at ang crontab utility ay responsable para sa pag-edit ng mga talahanayan ng user.

Talahanayan ng gawain at mga file ng pagsasaayos

Ang talahanayan ng gawain ng superuser ay matatagpuan sa /etc/crontab. Ang syntax ng system table ay tumutugma sa syntax ng Vixie cron, maliban na ang ikaanim na column dito ay nagpapahiwatig ng pangalan ng user kung saan inilunsad ang gawain:

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

Ang mga regular na talahanayan ng gawain ng user ay matatagpuan sa /var/cron/tabs/username at gumagamit ng parehong syntax. Kapag pinatakbo mo ang crontab utility bilang isang user, ito ang mga file na na-edit.

Ang mga listahan ng mga user na may access sa crontab ay pinamamahalaan sa /var/cron/allow at /var/cron/deny file, kung saan kailangan mo lang ilagay ang user name sa isang hiwalay na linya.

Pinalawak na syntax

Kung ikukumpara sa POSIX crontab, ang solusyon ni Paul Vixey ay naglalaman ng ilang napakakapaki-pakinabang na mga pagbabago sa syntax ng mga talahanayan ng gawain ng utility.

Naging available ang isang bagong syntax ng talahanayan: halimbawa, maaari mong tukuyin ang mga araw ng linggo o mga buwan ayon sa pangalan (Lun, Mar, at iba pa):

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

Maaari mong tukuyin ang hakbang kung saan inilulunsad ang mga gawain:

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

Maaaring ihalo ang mga hakbang at pagitan:

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

Ang mga intuitive na alternatibo sa karaniwang syntax ay sinusuportahan (reboot, taun-taon, taun-taon, buwanan, lingguhan, araw-araw, hatinggabi, oras-oras):

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

Kapaligiran ng pagpapatupad ng gawain

Binibigyang-daan ka ng Vixie cron na baguhin ang kapaligiran ng mga tumatakbong application.

Ang mga variable ng kapaligiran na USER, LOGNAME at HOME ay hindi lamang ibinigay ng daemon, ngunit kinuha mula sa isang file passwd. Ang PATH variable ay nakatakda sa "/usr/bin:/bin" at ang SHELL variable ay nakatakda sa "/bin/sh". Ang mga halaga ng lahat ng mga variable maliban sa LOGNAME ay maaaring baguhin sa mga talahanayan ng gumagamit.

Ang ilang mga variable ng kapaligiran (lalo na ang SHELL at HOME) ay ginagamit ng cron mismo upang patakbuhin ang gawain. Narito kung ano ang maaaring maging hitsura ng paggamit ng bash sa halip na karaniwang sh upang magpatakbo ng mga custom na gawain:

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

Sa huli, ang lahat ng mga variable ng kapaligiran na tinukoy sa talahanayan (ginagamit ng cron o kinakailangan ng proseso) ay ipapasa sa tumatakbong gawain.

Para mag-edit ng mga file, ginagamit ng crontab ang editor na tinukoy sa VISUAL o EDITOR environment variable. Kung ang kapaligiran kung saan pinapatakbo ang crontab ay walang tinukoy na mga variable, kung gayon ang "/usr/ucb/vi" ay ginagamit (ang ucb ay malamang na ang Unibersidad ng California, Berkeley).

cron sa Debian at Ubuntu

Inilabas na ang mga developer ng Debian at derivative distribution lubos na binagong bersyon Vixie cron bersyon 3.0pl1. Walang mga pagkakaiba sa syntax ng mga file ng talahanayan; para sa mga gumagamit ito ay ang parehong Vixie cron. Pinakamalaking Bagong Tampok: Suporta syslog, SELinux и WFP.

Hindi gaanong kapansin-pansin, ngunit ang mga nasasalat na pagbabago ay kinabibilangan ng lokasyon ng mga file ng pagsasaayos at mga talahanayan ng gawain.

Ang mga talahanayan ng gumagamit sa Debian ay matatagpuan sa direktoryo ng /var/spool/cron/crontabs, nandoon pa rin ang talahanayan ng system - sa /etc/crontab. Ang mga talahanayan ng gawain na partikular sa package ng Debian ay inilalagay sa /etc/cron.d, kung saan awtomatikong binabasa ng cron daemon ang mga ito. Ang kontrol sa pag-access ng user ay kinokontrol ng mga file na /etc/cron.allow at /etc/cron.deny.

Ang default na shell ay pa rin /bin/sh, na sa Debian ay isang maliit na POSIX-compliant na shell pagsugod, inilunsad nang hindi nagbabasa ng anumang configuration (sa non-interactive na mode).

Ang Cron mismo sa mga pinakabagong bersyon ng Debian ay inilunsad sa pamamagitan ng systemd, at ang configuration ng paglulunsad ay maaaring tingnan sa /lib/systemd/system/cron.service. Walang espesyal sa configuration ng serbisyo; anumang mas banayad na pamamahala ng gawain ay maaaring gawin sa pamamagitan ng mga variable ng kapaligiran na direktang ipinahayag sa crontab ng bawat user.

cronie sa RedHat, Fedora at CentOS

cronie — tinidor ng Vixie cron bersyon 4.1. Tulad ng sa Debian, ang syntax ay hindi nagbago, ngunit ang suporta para sa PAM at SELinux, nagtatrabaho sa isang kumpol, pagsubaybay sa mga file gamit ang inotify at iba pang mga tampok ay naidagdag.

Ang default na configuration ay nasa karaniwang mga lugar: ang system table ay nasa /etc/crontab, ang mga package ay naglalagay ng kanilang mga table sa /etc/cron.d, ang mga user table ay pumapasok sa /var/spool/cron/crontabs.

Ang daemon ay tumatakbo sa ilalim ng systemd control, ang service configuration ay /lib/systemd/system/crond.service.

Sa mga distribusyon na tulad ng Red Hat, ang /bin/sh ay ginagamit bilang default sa startup, na siyang karaniwang bash. Dapat tandaan na kapag nagpapatakbo ng mga cron job sa pamamagitan ng /bin/sh, magsisimula ang bash shell sa POSIX-compliant mode at hindi nagbabasa ng anumang karagdagang configuration, na tumatakbo sa non-interactive na mode.

cronie sa SLES at openSUSE

Ang German distribution na SLES at ang derivative nitong openSUSE ay gumagamit ng parehong cronie. Ang daemon dito ay inilunsad din sa ilalim ng systemd, ang configuration ng serbisyo ay matatagpuan sa /usr/lib/systemd/system/cron.service. Configuration: /etc/crontab, /etc/cron.d, /var/spool/cron/tabs. Ang /bin/sh ay ang parehong bash na tumatakbo sa POSIX-compliant non-interactive mode.

Vixie cron device

Ang mga modernong inapo ng cron ay hindi nagbago nang malaki kumpara sa Vixie cron, ngunit nakakuha pa rin ng mga bagong tampok na hindi kinakailangan upang maunawaan ang mga prinsipyo ng programa. Marami sa mga extension na ito ay hindi maganda ang disenyo at nalilito ang code. Ang orihinal na cron source code ni Paul Vixey ay nakakatuwang basahin.

Samakatuwid, nagpasya akong suriin ang cron device gamit ang halimbawa ng isang cron program na karaniwan sa parehong sangay ng development - Vixie cron 3.0pl1. Sisimplehin ko ang mga halimbawa sa pamamagitan ng pag-alis ng mga ifdef na nagpapalubha sa pagbabasa at pag-aalis ng mga maliliit na detalye.

Ang gawain ng demonyo ay maaaring nahahati sa maraming yugto:

  1. Pagsisimula ng programa.
  2. Pagkolekta at pag-update ng listahan ng mga gawain na tatakbo.
  3. Ang pangunahing cron loop ay tumatakbo.
  4. Magsimula ng isang gawain.

Tingnan natin ang mga ito sa pagkakasunud-sunod.

Pagsisimula

Kapag nagsimula, pagkatapos suriin ang mga argumento ng proseso, ini-install ng cron ang SIGCHLD at SIGHUP signal handler. Ang una ay gumagawa ng isang log entry tungkol sa pagwawakas ng proseso ng bata, ang pangalawa ay nagsasara ng file descriptor ng log file:

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

Ang cron daemon ay palaging tumatakbo nang mag-isa sa system, bilang isang superuser lamang at mula sa pangunahing direktoryo ng cron. Lumilikha ang mga sumusunod na tawag ng lock file na may PID ng proseso ng daemon, tiyaking tama ang user at baguhin ang kasalukuyang direktoryo sa pangunahing direktoryo:

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

Nakatakda ang default na landas, na gagamitin kapag nagsisimula ng mga proseso:

setenv("PATH", _PATH_DEFPATH, 1);

Pagkatapos ang proseso ay "na-demonize": lumilikha ito ng isang kopya ng bata ng proseso sa pamamagitan ng pagtawag sa tinidor at isang bagong session sa proseso ng bata (pagtawag ng setsid). Hindi na kailangan ang proseso ng magulang, at lalabas ito:

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

Ang pagwawakas ng proseso ng magulang ay naglalabas ng lock sa lock file. Bilang karagdagan, kinakailangan na i-update ang PID sa file sa bata. Pagkatapos nito, ang database ng gawain ay napunan sa:

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

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

Pagkatapos ay lumipat ang cron sa pangunahing ikot ng trabaho. Ngunit bago iyon, sulit na tingnan ang paglo-load ng listahan ng gawain.

Pagkolekta at pag-update ng listahan ng gawain

Ang function ng load_database ay responsable para sa pag-load ng listahan ng mga gawain. Sinusuri nito ang pangunahing system crontab at ang direktoryo na may mga file ng user. Kung ang mga file at direktoryo ay hindi nagbago, ang listahan ng gawain ay hindi muling binabasa. Kung hindi, magsisimulang mabuo ang isang bagong listahan ng mga gawain.

Naglo-load ng system file na may mga espesyal na pangalan ng file at talahanayan:

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

Nilo-load ang mga talahanayan ng user sa isang loop:

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);
}

Pagkatapos nito, ang lumang database ay pinalitan ng bago.

Sa mga halimbawa sa itaas, ang process_crontab function call ay nagpapatunay na ang isang user na tumutugma sa pangalan ng table file ay umiiral (maliban kung ito ay isang superuser) at pagkatapos ay tumatawag sa load_user. Binabasa na ng huli ang file mismo ng linya sa linya:

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;
    }
}

Dito, itinakda ang variable ng kapaligiran (mga linya ng form na VAR=value) gamit ang mga function ng load_env / env_set, o binabasa ang paglalarawan ng gawain (* * * * * /path/to/exec) gamit ang function na load_entry.

Ang entry entity na ibinabalik ng load_entry ay ang aming gawain, na inilalagay sa pangkalahatang listahan ng mga gawain. Ang mismong function ay nagsasagawa ng verbose parsing ng format ng oras, ngunit mas interesado kami sa pagbuo ng mga variable ng kapaligiran at mga parameter ng paglulunsad ng gawain:

/* пользователь и группа для запуска задачи берутся из 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);

Gumagana ang pangunahing loop sa kasalukuyang listahan ng mga gawain.

Pangunahing Loop

Ang orihinal na cron mula sa Bersyon 7 Unix ay gumana nang simple: binabasa nitong muli ang pagsasaayos sa isang loop, inilunsad ang mga gawain ng kasalukuyang minuto bilang isang superuser, at natulog hanggang sa simula ng susunod na minuto. Ang simpleng diskarte na ito sa mas lumang mga makina ay nangangailangan ng napakaraming mapagkukunan.

Isang alternatibong bersyon ang iminungkahi sa SysV, kung saan natulog ang daemon hanggang sa pinakamalapit na minuto kung saan tinukoy ang gawain, o sa loob ng 30 minuto. Mas kaunting mga mapagkukunan ang nagamit para sa muling pagbabasa ng pagsasaayos at pagsuri sa mga gawain sa mode na ito, ngunit ang mabilis na pag-update ng listahan ng mga gawain ay naging hindi maginhawa.

Bumalik si Vixie cron sa pagsuri sa mga listahan ng gawain isang beses sa isang minuto, sa kabutihang palad sa pagtatapos ng dekada 80 ay may mas maraming mapagkukunan sa mga karaniwang Unix machine:

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

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

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

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

Direktang kasangkot ang cron_sleep function sa pagsasagawa ng mga gawain, pagtawag sa job_runqueue (bilangin at patakbuhin ang mga gawain) at do_command (patakbuhin ang bawat indibidwal na gawain). Ang huling function ay nagkakahalaga ng pagsusuri nang mas detalyado.

Pagpapatakbo ng isang gawain

Ang do_command function ay pinaandar sa magandang Unix style, iyon ay, ito ay gumagawa ng isang tinidor upang maisagawa ang gawain nang asynchronous. Ang proseso ng magulang ay patuloy na naglulunsad ng mga gawain, inihahanda ng proseso ng bata ang proseso ng gawain:

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

Napakaraming lohika sa child_process: nangangailangan ito ng karaniwang output at mga stream ng error sa sarili nito, upang maipadala ito sa mail (kung ang variable ng kapaligiran ng MAILTO ay tinukoy sa talahanayan ng gawain), at, sa wakas, naghihintay para sa pangunahing proseso ng gawain upang makumpleto.

Ang proseso ng gawain ay nabuo ng isa pang tinidor:

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;
}

Iyon lang talaga ang cron. Inalis ko ang ilang mga kagiliw-giliw na detalye, halimbawa, accounting para sa mga malalayong gumagamit, ngunit binalangkas ko ang pangunahing bagay.

afterword

Ang Cron ay isang nakakagulat na simple at kapaki-pakinabang na programa, na ginawa sa pinakamahusay na mga tradisyon ng Unix world. Wala siyang ginagawang dagdag, ngunit napakaganda niyang ginagawa ang kanyang trabaho sa loob ng ilang dekada na ngayon. Hindi hihigit sa isang oras ang pagkuha sa code para sa bersyon na kasama ng Ubuntu, at sobrang saya ko! Sana ay naibahagi ko ito sa inyo.

Hindi ko alam ang tungkol sa iyo, ngunit medyo nalulungkot akong napagtanto na ang modernong programming, na may tendensiyang labis na kumplikado at labis na abstract, ay hindi nakakatulong sa gayong pagiging simple sa mahabang panahon.

Mayroong maraming mga modernong alternatibo sa cron: systemd-timer ay nagbibigay-daan sa iyo upang ayusin ang mga kumplikadong sistema na may mga dependency, ang fcron ay nagbibigay-daan sa iyo upang mas flexible na ayusin ang pagkonsumo ng mapagkukunan sa pamamagitan ng mga gawain. Ngunit sa personal, ang pinakasimpleng crontab ay palaging sapat para sa akin.

Sa madaling salita, mahalin ang Unix, gumamit ng mga simpleng programa at huwag kalimutang basahin ang mana para sa iyong platform!

Pinagmulan: www.habr.com

Magdagdag ng komento