Црон у Линуку: историја, употреба и уређај

Црон у Линуку: историја, употреба и уређај

Класик је написао да срећни сати не гледају. У тим дивљим временима није било ни програмера ни Уника, али данас програмери сигурно знају: црон ће уместо њих пратити време.

Услужни програми командне линије су за мене и слабост и напор. сед, авк, вц, цут и други стари програми покрећу скрипте на нашим серверима сваки дан. Многи од њих су дизајнирани као задаци за црон, планер који потиче из 70-их.

Дуго сам користио црон површно, не улазећи у детаље, али једног дана, када сам наишао на грешку при покретању скрипте, одлучио сам да је детаљно испитам. Овако се појавио овај чланак, док сам га писао упознао се са ПОСИКС цронтаб-ом, главним црон опцијама у популарним Линук дистрибуцијама и структуром неких од њих.

Да ли користите Линук и покрећете црон задатке? Да ли сте заинтересовани за архитектуру системских апликација у Унику? Онда смо на путу!

Садржина

Порекло врсте

Периодично извршавање корисничких или системских програма је очигледна неопходност у свим оперативним системима. Стога су програмери одавно схватили потребу за услугама које им омогућавају да централно планирају и извршавају задатке.

Оперативни системи слични Уник-у вуку своје порекло од верзије 7 Уник-а, развијене 70-их година прошлог века у Белл Лабс-у, укључујући и чувени Кен Тхомпсон. Верзија 7 Уник је такође укључивала црон, услугу за редовно извршавање задатака суперкорисника.

Типичан савремени црон је једноставан програм, али је оперативни алгоритам оригиналне верзије био још једноставнији: услуга се будила једном у минуту, читала табелу са задацима из једне датотеке (/етц/либ/цронтаб) и извршавала за суперкорисник они задаци који су требали бити обављени у овом тренутку .

Након тога, побољшане верзије једноставне и корисне услуге испоручене су са свим оперативним системима сличним Уник-у.

Генерализовани описи цронтаб формата и основни принципи рада услужног програма укључени су у главни стандард оперативних система сличних Уник-у – ПОСИКС – 1992. године, и тако је црон из де фацто стандарда постао де јуре стандард.

Године 1987, Паул Викие је, након што је испитао Уник кориснике о њиховим жељама за црон-ом, објавио још једну верзију демона која је исправила неке од проблема традиционалног црон-а и проширила синтаксу датотека табеле.

До треће верзије Викие црон је почео да испуњава ПОСИКС захтеве, поред тога, програм је имао либералну лиценцу, тачније није било никакве лиценце, осим жеље у РЕАДМЕ-у: аутор не даје гаранције, име аутора не може се избрисати, а програм се може продати само заједно са изворним кодом. Показало се да су ови захтеви компатибилни са принципима слободног софтвера који је тих година добијао на популарности, па су неке од кључних Линукс дистрибуција које су се појавиле раних 90-их узеле Викие црон као системски и развијају га и данас.

Конкретно, Ред Хат и СУСЕ развијају форк Викие црон - цроние, а Дебиан и Убунту користе оригинално издање Викие црон са много закрпа.

Хајде да се прво упознамо са корисничким услужним програмом цронтаб описаним у ПОСИКС-у, након чега ћемо погледати проширења синтаксе обезбеђена у Викие црон-у и употребу варијација Викие црон-а у популарним дистрибуцијама Линук-а. И на крају, трешња на торти је анализа црон даемон уређаја.

ПОСИКС цронтаб

Ако је оригинални црон увек радио за суперкорисника, савремени планери се често баве задацима обичних корисника, што је сигурније и погодније.

Цронс се испоручују као скуп од два програма: стално покренути црон демон и цронтаб услужни програм који је доступан корисницима. Ово последње вам омогућава да уређујете табеле задатака специфичне за сваког корисника у систему, док демон покреће задатке из корисничких и системских табела.

В ПОСИКС стандард понашање демона није описано ни на који начин и само је кориснички програм формализован цорнтаб. Постојање механизама за покретање корисничких задатака се, наравно, подразумева, али није детаљно описано.

