Cron ing Linux: riwayat, panggunaan lan piranti

Cron ing Linux: riwayat, panggunaan lan piranti

Klasik nulis yen jam seneng ora nonton. Ing jaman sing liar ora ana programer utawa Unix, nanging saiki programer ngerti: cron bakal nglacak wektu tinimbang dheweke.

Utilitas baris perintah minangka kekirangan lan tugas kanggo aku. sed, awk, wc, cut lan program lawas liyane sing mbukak dening script ing server kita saben dina. Akeh sing dirancang minangka tugas kanggo cron, panjadwal asli saka 70s.

Kanggo dangu aku nggunakake cron superficially, tanpa arep menyang rincian, nanging ing sawijining dina, nalika aku nemoni kesalahan nalika mbukak script, aku mutusaké kanggo nliti iku sak tenane. Mangkene carane artikel iki muncul, nalika nulis aku dadi akrab karo POSIX crontab, pilihan cron utama ing distribusi Linux populer lan struktur sawetara.

Apa sampeyan nggunakake Linux lan nindakake tugas cron? Apa sampeyan kepengin weruh arsitektur aplikasi sistem ing Unix? Banjur kita lagi ing dalan!

Isi

Asal usul spesies

Eksekusi periodik program pangguna utawa sistem minangka kabutuhan sing jelas ing kabeh sistem operasi. Mulane, programer nyadari kebutuhan kanggo layanan sing ngidini dheweke ngrancang lan nglakokake tugas kanthi cepet.

Sistem operasi kaya Unix nglacak asal-usule menyang Versi 7 Unix, sing dikembangake ing taun 70-an ing abad pungkasan ing Bell Labs, kalebu Ken Thompson sing misuwur. Versi 7 Unix uga kalebu cron, layanan kanggo rutin mbukak tugas superuser.

Cron modern sing khas minangka program sing prasaja, nanging algoritma operasi versi asli luwih gampang: layanan tangi sapisan menit, maca tabel kanthi tugas saka file siji (/etc/lib/crontab) lan dileksanakake kanggo superuser tugas sing kudu ditindakake saiki.

Sabanjure, versi apik saka layanan prasaja lan migunani diwenehake karo kabeh sistem operasi Unix-kaya.

Katrangan umum babagan format crontab lan prinsip dhasar operasi sarana kasebut kalebu ing standar utama sistem operasi kaya Unix - POSIX - ing taun 1992, lan kanthi mangkono cron saka standar de facto dadi standar de jure.

Ing taun 1987, Paul Vixie, sawise nliti pangguna Unix babagan kepinginan kanggo cron, ngeculake versi daemon liyane sing mbenerake sawetara masalah cron tradisional lan ngembangake sintaks file tabel.

Miturut versi katelu saka Vixie cron wiwit ketemu syarat POSIX, Kajaba iku, program wis lisensi liberal, utawa rodo ora ana lisensi ing kabeh, kajaba wishes ing README: penulis ora menehi jaminan, jeneng penulis. ora bisa dibusak, lan program mung bisa didol bebarengan karo kode sumber. Keperluan kasebut cocog karo prinsip piranti lunak gratis sing populer ing taun-taun kasebut, mula sawetara distribusi Linux utama sing muncul ing awal 90-an njupuk Vixie cron minangka sistem siji lan isih dikembangake saiki.

Utamane, Red Hat lan SUSE ngembangake garpu Vixie cron - cronie, lan Debian lan Ubuntu nggunakake edisi asli Vixie cron kanthi akeh patch.

Ayo dadi kenalan karo crontab utilitas pangguna sing diterangake ing POSIX, sawise iku kita bakal ndeleng ekstensi sintaks sing kasedhiya ing Vixie cron lan panggunaan variasi Vixie cron ing distribusi Linux populer. Lan pungkasane, ceri ing kue yaiku analisis piranti daemon cron.

POSIX crontab

Yen cron asli tansah bisa digunakake kanggo superuser, panjadwal modern asring ngatasi tugas pangguna biasa, sing luwih aman lan trep.

Crons diwenehake minangka rong program: daemon cron sing terus-terusan lan utilitas crontab sing kasedhiya kanggo pangguna. Sing terakhir ngidini sampeyan ngowahi tabel tugas khusus kanggo saben pangguna ing sistem, nalika daemon ngluncurake tugas saka tabel pangguna lan sistem.

В standar POSIX prilaku daemon ora diterangake ing sembarang cara lan mung program panganggo formal crontab. Anane mekanisme kanggo mbukak tugas pangguna, mesthi, diwenehake, nanging ora diterangake kanthi rinci.

Kanthi nelpon utilitas crontab, sampeyan bisa nindakake papat perkara: ngowahi tabel tugas pangguna ing editor, mbukak tabel saka file, nuduhake tabel tugas saiki, lan mbusak tabel tugas. Conto cara utilitas crontab:

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

