Kategória: Linux všeobecne

Zmenené: 12. január 2012

Fcron – trochu iný plánovač

Pravdepodobne poznáte štandardný plánovač cron (presne Vixie Cron), ktorý je súčasťou väčšiny dnešných distribúcií Linuxu. Má však jednu veľkú nevýhodu na strojoch, ktoré nebežia vkuse (osobné počítače, notebooky), nikdy nie sú spúšťané úlohy, ktoré mali byť vykonané v dobe vypnutia…

Tento nedostatok aspoň čiastočne rieši nástroj anacron, ktorý sa postará aspoň o spúšťanie pravidelných úloh (denné, týždenné a mesačné), ale i tak je cron len ťažko využiteľný napríklad ako pripomienkovač narodenín… Chvíľu som sa pohrával aj s myšlienkou nejakého grafického plánovača, ale kvôli zopár narodeninám mi to príde zbytočné, a tak som začal pátrať a našiel som fcron.

Fcron je náhradou štandardného Vixie cron, avšak bol navrhnutý s ohľadom na systémy, ktoré nebežia 24 hod denne a 7 dní v týždni. Môžete ho použiť ako plnohodnotnú náhradu cron, alebo ako jeho doplnok. Obdobne ako cron, umožňuje používateľom definovať si ich vlastné zoznamy úloh, a to nie len skutočným používateľom, ale prakticky každému používateľovi (aj systémovým). Rovnako ako pri fcron, je najmenšou jednotkou spustenia minúta.

Tip

Zlou správou je, že fcron bol z Debianu odstránený, môžete si ho skompilovať zo zdrojových kódov alebo použiť balík z môjho úložiska…

Zoznamy úloh

Na prácu s úlohami slúži nástroj fcrontab, ktorého použite je veľmi podobné nástroju crontab z Vixie Cron. Pomocou nástroja fcrontab možno:

  • vypísať obsah svojho zoznamu úloh:

    fcrontab -l
    
  • odstrániť svoj zoznam úloh:

    fcrontab -r
    
  • upraviť svoj zoznam úloh:

    fcrontab -e
    
  • obnoviť svoj zoznam úloh, teda znova vygenerovať binárnu podobu zoznamu úloh, čo bude mať za následok zahodenie informácií o poslednom vykonaní úlohy:

    fcrontab -z
    

Každý vyššie spomenutý príkaz možno spustiť v voľbou -n, hoci prakticky to má zmysel len pri úprave, ktorá zaistí, že pri úprave zoznamu úloh, budú aj nezmenené úlohy považované za nové. Bez tejto voľby sa fcron snaží zachovať maximum informácií o úlohách, ktoré menené neboli (čas a úloha), najmä však informácie o nasledujúcom spustení.

Všetky spomenuté možnosti je možné robiť aj so zoznamom úloh iného používateľa, avšak na toto sú potrebné práva root. Napríklad na vypísanie zoznamu úloh používateľa slavko treba zadať:

fcrontab -l slavko

Fcron umožňuje vytvoriť zoznam úloh pre každého používateľa, ktorý má záznam v /etc/passwd, teda ja pre systémových používateľov. Okrem skutočných účtov ešte rozpoznáva používateľa systab, ktorý slúži na správu systémového zoznamu úloh.

Zoznam úloh možno importovať z externého súboru pomocou:

fcrontab súbor používateľ

Príkaz na úpravu zoznamu úloh spúšťa textový editor, v ktorom môžete jednotlivé úlohy upravovať. V Debiane je možné tento editor pre celý systém nastaviť pomocou systému alternatív:

update-alternatives --config editor

Používateľ si ho potom môže zmeniť pomocou premennej prostredia $EDITOR.

Riadenie prístupu

Ako som spomenul, fcron dokáže pracovať so zoznamami úloh hociktorého existujúceho používateľa, ale niekedy je žiadúce toto správanie obmedziť, na čo slúžia súbory riadenia prístupu /etc/frcon.allow a /etc/fcron.denny. Ako mená súborov napovedajú, do prvého možno vkladať mená používateľov, ktorí majú právo vytvárať si zoznamy úloh a do druhého zase mená používateľov, ktorým je toto právo odopreté. Okrem mien používateľov môže byť v týchto súboroch použité kľúčové slovo all, ktoré označuje všetkých používateľov. Nasledujúca tabuľka ukazuje výsledok rôznych kombinácií zápisu do súborov fcron.allow a fcron.denny:

používateľ fcron.allow fcron.denny výsledok
slavko all - môže
slavko - all nemôže
slavko all all nemôže
slavko all slavko nemôže
slavko slavko - môže
slavko slavko all môže
slavko - slavko nemôže
slavko slavko slavko nemôže

Varovanie

Pridanie používateľa do súboru fcron.denny nebráni spúšťaniu jeho úloh, ak už má svoj zoznam úloh vytvorený, preto ho treba odstrániť.

Nastavenie prostredia

Úlohy fcrontab sú spúšťané vždy v novom prostredí, teda nastavenia prostredia nie sú dedené. V tomto prostredí fcron vždy nastavuje premenné:

  • USER a HOME (z /etc/passwd) na základe vlastníka tabuľky fcrontab, z ktorej pochádza úloha;
  • TZ na hodnotu voľby timezone, keď je táto voľba nastavená;
  • SHELL, a to buď z fcrontab, ak tam nie je definovaná, tak z fcron.conf, a ak nie je definovaná ani tam, tak z /etc/passwd;
  • všetky ostatné premenné z fcrontab.

Hodnoty premenných HOME a SHELL môžu byť v tabuľke fcrontab zmenené, ale USER nie. Definícia premenných vo fcrontab je vo forme:

meno = hodnota
  • medzery okolo znaku = sú voliteľné a ignorované
  • medzery na konci sú ignorované
  • na vynútenie medzier možno použiť úvodzovky, a to jednoduché alebo dvojité

Predvolene posiela fcron emaily s hlavičkou Content-Type: nastavenou na „text/plain“ s parametrom „charset=“ nastaveným na kódovanie podľa kódovania prostredia, z ktorého je fcron spustený teda predvolené nastavenie lokalizácie alebo podľa nastavení premenných prostredia LC_\*. V prípade potreby je možné v fcrontab použiť premenné CONTENT_TYPE a/alebo CONTENT_TRANSFER_ENCODING a nastaviť ich na požadované hodnoty.

V fcrontab možno použiť aj špeciálnu premennú MAILTO, ktorá bude udávať adresáta emailov, ale táto premenná je len kvôli spätnej kompatibilite a mala by byť používaná voľba mailto.

Plánovanie úloh

Ak poznáte spôsob vytvárania času spustenia (opakovania) úlohy vo Vixie cron, môžete tieto znalosti využiť, pretože fcron podporuje skoro všetko z tohoto cronu. Píšem skoro všetko, pretože nepodporuje syntax @… (@daily, @monthly, atď) ani definície úloh v /etc/cron.d.

Naproti tomu, v fcron možno definovať čas spustenia tromi spôsobmi:

  • položky @… – založené na čase, ktorý uplynul od štartu
  • položky &… – založené na čase a dátume
  • položky %… – periodicky spúšťané

Spustenie založené na čase od štartu

Tento typ položiek začína znakom @ a spúšťa úlohy raz po každom uplynutí zadaného intervalu, ale negarantuje konkrétny čas a dátum vykonania úlohy, pretože systém mohol byť spustený prakticky kedykoľvek. Všeobecný syntax zápisu takto spúšťanej úlohy vyzerá nasledovne:

@voľby frekvencia príkaz

Voľbám sa budem venovať neskôr, ale namiesto voľby možno za znak @ zadať číslo, ktoré bude interpretované ako hodnota voľby first(). Frekvencia je, predvolene, počet minút (od spustenia), ale pre dlhšie intervaly možno použiť násobky:

  • m – mesiace (4 týždne)
  • w – týždne (7 dní)
  • d – dni (24 hod)
  • h – hodiny (60min)
  • s – sekundy

Príklady:

# spustiť každých 5 minúť
@ 5 echo "Prešlo 5 minút"

# prijať emaily každých 30 min
@ 30 getmails -all