Позивањем услужног програма цронтаб можете урадити четири ствари: уредити табелу задатака корисника у уређивачу, учитати табелу из датотеке, приказати тренутну табелу задатака и обрисати табелу задатака. Примери како функционише услужни програм цронтаб:

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

Приступ корисника планирању задатака је у ПОСИКС-у регулисан датотекама црон.аллов и црон.дени, које наводе кориснике са приступом цронтаб-у и кориснике који немају приступ програму, респективно. Стандард ни на који начин не регулише локацију ових датотека.

Према стандарду, најмање четири променљиве окружења морају бити прослеђене покренутим програмима:

  1. ХОМЕ - почетни именик корисника.
  2. ЛОГНАМЕ — пријављивање корисника.
  3. ПАТХ је путања на којој можете пронаћи стандардне системске услужне програме.
  4. СХЕЛЛ — путања до коришћеног тумача команди.

Посебно, ПОСИКС не говори ништа о томе одакле потичу вредности за ове варијабле.

Најбољи продавац - Викие црон 3.0пл1

Заједнички предак популарних црон варијанти је Викие црон 3.0пл1, уведен на цомп.соурцес.уник маилинг листу 1992. године. Размотрићемо главне карактеристике ове верзије детаљније.

Викие црон долази у два програма (црон и цронтаб). Као и обично, демон је одговоран за читање и покретање задатака из табеле системских задатака и појединачних корисничких табела задатака, а услужни програм цронтаб је одговоран за уређивање корисничких табела.

Табела задатака и конфигурационе датотеке

Табела задатака суперкорисника се налази у /етц/цронтаб. Синтакса системске табеле одговара синтакси Викие црон-а, с тим што шеста колона у њој означава име корисника у чије име је задатак покренут:

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

Табеле редовних корисничких задатака налазе се у /вар/црон/табс/усернаме и користе исту синтаксу. Када покренете услужни програм цронтаб као корисник, ово су датотеке које се уређују.

Листама корисника са приступом цронтаб-у се управља у датотекама /вар/црон/аллов и /вар/црон/дени, где само треба да унесете корисничко име у посебан ред.

Проширена синтакса

У поређењу са ПОСИКС цронтаб-ом, решење Пола Виксија садржи неколико веома корисних модификација синтаксе табела задатака услужног програма.

Нова синтакса табеле је постала доступна: на пример, можете да наведете дане у недељи или месеце по имену (пон, уто и тако даље):

# Запускается ежеминутно по понедельникам и вторникам в январе
* * * 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

Окружење за извршавање задатака

Викие црон вам омогућава да промените окружење покренутих апликација.

Променљиве окружења УСЕР, ЛОГНАМЕ и ХОМЕ нису једноставно обезбеђене од стране демона, већ су преузете из датотеке пассвд. Променљива ПАТХ је постављена на "/уср/бин:/бин", а променљива СХЕЛЛ је постављена на "/бин/сх". Вредности свих променљивих осим ЛОГНАМЕ могу се променити у корисничким табелама.

Неке варијабле окружења (нарочито СХЕЛЛ и ХОМЕ) користи сам црон за покретање задатка. Ево како би коришћење басх уместо стандардног сх за покретање прилагођених задатака могло изгледати:

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

На крају, све променљиве окружења дефинисане у табели (које користи црон или су потребне процесу) биће прослеђене задатку који се извршава.

За уређивање датотека, цронтаб користи уређивач наведен у променљивој окружења ВИСУАЛ или ЕДИТОР. Ако окружење у којем је покренут цронтаб нема дефинисане ове варијабле, онда се користи „/уср/уцб/ви“ (уцб је вероватно Универзитет Калифорније, Беркли).

црон на Дебиан и Убунту

Програмери Дебиан-а и изведених дистрибуција су објавили високо модификована верзија Викие црон верзија 3.0пл1. Не постоје разлике у синтакси табела, за кориснике је исти Викие црон. Највећа нова карактеристика: Подршка сислог, СЕЛинук и Пам.