Nalika diarani crontab -e editor sing ditemtokake ing variabel lingkungan standar bakal digunakake EDITOR.

Tugas kasebut diterangake kanthi format ing ngisor iki:

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

Lima kolom pisanan saka cathetan: menit [1..60], jam [0..23], dina sasi [1..31], sasi [1..12], dina minggu [0. .6], ngendi 0 iku Sunday. Lapangan pungkasan, enem, minangka baris sing bakal dieksekusi dening interpreter printah standar.

Ing limang kolom pisanan, nilai bisa didhaptar kanthi dipisahake kanthi koma:

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

Utawa nganggo tanda hubung:

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

Akses pangguna menyang jadwal tugas diatur ing POSIX dening file cron.allow lan cron.deny, sing menehi dhaptar pangguna kanthi akses menyang crontab lan pangguna tanpa akses menyang program kasebut. Standar kasebut ora ngatur lokasi file kasebut kanthi cara apa wae.

Miturut standar kasebut, paling ora ana papat variabel lingkungan kudu diterusake menyang program sing diluncurake:

  1. HOME - direktori ngarep pangguna.
  2. LOGNAME - pangguna mlebu.
  3. PATH minangka path ing ngendi sampeyan bisa nemokake utilitas sistem standar.
  4. SHELL - path menyang interpreter printah digunakake.

Utamane, POSIX ora ngomong apa-apa babagan asale saka nilai-nilai variabel kasebut.

Paling laris - Vixie cron 3.0pl1

Leluhur umum saka varian cron populer yaiku Vixie cron 3.0pl1, dikenalake ing mailing list comp.sources.unix ing taun 1992. Kita bakal nimbang fitur utama versi iki kanthi luwih rinci.

Vixie cron kasedhiya ing rong program (cron lan crontab). Kaya biasane, daemon tanggung jawab kanggo maca lan mbukak tugas saka tabel tugas sistem lan tabel tugas pangguna individu, lan utilitas crontab tanggung jawab kanggo nyunting tabel pangguna.

Tabel tugas lan file konfigurasi

Tabel tugas superuser dumunung ing /etc/crontab. Sintaks tabel sistem cocog karo sintaks Vixie cron, kajaba kolom kaping enem nuduhake jeneng pangguna sing kanggo tugas kasebut diluncurake:

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

Tabel tugas pangguna biasa dumunung ing /var/cron/tabs/username lan nggunakake sintaks sing padha. Nalika sampeyan mbukak utilitas crontab minangka pangguna, iki minangka file sing diowahi.

Dhaptar pangguna sing nduweni akses menyang crontab dikelola ing file /var/cron/allow lan /var/cron/deny, ing ngendi sampeyan mung kudu ngetik jeneng pangguna ing baris sing kapisah.

Sintaks sing ditambahi

Dibandhingake karo crontab POSIX, solusi Paul Vixey ngemot sawetara modifikasi sing migunani banget kanggo sintaks tabel tugas utilitas.

Sintaks tabel anyar wis kasedhiya: contone, sampeyan bisa nemtokake dina ing minggu utawa sasi miturut jeneng (Sen, Sel, lan sapiturute):

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

Sampeyan bisa nemtokake langkah kanggo mbukak tugas:

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

Langkah lan interval bisa dicampur:

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

Alternatif intuisi kanggo sintaks biasanipun didhukung (booting maneh, tahunan, tahunan, saben wulan, mingguan, saben dina, tengah wengi, saben jam):

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

Lingkungan eksekusi tugas

Vixie cron ngidini sampeyan ngganti lingkungan aplikasi sing mlaku.

Variabel lingkungan USER, LOGNAME lan HOME ora mung diwenehake dening daemon, nanging dijupuk saka file. passwd. Variabel PATH disetel dadi "/ usr / bin: / bin" lan variabel SHELL disetel dadi "/ bin / sh". Nilai kabeh variabel kajaba LOGNAME bisa diganti ing tabel pangguna.

Sawetara variabel lingkungan (utamane SHELL lan HOME) digunakake dening cron dhewe kanggo mbukak tugas kasebut. Mangkene apa sing nggunakake bash tinimbang sh standar kanggo mbukak tugas khusus bisa uga katon:

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

Pungkasane, kabeh variabel lingkungan sing ditetepake ing tabel (digunakake dening cron utawa dibutuhake dening proses) bakal diterusake menyang tugas sing mlaku.

Kanggo ngowahi file, crontab nggunakake editor sing ditemtokake ing variabel lingkungan VISUAL utawa EDITOR. Yen lingkungan ing ngendi crontab ditindakake ora nemtokake variabel kasebut, banjur "/usr/ucb/vi" digunakake (ucb mbokmenawa Universitas California, Berkeley).

