Cron Linux-ում. պատմություն, օգտագործում և սարք

Cron Linux-ում. պատմություն, օգտագործում և սարք

Դասականը գրել է, որ երջանիկ ժամերը չեն դիտում։ Այն վայրի ժամանակներում ոչ ծրագրավորողներ կային, ոչ Յունիքս, բայց այսօր ծրագրավորողները հաստատ գիտեն՝ նրանց փոխարեն cron-ը կհետևի ժամանակին։

Հրամանատարի կոմունալ ծառայություններն ինձ համար և՛ թուլություն են, և՛ գործ: sed, awk, wc, cut և այլ հին ծրագրերը ամեն օր գործարկվում են մեր սերվերների սկրիպտներով: Դրանցից շատերը նախագծված են որպես առաջադրանքներ cron-ի համար՝ ժամանակացույցի սկզբնապես 70-ականներից:

Երկար ժամանակ ես օգտագործում էի cron-ը մակերեսորեն, առանց մանրամասնելու, բայց մի օր, երբ սկրիպտը գործարկելիս սխալի հանդիպեցի, որոշեցի մանրակրկիտ ուսումնասիրել այն։ Ահա թե ինչպես հայտնվեց այս հոդվածը, այն գրելիս ես ծանոթացա POSIX crontab-ին՝ հայտնի Linux բաշխումների հիմնական cron տարբերակներին և դրանցից մի քանիսի կառուցվածքին:

Դուք օգտվո՞ւմ եք Linux-ից և կատարում եք cron առաջադրանքներ: Հետաքրքրվա՞ծ եք Unix-ում համակարգի կիրառական ճարտարապետությամբ: Հետո մենք մեր ճանապարհին ենք:

Պարունակություն

Տեսակների ծագումը

Օգտագործողի կամ համակարգի ծրագրերի պարբերական կատարումը ակնհայտ անհրաժեշտություն է բոլոր օպերացիոն համակարգերում: Հետևաբար, ծրագրավորողները վաղուց հասկացել են ծառայությունների անհրաժեշտությունը, որոնք թույլ են տալիս կենտրոնացված կերպով պլանավորել և կատարել առաջադրանքները:

Unix-ի նման օպերացիոն համակարգերը սկիզբ են առնում Unix 7-րդ տարբերակից, որը մշակվել է անցյալ դարի 70-ականներին Bell Labs-ում, այդ թվում՝ հայտնի Քեն Թոմփսոնի կողմից: Unix-ի 7-րդ տարբերակը ներառում էր նաև cron-ը, որը գերօգտագործողի առաջադրանքների կանոնավոր գործարկումն է:

Տիպիկ ժամանակակից cron-ը պարզ ծրագիր է, բայց սկզբնական տարբերակի գործառնական ալգորիթմն ավելի պարզ էր. ծառայությունը րոպեն մեկ արթնանում էր, մեկ ֆայլից (/etc/lib/crontab) կարդում էր առաջադրանքներով աղյուսակ և կատարում superuser այն առաջադրանքները, որոնք պետք է կատարվեին ներկա պահին:

Այնուհետև, պարզ և օգտակար ծառայության բարելավված տարբերակները մատակարարվեցին բոլոր Unix-ի նման օպերացիոն համակարգերով:

Crontab ձևաչափի ընդհանրացված նկարագրությունները և կոմունալ ծառայության հիմնական սկզբունքները ներառվել են Unix-ի նման օպերացիոն համակարգերի հիմնական ստանդարտում՝ POSIX-ում 1992 թվականին, և այդպիսով, cron-ը դե ֆակտո ստանդարտից դարձել է դե յուրե ստանդարտ:

1987թ.-ին Փոլ Վիքսին, հարցում անելով Unix-ի օգտատերերին cron-ի ցանկությունների մասին, թողարկեց դեյմոնի մեկ այլ տարբերակ, որը շտկեց ավանդական cron-ի որոշ խնդիրներ և ընդլայնեց սեղանի ֆայլերի շարահյուսությունը:

Vixie-ի երրորդ տարբերակով cron-ը սկսեց բավարարել POSIX-ի պահանջները, բացի այդ, ծրագիրն ուներ լիբերալ լիցենզիա, ավելի ճիշտ՝ լիցենզիա ընդհանրապես չկար, բացառությամբ README-ի ցանկությունների. հեղինակը երաշխիքներ չի տալիս, հեղինակի անունը։ չի կարող ջնջվել, և ծրագիրը կարող է վաճառվել միայն սկզբնական կոդի հետ միասին: Պարզվեց, որ այս պահանջները համատեղելի էին ազատ ծրագրային ապահովման սկզբունքների հետ, որոնք այդ տարիներին ժողովրդականություն էին վայելում, ուստի Linux-ի որոշ առանցքային բաշխումներ, որոնք հայտնվեցին 90-ականների սկզբին, վերցրեցին Vixie cron-ը որպես իրենց համակարգային և մինչ օրս այն զարգացնում են:

Մասնավորապես, Red Hat-ը և SUSE-ը մշակում են Vixie cron-ի պատառաքաղը՝ cronie, իսկ Debian-ն ու Ubuntu-ն օգտագործում են Vixie cron-ի բնօրինակ տարբերակը՝ բազմաթիվ patches-ներով:

Եկեք նախ ծանոթանանք POSIX-ում նկարագրված օգտվողի օգտակար crontab-ին, որից հետո կդիտարկենք Vixie cron-ում տրամադրված շարահյուսական ընդլայնումները և Vixie cron-ի տատանումների օգտագործումը հայտնի Linux բաշխումներում: Եվ վերջապես, տորթի վրայի բալը cron daemon սարքի վերլուծությունն է։

POSIX կրոնտաբ

Եթե ​​բնօրինակ cron-ը միշտ աշխատել է գերօգտագործողի համար, ժամանակակից ժամանակացույցները հաճախ զբաղվում են սովորական օգտատերերի առաջադրանքներով, ինչը ավելի ապահով և հարմար է:

Cron-ները մատակարարվում են որպես երկու ծրագրերի հավաքածու՝ անընդհատ գործող cron daemon և 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 տարբերակների ընդհանուր նախահայրը Vixie cron 3.0pl1-ն է, որը ներկայացվել է comp.sources.unix փոստային ցուցակում 1992 թվականին: Մենք ավելի մանրամասն կքննարկենք այս տարբերակի հիմնական հատկանիշները:

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-ի հետ՝ Paul Vixey-ի լուծումը պարունակում է մի քանի շատ օգտակար փոփոխություններ կոմունալ ծառայության առաջադրանքների աղյուսակների շարահյուսության մեջ:

Աղյուսակի նոր շարահյուսությունը հասանելի է դարձել. օրինակ, կարող եք անվանել շաբաթվա օրերը կամ ամիսները (երկուշաբթի, երեքշաբթի և այլն).

# Запускается ежеминутно по понедельникам и вторникам в январе
* * * 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 կամ EDITOR միջավայրի փոփոխականում նշված խմբագրիչը: Եթե ​​միջավայրը, որտեղ գործարկվել է crontab-ը, չունի այս փոփոխականները սահմանված, ապա օգտագործվում է «/usr/ucb/vi» (ucb-ը հավանաբար Կալիֆորնիայի համալսարանն է, Բերքլի):

cron-ը Debian-ում և Ubuntu-ում

Debian-ի և ածանցյալ բաշխումների մշակողները թողարկել են խիստ փոփոխված տարբերակ Vixie cron տարբերակը 3.0pl1. Սեղանի ֆայլերի շարահյուսության մեջ տարբերություններ չկան, օգտատերերի համար դա նույն Vixie cron-ն է։ Ամենամեծ նոր առանձնահատկությունը. Աջակցություն syslog, SELinux- ը и PAM.

Ավելի քիչ նկատելի, բայց շոշափելի փոփոխությունները ներառում են կազմաձևման ֆայլերի և առաջադրանքների աղյուսակների գտնվելու վայրը:

Debian-ի օգտատերերի աղյուսակները գտնվում են /var/spool/cron/crontabs գրացուցակում, համակարգի աղյուսակը դեռ այնտեղ է՝ /etc/crontab-ում: Debian փաթեթին հատուկ առաջադրանքների աղյուսակները տեղադրվում են /etc/cron.d-ում, որտեղից cron daemon-ը ավտոմատ կերպով կարդում է դրանք։ Օգտատիրոջ մուտքի վերահսկումը վերահսկվում է /etc/cron.allow և /etc/cron.deny ֆայլերով:

Լռելյայն ծածկույթը շարունակում է մնալ /bin/sh, որը Debian-ում POSIX-ին համապատասխանող փոքր շերտ է: անիծել, գործարկվել է առանց որևէ կոնֆիգուրացիա կարդալու (ոչ ինտերակտիվ ռեժիմում):

Cron-ն ինքը Debian-ի վերջին տարբերակներում գործարկվում է systemd-ի միջոցով, և գործարկման կոնֆիգուրացիան կարելի է դիտել /lib/systemd/system/cron.service-ում: Ծառայության կոնֆիգուրացիայի մեջ առանձնահատուկ բան չկա, ավելի նուրբ առաջադրանքների կառավարումը կարող է իրականացվել շրջակա միջավայրի փոփոխականների միջոցով, որոնք ուղղակիորեն հայտարարված են յուրաքանչյուր օգտագործողի crontab-ում:

cronie-ն RedHat-ում, Fedora-ում և CentOS-ում

քրոնիկ — Vixie cron 4.1 տարբերակի պատառաքաղ: Ինչպես Debian-ում, շարահյուսությունը չի փոխվել, սակայն ավելացվել է աջակցություն PAM-ի և SELinux-ի, կլաստերի մեջ աշխատելու, inotify-ի միջոցով ֆայլերին հետևելու և այլ հնարավորությունների համար:

Լռելյայն կոնֆիգուրացիան գտնվում է սովորական վայրերում. համակարգի աղյուսակը գտնվում է /etc/crontab-ում, փաթեթներն իրենց աղյուսակները դնում են /etc/cron.d-ում, օգտվողների աղյուսակները մտնում են /var/spool/cron/crontabs:

Դեյմոնն աշխատում է systemd հսկողության ներքո, ծառայության կոնֆիգուրացիան /lib/systemd/system/crond.service է:

Red Hat-ի նման բաշխումների դեպքում /bin/sh-ը լռելյայն օգտագործվում է գործարկման ժամանակ, որը ստանդարտ bash-ն է: Պետք է նշել, որ /bin/sh-ի միջոցով cron-ի աշխատանքը գործարկելիս bash shell-ը սկսվում է POSIX-ին համապատասխանող ռեժիմով և չի կարդում որևէ լրացուցիչ կոնֆիգուրացիա՝ աշխատելով ոչ ինտերակտիվ ռեժիմով:

cronie-ն SLES-ում և openSUSE-ում

Գերմանական SLES բաշխումը և դրա ածանցյալը openSUSE-ն օգտագործում են նույն cronie-ն: Դեյմոնն այստեղ նույնպես գործարկվում է systemd-ի տակ, ծառայության կոնֆիգուրացիան գտնվում է /usr/lib/systemd/system/cron.service-ում: Կազմաձևում՝ /etc/crontab, /etc/cron.d, /var/spool/cron/tabs: /bin/sh-ը նույն bash-ն է, որն աշխատում է POSIX-ին համապատասխան ոչ ինտերակտիվ ռեժիմով:

Vixie cron սարք

Cron-ի ժամանակակից ժառանգները արմատապես չեն փոխվել Vixie cron-ի համեմատ, բայց դեռևս ձեռք են բերել նոր առանձնահատկություններ, որոնք չեն պահանջվում հասկանալ ծրագրի սկզբունքները: Այս ընդլայնումներից շատերը վատ նախագծված են և շփոթում են կոդը: Պոլ Վիքսեյի կողմից ստեղծված cron սկզբնական կոդը հաճելի է կարդալ:

Հետևաբար, ես որոշեցի վերլուծել cron սարքը՝ օգտագործելով cron ծրագրի օրինակը, որը ընդհանուր է զարգացման երկու ճյուղերի համար՝ Vixie cron 3.0pl1: Ես կպարզեցնեմ օրինակները՝ հեռացնելով ifdef-ները, որոնք բարդացնում են ընթերցումը և բաց թողնում աննշան մանրամասները:

Դևի աշխատանքը կարելի է բաժանել մի քանի փուլերի.

  1. Ծրագրի սկզբնավորում.
  2. Աշխատանքային առաջադրանքների ցանկի հավաքում և թարմացում:
  3. Հիմնական cron հանգույցն աշխատում է:
  4. Սկսեք առաջադրանք:

Դիտարկենք դրանք ըստ հերթականության։

Մեկնարկումը

Երբ սկսվում է, պրոցեսի փաստարկները ստուգելուց հետո, cron-ը տեղադրում է SIGCHLD և SIGHUP ազդանշանի մշակիչներ: Առաջինը գրանցամատյանում գրառում է կատարում երեխայի գործընթացի ավարտի մասին, երկրորդը փակում է մատյան ֆայլի ֆայլի նկարագրիչը.

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

Cron daemon-ը միշտ աշխատում է միայնակ համակարգում, միայն որպես գերօգտագործող և հիմնական cron գրացուցակից: Հետևյալ զանգերը ստեղծում են կողպեքի ֆայլ՝ daemon գործընթացի 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_database ֆունկցիան պատասխանատու է առաջադրանքների ցանկը բեռնելու համար: Այն ստուգում է հիմնական համակարգի 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;
    }
}

Այստեղ կա՛մ շրջակա միջավայրի փոփոխականը դրված է (VAR=value ձևի տողեր)՝ օգտագործելով load_env / env_set ֆունկցիաները, կամ առաջադրանքի նկարագրությունը կարդացվում է (* * * * * /path/to/exec)՝ օգտագործելով load_entry ֆունկցիան։

Մուտքի էությունը, որը վերադարձնում է 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);

Հիմնական հանգույցն աշխատում է առաջադրանքների ընթացիկ ցանկի հետ:

Հիմնական հանգույց

Unix-ի 7-րդ տարբերակի բնօրինակը cron-ն աշխատում էր բավականին պարզ. այն վերընթերցում էր կոնֆիգուրացիան հանգույցով, գործարկում էր ընթացիկ րոպեի առաջադրանքները որպես գերօգտագործող և քնում մինչև հաջորդ րոպեի սկիզբը: Հին մեքենաների այս պարզ մոտեցումը չափազանց շատ ռեսուրսներ էր պահանջում:

SysV-ում առաջարկվել է այլընտրանքային տարբերակ, որտեղ դեյմոնը քնում է կամ մինչև մոտակա րոպեն, որի համար առաջադրանքը սահմանվել է, կամ 30 րոպե: Ավելի քիչ ռեսուրսներ են ծախսվել այս ռեժիմում կազմաձևումը վերընթերցելու և առաջադրանքները ստուգելու համար, սակայն առաջադրանքների ցանկի արագ թարմացումը անհարմար է դարձել:

Vixie cron-ը վերադարձավ րոպեն մեկ անգամ առաջադրանքների ցուցակները ստուգելուն, բարեբախտաբար մինչև 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;
}

Երեխայի գործընթացում բավականին շատ տրամաբանություն կա. այն վերցնում է ստանդարտ ելք և սխալի հոսքեր իր վրա, որպեսզի այն ուղարկի փոստ (եթե առաջադրանքի աղյուսակում նշված է 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-timers-ը թույլ է տալիս կազմակերպել կախվածություն ունեցող բարդ համակարգեր, fcron-ը թույլ է տալիս ավելի ճկուն կերպով կարգավորել ռեսուրսների սպառումը ըստ առաջադրանքների: Բայց անձամբ ինձ միշտ բավական էր ամենապարզ քրոնթաբը։

Մի խոսքով, սիրեք Unix-ը, օգտագործեք պարզ ծրագրեր և մի մոռացեք կարդալ ձեր հարթակի մանան:

Source: www.habr.com

Добавить комментарий