Мање приметне, али опипљиве промене укључују локацију конфигурационих датотека и табела задатака.

Корисничке табеле у Дебиану се налазе у директоријуму /вар/споол/црон/цронтабс, системска табела је још увек тамо - у /етц/цронтаб. Табеле задатака специфичне за Дебиан пакет су смештене у /етц/црон.д, одакле их црон демон аутоматски чита. Контролу приступа корисника контролишу датотеке /етц/црон.аллов и /етц/црон.дени.

Подразумевана љуска је и даље /бин/сх, која је у Дебиану мала љуска компатибилна са ПОСИКС-ом повлака, покренут без читања било какве конфигурације (у неинтерактивном режиму).

Сам Црон у најновијим верзијама Дебиана се покреће преко системд-а, а конфигурација покретања се може видети у /либ/системд/систем/црон.сервице. Нема ничег посебног у конфигурацији услуге; било какво суптилније управљање задацима може се обавити преко променљивих окружења декларисаних директно у цронтаб-у сваког корисника.

цроние на РедХат, Федора и ЦентОС

цроние — форк Викие црон верзије 4.1. Као иу Дебиан-у, синтакса се није променила, али је додата подршка за ПАМ и СЕЛинук, рад у кластеру, праћење датотека помоћу инотифи и друге функције.

Подразумевана конфигурација је на уобичајеним местима: системска табела је у /етц/цронтаб, пакети стављају своје табеле у /етц/црон.д, корисничке табеле иду у /вар/споол/црон/цронтабс.

Даемон ради под системском контролом, конфигурација услуге је /либ/системд/систем/цронд.сервице.

У дистрибуцијама сличним Ред Хату, /бин/сх се подразумевано користи при покретању, што је стандардни басх. Треба напоменути да када се извршавају црон послови преко /бин/сх, басх схелл почиње у ПОСИКС-компатибилном режиму и не чита никакву додатну конфигурацију, ради у неинтерактивном режиму.

цроние у СЛЕС и опенСУСЕ

Немачка дистрибуција СЛЕС и њен дериват опенСУСЕ користе истог пријатеља. Демон се овде такође покреће под системд, конфигурација услуге се налази у /уср/либ/системд/систем/црон.сервице. Конфигурација: /етц/цронтаб, /етц/црон.д, /вар/споол/црон/табс. /бин/сх је исти басх који ради у ПОСИКС-компатибилном неинтерактивном режиму.

Викие црон уређај

Савремени потомци црона нису се радикално променили у поређењу са Викие црон-ом, али су ипак стекли нове карактеристике које нису потребне за разумевање принципа програма. Многа од ових проширења су лоше дизајнирана и збуњују код. Оригинални црон изворни код Паула Викеиа је задовољство читати.

Због тога сам одлучио да анализирам црон уређај на примеру црон програма заједничког за обе гране развоја - Викие црон 3.0пл1. Поједноставићу примере тако што ћу уклонити ифдеф-ове који компликују читање и изоставити мање детаље.

Рад демона се може поделити у неколико фаза:

  1. Иницијализација програма.
  2. Прикупљање и ажурирање листе задатака за покретање.
  3. Покреће се главна црон петља.
  4. Започните задатак.

Погледајмо их редом.

Иницијализација

Када се покрене, након провере аргумената процеса, црон инсталира СИГЦХЛД и СИГХУП обрађиваче сигнала. Први прави унос у дневник о прекиду подређеног процеса, други затвара дескриптор датотеке евиденције:

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

Црон даемон увек ради сам на систему, само као суперкорисник и из главног црон директоријума. Следећи позиви креирају датотеку закључавања са ПИД-ом демонског процеса, уверите се да је корисник исправан и промените тренутни директоријум у главни:

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

Подешена је подразумевана путања која ће се користити приликом покретања процеса:

setenv("PATH", _PATH_DEFPATH, 1);

Тада се процес „демонизује“: креира подређену копију процеса позивањем форк-а и нове сесије у подређеном процесу (позивањем сетсид-а). Надређени процес више није потребан и излази:

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