cron ing Debian lan Ubuntu

Pengembang Debian lan distribusi derivatif wis dirilis versi banget dipunéwahi Vixie cron versi 3.0pl1. Ora ana bedane sintaks file tabel; kanggo pangguna, iku Vixie cron sing padha. Fitur Anyar Paling gedhe: Dhukungan syslog, SELinux и PAM.

Kurang katon, nanging owah-owahan nyata kalebu lokasi file konfigurasi lan tabel tugas.

Tabel pangguna ing Debian dumunung ing direktori /var/spool/cron/crontabs, tabel sistem isih ana - ing /etc/crontab. Tabel tugas khusus paket Debian diselehake ing /etc/cron.d, saka ngendi daemon cron maca kanthi otomatis. Kontrol akses pangguna dikontrol dening file /etc/cron.allow lan /etc/cron.deny.

Cangkang standar isih / bin / sh, sing ing Debian minangka cangkang cilik sing cocog karo POSIX mlayu, diluncurake tanpa maca konfigurasi apa wae (ing mode non-interaktif).

Cron dhewe ing versi paling anyar saka Debian diluncurake liwat systemd, lan konfigurasi peluncuran bisa dideleng ing /lib/systemd/system/cron.service. Ora ana sing khusus ing konfigurasi layanan; manajemen tugas sing luwih halus bisa ditindakake liwat variabel lingkungan sing diumumake langsung ing crontab saben pangguna.

cronie ing RedHat, Fedora lan CentOS

kroni - garpu Vixie cron versi 4.1. Kaya ing Debian, sintaks ora diganti, nanging dhukungan kanggo PAM lan SELinux, makarya ing kluster, nglacak file nggunakake inotify lan fitur liyane wis ditambahake.

Konfigurasi standar ing panggonan biasanipun: Tabel sistem ing /etc/crontab, paket sijine tabel ing /etc/cron.d, tabel pangguna mlebu /var/spool/cron/crontabs.

Daemon mlaku ing kontrol systemd, konfigurasi layanan yaiku /lib/systemd/system/crond.service.

Ing distribusi kaya Red Hat, / bin / sh digunakake minangka standar nalika wiwitan, yaiku bash standar. Perlu dicathet yen nalika mbukak proyek cron liwat / bin / sh, cangkang bash diwiwiti ing mode sing cocog karo POSIX lan ora maca konfigurasi tambahan, mlaku ing mode non-interaktif.

cronie ing SLES lan openSUSE

Distribusi Jerman SLES lan openSUSE turunan nggunakake cronie sing padha. Daemon ing kene uga diluncurake ing systemd, konfigurasi layanan dumunung ing /usr/lib/systemd/system/cron.service. Konfigurasi: /etc/crontab, /etc/cron.d, /var/spool/cron/tabs. / bin / sh minangka bash sing padha ing mode non-interaktif sing cocog karo POSIX.

Piranti cron Vixie

Keturunan cron modern ora owah sacara radikal dibandhingake karo Vixie cron, nanging isih entuk fitur anyar sing ora dibutuhake kanggo ngerti prinsip program kasebut. Akeh ekstensi iki ora dirancang lan mbingungake kode kasebut. Kode sumber cron asli dening Paul Vixey seneng maca.

Mulane, aku mutusake kanggo nganalisa piranti cron nggunakake conto program cron sing umum kanggo loro cabang pangembangan - Vixie cron 3.0pl1. Aku bakal menakake conto dening njabut ifdefs sing complicate maca lan ngilangi rincian cilik.

Karya setan bisa dipérang dadi sawetara tahapan:

  1. Inisialisasi program.
  2. Nglumpukake lan nganyari dhaptar tugas sing bakal ditindakake.
  3. Loop cron utama mlaku.
  4. Miwiti tugas.

Ayo padha katon ing urutan.

Wiwitan

Nalika diwiwiti, sawise mriksa argumen proses, cron nginstal panangan sinyal SIGCHLD lan SIGHUP. Sing pertama nggawe entri log babagan mungkasi proses anak, sing nomer loro nutup deskriptor file saka file log:

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

Daemon cron tansah mlaku piyambak ing sistem, mung minangka superuser lan saka direktori cron utama. Panggilan ing ngisor iki nggawe file kunci nganggo PID proses daemon, priksa manawa pangguna bener lan ganti direktori saiki dadi sing utama:

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

Path standar disetel, sing bakal digunakake nalika miwiti proses:

setenv("PATH", _PATH_DEFPATH, 1);

Banjur proses "daemonized": nggawe salinan anak saka proses kanthi nelpon garpu lan sesi anyar ing proses anak (nelpon setsid). Proses induk ora dibutuhake maneh, lan metu:

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