# prvý krát spustiť po 5 min, potom každú hodinu
@5 1h   echo "Prešla hodina"

# spustiť každých 12 hod a 2 min
@ 12h02 echo "Prešlo 12 hod a 2 min"

# spustiť každý deň
@ 1d echo "systém beží ďalší deň"

Spustenie založené na dátume a čase

Druhý typ položiek začína voliteľným znakom & a spúšťa úlohy v zadaných časoch, ktoré sú definované pomocou piatich časových polí (rovnako ako vo Vixie cron):

&voľby min hod den-mesiaca mesiac deň-týždňa príkaz

Aj tu sa budem voľbám venovať neskôr, ale namiesto voľby možno za znak @ zadať číslo, ktoré bude interpretované ako hodnota voľby runfreq().

Časové polia môžu byť zadané pomocou:

  • číslo
  • hviezdička
  • zoznam
  • rozsah
  • meno

Povolený rozsah čísel:

  • minúta – 0-59
  • hodina – 0-23
  • deň mesiaca – 1-31
  • mesiac – 1-12 (alebo meno)
  • deň týždňa – 0-7, pričom 0 i 7 sú nedeľa (alebo meno)

Ak je hodnotou poľa jedno číslo (alebo meno), pole vyhovuje pre túto konkrétnu hodnotu. Ak je hodnotou hviezdička, pole vyhovuje každej hodnote v rozsahu povolenom pre dané pole. Zoznamy sú hodnoty oddelené čiarkami a pole vyhovuje pre každú hodnotu zoznamu.

Rozsahy sú vo forme štart-koniec, a pole vyhovuje pre každú hodnotu rozsahu (vrátane hraničných). K rozsahu možno pridať časť /číslo, ktoré udáva počet preskakovaných hodnôt. Ďalším rozšírením je pridanie jednej alebo viac ~číslo, čo udáva konkrétne hodnoty, ktoré budú preskočené.

Výsledný čas spustenia je určený logickým a všetkých polí, teda aby bola úloha spustená, musia všetky polia zodpovedať aktuálnemu času. Zaujímavou však je kombinácia definície dňa mesiaca (dátumového) a dňa týždňa, pretože tieto polia môžu byť v určovaní termínu spracované dvomi spôsobmi:

  • pomocou logického a, teda ak vyhovujú obe polia (predvolene)
  • pomocou logického alebo, teda ak vyhovuje jedno z polí (voľba dayor).

Príklady:

# spustí príkaz každý deň o 12:05, 12:35, 13:05, 13:35, 14:05 a 14:35
05,35 12-14 * * * echo "Spustené"

# spustí príkaz každú hodinu v 20, 21, 22, 23 a 24 minúte
20-24 * * * * * echo "Spustené"

# spustí príkaz každú hodinu v 20, 21, 22 a 24 minúte
20-24~23 * * * * * echo "Spustené"

# spustí príkaz každú druhú hodinu v 20, 21, 22 a 24 minúte
20-24~23 */2 * * * echo "Spustené"

# spustiť úlohu o 03.45 alebo po štarte, ak o 03.45 nebol stroj zapnutý
# ~0 zasití, aby úloha nebola spustená v nedeľu 2x
&bootrun 45 03 * * *~0 "Spustené"

Spúšťanie v intervaloch

Tretí typ položiek začína znakom %, nasledovaným kľúčovým slovom a spúšťa úlohu raz v zadanom intervale. Jeho základná syntax vyzerá takto:

%kľúčové_slovo,voľby dátum_a_čas príkaz

I tu popis volieb preskočím a spomeniem len, že ak nie sú použité žiadne voľby, netreba ani čiarku za kľúčovým slovom. Táto voľba je skutočnou silou plánovača fcron, pretože konkrétny čas vykonania úlohy závisí na tom, či a kedy je počítač spustený. Fcron pozná tri typy kľúčových slov tohoto typu položky, pričom prvé dva z nich majú podobné správanie:

  • *ly – hourly, daily, monthly a weekly
  • mid*ly – midhourly, middaily, nightly, midmonthly a midweekly