Завршетак надређеног процеса ослобађа закључавање датотеке закључавања. Поред тога, потребно је ажурирати ПИД у датотеци детету. Након тога попуњава се база података задатака:

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

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

Затим црон прелази на главни циклус рада. Али пре тога, вреди погледати учитавање листе задатака.

Прикупљање и ажурирање листе задатака

Функција лоад_датабасе је одговорна за учитавање листе задатака. Проверава главни системски цронтаб и директоријум са корисничким датотекама. Ако се датотеке и директоријум нису променили, листа задатака се не чита поново. У супротном, почиње да се формира нова листа задатака.

Учитавање системске датотеке са посебним именима датотека и табела:

/* если файл системной таблицы изменился, перечитываем */
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);
}

Након тога се стара база података замењује новом.

У горњим примерима, позив функције процесс_цронтаб потврђује да постоји корисник који одговара имену датотеке табеле (осим ако није суперкорисник), а затим позива лоад_усер. Овај други већ чита саму датотеку ред по ред:

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

Овде се или поставља променљива окружења (линије облика ВАР=вредност) коришћењем функција лоад_енв / енв_сет, или се чита опис задатка (* * * * * /патх/то/екец) помоћу функције лоад_ентри.

Ентитет уноса који лоад_ентри враћа је наш задатак, који се налази у општој листи задатака. Сама функција врши опширно рашчлањивање формата времена, али нас више занима формирање променљивих окружења и параметара покретања задатка:

/* пользователь и группа для запуска задачи берутся из 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 Уник-а је радио прилично једноставно: поново је прочитао конфигурацију у петљи, покренуо задатке текућег минута као суперкорисник и спавао до почетка следећег минута. Овај једноставан приступ на старијим машинама захтевао је превише ресурса.

У СисВ-у је предложена алтернативна верзија, у којој је демон спавао или до најближег минута за који је задатак дефинисан, или 30 минута. Мање ресурса је потрошено за поновно читање конфигурације и проверу задатака у овом режиму, али је брзо ажурирање листе задатака постало незгодно.

Викие црон се вратио на проверу листе задатака једном у минуту, на срећу до краја 80-их било је знатно више ресурса на стандардним Уник машинама:

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

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

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

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

Функција црон_слееп је директно укључена у извршавање задатака, позивајући функције јоб_рункуеуе (наброј и покрени задатке) и до_цомманд (покрени сваки појединачни задатак). Последњу функцију вреди детаљније испитати.

Покретање задатка

Функција до_цомманд се извршава у добром Уник стилу, то јест, врши виљушку да изврши задатак асинхроно. Надређени процес наставља са покретањем задатака, подређени процес припрема процес задатка:

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

Постоји доста логике у цхилд_процесс: прихвата стандардни излаз и токове грешака, затим их шаље на пошту (ако је променљива окружења МАИЛТО наведена у табели задатака) и, коначно, чека да се главни процес задатка комплетан.

Процес задатка је формиран другом виљушком:

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

То је у основи све што је црон. Изоставио сам неке занимљиве детаље, на пример, обрачун за удаљене кориснике, али сам изнео оно главно.

Афтерворд

Црон је изненађујуће једноставан и користан програм, направљен у најбољим традицијама Уник света. Не ради ништа додатно, али већ неколико деценија одлично ради свој посао. Пролажење кода за верзију која долази са Убунтуом није трајало више од сат времена и било ми је јако забавно! Надам се да сам успео да то поделим са вама.

Не знам за вас, али ја сам помало тужан што схватам да модерно програмирање, са својом тенденцијом да се прекомпликује и преапстрактно, већ дуго није погодовало таквој једноставности.

Постоје многе модерне алтернативе за црон: системски тајмери ​​вам омогућавају да организујете сложене системе са зависностима, фцрон вам омогућава да флексибилније регулишете потрошњу ресурса према задацима. Али лично, најједноставнији цронтаб ми је увек био довољан.

Укратко, волите Уник, користите једноставне програме и не заборавите да прочитате ману за своју платформу!

Извор: ввв.хабр.цом

Додај коментар