Mandap proses induk ngeculake kunci ing file kunci. Kajaba iku, perlu nganyari PID ing file kasebut menyang bocah kasebut. Sawise iki, database tugas diisi:

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

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

Banjur cron pindhah menyang siklus kerja utama. Nanging sadurunge iku, iku worth njupuk dipikir ing loading dhaftar tugas.

Nglumpukake lan nganyari dhaptar tugas

Fungsi load_database tanggung jawab kanggo mbukak dhaptar tugas. Iku mriksa crontab sistem utama lan direktori karo file pangguna. Yen file lan direktori ora diganti, dhaptar tugas ora diwaca maneh. Yen ora, dhaptar tugas anyar wiwit dibentuk.

Ngunggah file sistem kanthi jeneng file lan tabel khusus:

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

Loading tabel pangguna ing 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);
}

Sawise database lawas diganti karo sing anyar.

Ing conto ing ndhuwur, telpon fungsi process_crontab verifikasi manawa ana pangguna sing cocog karo jeneng file tabel (kajaba iku superuser) banjur nelpon load_user. Sing terakhir wis maca file kasebut kanthi baris:

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

Ing kene, variabel lingkungan disetel (baris saka wangun VAR = nilai) nggunakake fungsi load_env / env_set, utawa deskripsi tugas diwaca (* * * * * /path/to/exec) nggunakake fungsi load_entry.

Entitas entri sing load_entry bali minangka tugas kita, sing diselehake ing dhaptar tugas umum. Fungsi kasebut dhewe nindakake parsing verbose format wektu, nanging kita luwih kasengsem ing pambentukan variabel lingkungan lan paramèter peluncuran tugas:

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

Daur ulang utama bisa digunakake karo dhaptar tugas saiki.

Loop utama

Cron asli saka Versi 7 Unix makarya cukup prasaja: maca maneh konfigurasi ing daur ulang, ngluncurake tugas menit saiki minangka superuser, lan turu nganti wiwitan menit sabanjure. Pendekatan prasaja ing mesin lawas iki mbutuhake sumber daya sing akeh banget.

Versi alternatif diusulake ing SysV, ing ngendi daemon turu nganti menit paling cedhak sing ditetepake tugas kasebut, utawa 30 menit. Kurang sumber daya sing digunakake kanggo maca maneh konfigurasi lan mriksa tugas ing mode iki, nanging kanthi cepet nganyari dhaptar tugas dadi ora trep.

Vixie cron bali mriksa dhaptar tugas saben menit, untunge ing pungkasan taun 80-an ana sumber daya sing luwih akeh ing mesin Unix standar:

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

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

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

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

Fungsi cron_sleep langsung melu nglakokake tugas, nelpon fungsi job_runqueue (enumerate lan mbukak tugas) lan do_command (mlaku saben tugas individu). Fungsi pungkasan worth mriksa luwih rinci.

Nglakokake tugas

Fungsi do_command dieksekusi kanthi gaya Unix sing apik, yaiku, garpu kanggo nindakake tugas kanthi ora sinkron. Proses wong tuwa terus mbukak tugas, proses anak nyiapake proses tugas:

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

Ana cukup akèh logika ing child_process: njupuk output standar lan kesalahan stream menyang dhewe, supaya banjur ngirim menyang mail (yen variabel lingkungan MAILTO kasebut ing meja tugas), lan, pungkasanipun, ngenteni utama proses tugas kanggo ngrampungake.

Proses tugas dibentuk dening garpu liyane:

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

Sing Sejatine kabeh cron punika. Aku ilang sawetara rincian menarik, contone, accounting kanggo pangguna remot, nanging aku mbatesi bab utama.

Afterword

Cron minangka program sing prasaja lan migunani, digawe ing tradhisi paling apik ing jagad Unix. Dheweke ora nindakake apa-apa, nanging dheweke wis nindakake pakaryan kanthi apik sajrone pirang-pirang dekade saiki. Njupuk liwat kode kanggo versi sing nerangake karo Ubuntu njupuk ora luwih saka jam, lan aku wis akèh fun! Muga-muga aku bisa nuduhake karo sampeyan.

Aku ora ngerti bab sampeyan, nanging aku rada sedih kanggo éling sing program modern, karo cenderung kanggo over-complicate lan over-abstract, wis ora kondusif kanggo gamblang kuwi kanggo dangu.

Ana akeh alternatif modern kanggo cron: systemd-timers ngidini sampeyan ngatur sistem kompleks kanthi dependensi, fcron ngidini sampeyan ngatur konsumsi sumber daya kanthi luwih fleksibel kanthi tugas. Nanging kanthi pribadi, crontab sing paling gampang mesthi cukup kanggo aku.

Ing cendhak, tresna Unix, nggunakake program prasaja lan aja lali kanggo maca mana kanggo platform!

Source: www.habr.com

Add a comment