Kľúčové slová *ly udávajú interval, ktorý zodpovedá ich menu a spustí úlohu v určenom intervale, keď je počítač spustený. Kľúčové slová mid*ly sa správajú presne rovnako, len interval začína uprostred daného intervalu, takže napríklad %midweekly spustí úlohu medzi štvrtkom a stredou.

Konkrétny čas spustenia úlohy závisí od špecifikácie času a dátumu. Tento časový údaj sa riadi rovnakými pravidlami ako v predchádzajúcom type položky (položky &…), jeho interpretácia je však mierne odlišná. Každá voľba pracuje s iným povinným rozsahom polí (ale môžu byť zadané aj ostatné polia):

kľúčové slovo časový údaj
hourly, midhourly minúty
daily, middaily, nightly, weekly, midweekly minúty a hodiny
monthly, midmonthly minúty, hodiny a dni

Ak je časový údaj definovaný ako rozsah, je úloha spustená niekedy v tomto rozsahu. Ak je definovaný ako zoznam rozsahov, je úloha spustená raz pre každý rozsah v zozname.

Tretím typom kľúčových slov sú *s, konkrétne:

  • *s – mins, hours, days, mons a dow (pracovné dni)

Tieto kľúčové slová spúšťajú úlohy trochu inak, a to raz v každom zadanom časovom intervale, pričom ako interval ignorujú zadané hodnoty s nižším rozsahom ako kľúčové slovo (hours nepovažuje pole s minútami ako definíciu intervalu, ale bude použité ako definícia času vykonania počas intervalu). Časový údaj týchto kľúčových slov sa skladá zo všetkých piatich časových polí.

Príklady:

# bude spustená raz medzi 2.00 a 10.59 a raz medzi 14.00 a 22.59
%daily * 2-10,14-22 echo "dva krát za deň"

# bude spustená každú hodinu, hneď ako je to možné
# napr 16.51, 17.00, 18.00, ...
%hourly * echo "každú hodinu"

# bude spustená raz týždenne 19:00 a 22:59
%weekly * 19-22 echo "raz za týždeň"

# bude spustené každý deň o 19:30, 20:30, 21:30 a o 22:30
%mins 30 19-22 * * * echo "štyri krát za deň"

# bude spustené o 19:30, 20:30, 21:30 alebo o 22:30
%hours 30 19-22 * * * echo "raz za deň"

# spustí príkaz raz medzi 8.00 a 12.59 a raz medzi 14.00 a 18.59
%hours * 8-12,14-18 * * *

Voľby

Voľby, ktoré menia správania spustenia úlohy, možno zadať na samostatnom riadku (potom platia pre zvyšok zoznamu úloh za voľbou) alebo v riadku úlohy. V prípade ich použitia na samostatnom riadku musí riadok začínať výkričníkom, nasledovaný voľbou. Na jednom riadku (v jednej úlohe) je možné zadať viac volieb, tieto sú potom oddelené čiarkami. V definícii volieb nie sú dovolené medzery.

Fcron poskytuje veľa volieb, nebudem tu popisovať všetky, ale len tie (pre mňa) najzaujímavejšie, kompletný popis je v manuálovej stránke:

bootrun
platné len pre položky &... ak mali byť vykonané počas vypnutia systému, budú vykonané pri štarte
dayor
polia deň týždňa a deň mesiaca porovnáva pomocou logického alebo
forcemail
vynúti poslanie emailu, aj keď nie je žiadny výstup
mailto(meno)
meno používateľa alebo emailová adresa adresára emailu (predvolene vlastník fcrontab)
nice(číslo)
mení prioritu spúšťanej úlohy
lavg(x,y,z)

vloží úlohu do fronty, kde čaká kým nebude load (1 min, 5 min a 15 min) systému nižší ako zadané hodnoty (AND), front dokáže uchovať až 30 úloh

  • podobnú úlohu plnia voľby lavg1, lavg5 a lavg15,
random
v položkách %… mení čas spustenia úlohy v intervale z hneď ako je možné na „v náhodnom čase“
rebootreset
fcron bude po každom reštarte OS považovať úlohu za novú, je to obdoba voľby volatile, ale založená na reštarte systému, nie na reštarte démona
reset
obnoví predvolené nastavenie všetkých volieb
runas(meno)
spustiť s právami iného používateľa, môže použiť len root
runatreboot
úloha bude spustená pri štarte systému (teda pri prvom spustení démona fcron po štarte operačného systému)
runfreq(počet)
frekvencia spúšťania (ignorované v položkách @...), teda spusť len každý n-tý krát
runonce
po spustení úlohy je nenaplánuje na ďalšie spustenie, kým nebude reštartovaný systém (ak nie je nastavené volatile) alebo kým nebude reštartovaný démon fcron (ak je nastavené volatile)
serial
nastavuje sériové (postupné) spúšťanie úloh, pričom naraz je spustená najviac jedna sériová úloha najviac jednu zo sériových úloh, ktoré majú nastavené rovnaké hodnoty lavg() (alebo lavg1, lavg5 či lavg15)
serialonce
udáva, či majú (môžu) byť v sériovom fronte ukladané úlohy aj viackrát, teda ak sériová úloha čaká vo fronte a nastane čas jej ďalšieho spustenia, či má byť znova pridaná do frontu

Tam kde nie je uvedený parameter voľby je voľba logickým prepínačom a pridanie parametra (false) má za následok opačný význam voľby. Ďalšie voľby nájdete v manuálovej stránke fcrontab(5).

Uspávanie

Pri zobudení počítača z uspania/hibernácie je potrebné démona fcron reštartovať, pretože má nesprávne vypočítané časy budúceho spustenia úloh. V Debiane sa o to postará jednoduchý skript, ktorý možno umiestniť do /etc/pm/sleep.d/ a nazvať napríklad 50fcron:

#!/bin/sh

# This script makes fcron jobs start to run when the machine is woken up.
# For a laptop, these are the closest parallels to turning on a desktop.

case $1 in
    hibernate|suspend)
        [ -x /etc/init.d/fcron ] && /etc/init.d/fcron stop
        ;;
    thaw|resume)
        [ -x /etc/init.d/fcron ] && /etc/init.d/fcron start
        ;;
esac

Nahradenie Vixie cron

Ako spomínal na začiatku, fron môže plnohodnotne nahradiť štandardný cron, čo sa týka používateľských zoznamov úloh to už iste dokážete posúdiť aj sami. V podstate fcron plne podporuje syntax plánovania úloh cron, s tým, že nepodporuje (respektíve dáva iný význam) položkám definovaným pomocou @hourly a podobne.

Trochu väčší, avšak riešiteľný problém, sú adresáre /etc/cron.*, do ktorých inštaluje svoje úlohy mnoho ďalších balíkov. Bez väčších problémov možno naplánovať spúšťanie skriptov v adresároch cron.daily, cron.hourly a cron.mounthly, pretože sa naozaj jedná o skripty (poslúži príkaz run-parts z balíka debianutils). Najtvrdším orieškom ostáva adresár /etc/cron.d, keďže súbory v tomto adresári nie sú skripty, ale úlohy cronu s rovnakou syntaxou ako je v crontab. Aj toto je však riešiteľné, hoci pomocou samostatného skriptu, ktorý je súčasťou zdrojových kódov frcon a určite sa k tomu ešte vrátim, ale inokedy.

Nahradenie skratiek Vixie cron

Démon fcron teraz rozumie týmto skratkám, používaným v tabuľkách úloh Vixie cron:

skratka Vixie cron význam ekvivalent fcron odporúčaná alternatíva
@reboot Spustiť raz, pri štarte @runatreboot,runonce(true)  
@yearly Spustiť raz za rok 0 0 1 1 * @ 12m
@annually (rovnaké ako @yearly) 0 0 1 1 * @ 12m
@monthly Spustiť raz za mesiac 0 0 1 * * @ 1m
@weekly Spustiť raz za týždeň 0 0 * * 0 @ 1w
@daily Spustiť raz za deň 0 0 * * * @ 1d
@midnight (rovnaké ako @daily) 0 0 * * *  
@hourly Spustiť raz za hodinu 0 * * * * @ 1h