
Der Klassiker sagte, dass glückliche Stunden nicht beobachtet werden. In jenen wilden Zeiten gab es weder Programmierer noch Unix, aber heutzutage wissen Programmierer mit Sicherheit: Stattdessen kümmert sich cron um die Zeit.
Befehlszeilen-Utilities sind für mich gleichzeitig eine Schwäche und Routine. sed, awk, wc, cut und andere alte Programme werden täglich durch Skripte auf unseren Servern ausgeführt. Viele von ihnen sind als Aufgaben für cron eingerichtet, einem Scheduler, der aus den 70er Jahren stammt.
Lange Zeit habe ich cron nur oberflächlich genutzt, ohne mich mit den Details zu beschäftigen, aber als ich irgendwann bei der Ausführung eines Skripts auf einen Fehler stieß, beschloss ich, mich intensiver damit auseinanderzusetzen. So entstand dieser Artikel, in dem ich mich mit POSIX crontab, den Hauptvarianten von cron in gängigen Linux-Distributionen und deren Funktionsweise vertrautmachte.
Nutzen Sie Linux und führen Aufgaben in cron aus? Interessiert Sie die Architektur von Systemanwendungen in Unix? Dann sind wir auf dem richtigen Weg!
Inhalt
Die Entstehung der Arten
Die regelmäßige Ausführung von Benutzer- oder Systemprogrammen ist eine offensichtliche Notwendigkeit in allen Betriebssystemen. Daher haben Programmierer schon vor langer Zeit die Notwendigkeit von Diensten erkannt, die das zentrale Planen und Ausführen von Aufgaben ermöglichen.
Unix-ähnliche Betriebssysteme stammen von Version 7 Unix ab, das in den 70er Jahren des letzten Jahrhunderts in den Bell Labs, unter anderem vom berühmten Ken Thompson, entwickelt wurde. Zusammen mit Version 7 Unix wurde auch cron geliefert, ein Dienst zur regelmäßigen Ausführung von Aufgaben für Superuser.
Ein typisches modernes cron ist ein einfaches Programm, aber der Algorithmus der Originalversion war noch einfacher: Der Dienst wacht einmal pro Minute auf, liest die Aufgabenliste aus einer einzigen Datei (/etc/lib/crontab) und führt die Aufgaben aus, die für den aktuellen Minutenzeitpunkt für den Superuser vorgesehen sind.
In der Folge wurden verbesserte Versionen dieses einfachen und nützlichen Dienstes mit allen Unix-ähnlichen Betriebssystemen ausgeliefert.
Die allgemeinen Beschreibungen des crontab-Formats und der grundlegenden Funktionsweise des Dienstprogramms wurden 1992 in den Hauptstandard für Unix-ähnliche Betriebssysteme – POSIX – aufgenommen. Damit wurde cron von einem De-Facto-Standard zu einem De-jure-Standard.
Im Jahr 1987 fragte Paul Vixie Unix-Nutzer nach ihren Wünschen bezüglich cron und veröffentlichte eine weitere Version des Daemons, die einige Probleme der traditionellen cron behob und die Syntax der Tabellen-Dateien erweiterte.
Mit der dritten Version wurde Vixie cron den Anforderungen von POSIX gerecht; zudem hatte das Programm eine liberale Lizenz, vielmehr gab es überhaupt keine Lizenz, abgesehen von den Wünschen im README: der Autor gibt keine Garantien, der Name des Autors darf nicht entfernt werden, und das Programm darf nur zusammen mit dem Quellcode verkauft werden. Diese Anforderungen erwiesen sich als kompatibel mit den Prinzipien der damals populär werdenden freien Software, weshalb einige wichtige Distributionen von Linux, die Anfang der 90er Jahre erschienen, Vixie cron als System-Tool aufnahmen und es bis heute weiterentwickeln.
Insbesondere Red Hat und SUSE entwickeln einen Fork von Vixie cron – cronie, während Debian und Ubuntu die Originalversion von Vixie cron mit zahlreichen Patches verwenden.
Lassen Sie uns zunächst die im POSIX-Standard beschriebene Benutzeranwendung crontab kennenlernen. Danach werden wir die Syntaxerweiterungen im Vixie cron sowie die Verwendung von Varianten des Vixie cron in gängigen Linux-Distributionen besprechen. Und schließlich als Sahnehäubchen — die Funktionsweise des cron-Daemons.
POSIX crontab
Während der ursprüngliche cron immer für Superuser konzipiert war, beschäftigen sich moderne Scheduler häufiger mit Aufgaben von regulären Benutzern, was sowohl sicherer als auch praktischer ist.
Crones werden als Paket bestehend aus zwei Programmen geliefert: einem ständig laufenden cron-Daemon und dem benutzerfreundlichen crontab-Tool. Letzteres ermöglicht die Bearbeitung von auf jeden Benutzer im System zugeschnittenen Aufgabentabellen, während der Daemon die Aufgaben aus den Benutzer- und Systemtabellen ausführt.
In Das Verhalten des Daemons wird dabei nicht beschrieben, und nur das Benutzerprogramm ist formalisiert. . Die Existenz von Mechanismen zur Ausführung von Benutzeraufgaben wird zwar impliziert, jedoch nicht im Detail beschrieben.
Mit dem Befehl crontab können Sie vier Dinge erledigen: die Benutzertabelle der Aufgaben im Editor bearbeiten, die Tabelle aus einer Datei laden, die aktuelle Aufgabenliste anzeigen und die Aufgabenliste löschen. Beispiele für die Verwendung des crontab-Befehls:
crontab -e # Aufgabenliste bearbeiten
crontab -l # Aufgabenliste anzeigen
crontab -r # Aufgabenliste löschen
crontab path/to/file.crontab # Aufgabenliste aus einer Datei ladenBeim Aufruf crontab -e verwendet den im Standard-Umgebungsvariablen angegebenen Editor EDITOR.
Die Aufgaben selbst sind im folgenden Format beschrieben:
# строки-комментарии игнорируются
#
# задача, выполняемая ежеминутно
* * * * * /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.logDie ersten fünf Felder der Einträge: Minuten [1..60], Stunden [0..23], Tage des Monats [1..31], Monate [1..12], Wochentage [0..6], wobei 0 für Sonntag steht. Das letzte, sechste Feld ist eine Zeichenfolge, die vom Standard-Befehlsinterpreter ausgeführt wird.
In den ersten fünf Feldern können Werte durch Kommas aufgelistet werden:
# задача, выполняемая в первую и десятую минуты каждого часа
1,10 * * * * /path/to/exec -a -b -cOder durch Bindestriche:
# задача, выполняемая в каждую из первых десяти минут каждого часа
0-9 * * * * /path/to/exec -a -b -cDer Zugriff der Benutzer auf die Aufgabenplanung wird in den POSIX-Dateien cron.allow und cron.deny geregelt, in denen entsprechend die Benutzer mit Zugriff auf crontab und die Benutzer ohne Zugriff auf das Programm aufgelistet sind. Der Standard regelt nicht, wo sich diese Dateien befinden.
Laut Standard müssen den gestarteten Programmen mindestens vier Umgebungsvariablen übergeben werden:
- HOME — das Home-Verzeichnis des Benutzers.
- LOGNAME — der Benutzername.
- PATH — der Pfad, unter dem die Standardwerkzeuge des Systems gefunden werden können.
- SHELL — der Pfad zum verwendeten Kommandointerpreter.
Bemerkenswert ist, dass POSIX keine Angaben dazu macht, woher die Werte für diese Variablen stammen.
Bestseller – Vixie cron 3.0pl1
Der gemeinsame Vorfahre der populären Cron-Varianten ist Vixie Cron 3.0pl1, der 1992 in der Mailingliste comp.sources.unix vorgestellt wurde. Die Hauptfunktionen dieser Version werden wir nun näher betrachten.
Vixie Cron wird in zwei Programmen geliefert (cron und crontab). Wie üblich ist der Daemon verantwortlich für das Lesen und Ausführen von Aufgaben aus der Systemaufgaben-Tabelle und den Aufgaben-Tabellen einzelner Benutzer, während das Dienstprogramm crontab für die Bearbeitung der Benutzer-Tabellen zuständig ist.
Aufgabenübersicht und Konfigurationsdateien
Die Aufgabenübersicht des Superbenutzers befindet sich in /etc/crontab. Die Syntax der Systemtabelle entspricht der Syntax von Vixie Cron, wobei in der sechsten Spalte der Benutzername angegeben wird, unter dem die Aufgabe ausgeführt wird:
# Запускается ежеминутно от пользователя vlad
* * * * * vlad /path/to/execDie Aufgabenlisten normaler Benutzer befinden sich in /var/cron/tabs/benutzername und verwenden eine gängige Syntax. Wird das crontab-Tool im Namen des Benutzers ausgeführt, werden genau diese Dateien bearbeitet.
Die Verwaltung der Benutzerlisten, die Zugriff auf crontab haben, erfolgt in den Dateien /var/cron/allow und /var/cron/deny, in die einfach der Benutzername in einer separaten Zeile eingetragen werden kann.
Erweiterte Syntax
Im Vergleich zu POSIX crontab enthält die Lösung von Paul Vixie mehrere sehr nützliche Modifikationen in der Syntax der Aufgabenlisten des Tools.
Eine neue Syntax für die Tabellen ist verfügbar: Beispielsweise können Wochentage oder Monate namentlich angegeben werden (Mon, Tue usw.):
# Запускается ежеминутно по понедельникам и вторникам в январе
* * * Jan Mon,Tue /path/to/execEs kann ein Schritt angegeben werden, in dem die Aufgaben gestartet werden:
# Запускается с шагом в две минуты
*/2 * * * Mon,Tue /path/to/execSchritte und Intervalle können kombiniert werden:
# Запускается с шагом в две минуты в первых десять минут каждого часа
0-10/2 * * * * /path/to/execIntuitive Alternativen zur gewöhnlichen Syntax werden unterstützt (reboot, yearly, annually, monthly, weekly, daily, midnight, hourly):
# Запускается после перезагрузки системы
@reboot /exec/on/reboot
# Запускается раз в день
@daily /exec/daily
# Запускается раз в час
@hourly /exec/dailyAusführungsumgebung von Aufgaben
Vixie cron ermöglicht es, die Umgebung der ausgeführten Anwendungen zu ändern.
Die Umgebungsvariablen USER, LOGNAME und HOME werden nicht nur vom Daemon bereitgestellt, sondern stammen aus der Datei. . Die Variable PATH erhält den Wert "/usr/bin:/bin" und SHELL den Wert "/bin/sh". Alle Variablenwerte außer LOGNAME können in den Benutzertabellen geändert werden.
Einige Umgebungsvariablen (insbesondere SHELL und HOME) werden von cron verwendet, um Aufgaben zu starten. So könnte die Verwendung von bash anstelle des Standard-sh für das Ausführen von Benutzertasks aussehen:
SHELL=/bin/bash
HOME=/tmp/
# exec wird mit bash in /tmp/ ausgeführt
* * * * * /path/to/execLetztendlich werden alle in der Tabelle definierten Umgebungsvariablen (die von cron verwendet werden oder für den Prozess erforderlich sind) an die gestartete Aufgabe übergeben.
Zum Bearbeiten von Dateien mit dem crontab-Utility wird der in der Umgebungsvariable VISUAL oder EDITOR angegebene Editor verwendet. Wenn diese Variablen in der Umgebung, in der crontab ausgeführt wurde, nicht definiert sind, wird „/usr/ucb/vi“ verwendet (ucb steht wahrscheinlich für University of California, Berkeley).
cron in Debian und Ubuntu
Die Entwickler von Debian und abgeleiteten Distributionen haben von Vixie cron 3.0pl1. Es gibt keine Unterschiede in der Syntax der Tabellen-Dateien, Benutzer sehen denselben Vixie cron. Zu den größten neuen Funktionen gehört die Unterstützung von , und .
Zu den weniger auffälligen, aber spürbaren Änderungen gehört die Positionierung der Konfigurationsdateien und der Aufgabenlisten.
Benutzerdefinierte Tabellen in Debian befinden sich im Verzeichnis /var/spool/cron/crontabs, während die Systemtabelle ebenfalls dort unter /etc/crontab zu finden ist. Spezifische für Debian-Pakete sind die Aufgabenlisten in /etc/cron.d abgelegt, von wo der cron-Daemon sie automatisch ausliest. Die Benutzerzugriffssteuerung erfolgt über die Dateien /etc/cron.allow und /etc/cron.deny.
Als Standard-Shell wird nach wie vor /bin/sh verwendet, wobei Debian einen kleinen POSIX-kompatiblen Shell , ohne das Lesen irgendeiner Konfiguration (im nicht interaktiven Modus) ausführt.
Der cron-Dienst wird in den neuesten Versionen von Debian über systemd gestartet, und die Startkonfiguration kann unter /lib/systemd/system/cron.service eingesehen werden. In der Dienstkonfiguration gibt es nichts Besonderes; jede feinere Aufgabenverwaltung kann über Umgebungsvariablen erfolgen, die direkt in der crontab jedes Benutzers deklariert werden.
cronie in RedHat, Fedora und CentOS
— Fork von Vixie Cron Version 4.1. Wie in Debian wurde die Syntax nicht geändert, aber Unterstützung für PAM und SELinux, Clusterbetrieb, File Monitoring mit inotify und andere Funktionen wurden hinzugefügt.
Die Standardkonfiguration befindet sich an den üblichen Orten: Die Systemtabelle findet man in /etc/crontab, Pakete speichern ihre Tabellen in /etc/cron.d, während Benutzertabellen in /var/spool/cron/crontabs landen.
Der Daemon wird unter systemd betrieben, die Dienstkonfiguration befindet sich unter /lib/systemd/system/crond.service.
In Red Hat-basierten Distributionen wird standardmäßig /bin/sh genutzt, wobei die Standard-Bash als interpretiert wird. Es ist wichtig zu beachten, dass beim Ausführen von Cron-Aufgaben über /bin/sh die Bash-Shell im POSIX-kompatiblen Modus gestartet wird und keine zusätzliche Konfiguration liest, da sie im nicht-interaktiven Modus arbeitet.
cronie in SLES und openSUSE
Die deutsche Distribution SLES und deren Derivat openSUSE verwenden ebenfalls cronie. Der Daemon läuft hier ebenfalls unter systemd, und die Dienstkonfiguration befindet sich unter /usr/lib/systemd/system/cron.service. Konfiguration: /etc/crontab, /etc/cron.d, /var/spool/cron/tabs. Als /bin/sh wird die gleiche Bash verwendet, die im POSIX-kompatiblen nicht-interaktiven Modus gestartet wird.
Aufbau von Vixie cron
Moderne Nachfolger von cron haben sich im Vergleich zu Vixie cron nicht radikal verändert, jedoch mit neuen Funktionen ausgestattet, die für das Verständnis der Programmprinzipien nicht notwendig sind. Viele dieser Erweiterungen sind unordentlich gestaltet und verwirren den Code. Der originale Quellcode von cron, wie er von Paul Vixie umgesetzt wurde, zu lesen, ist wahrlich ein Vergnügen.
Deshalb habe ich beschlossen, die Funktionsweise von cron am Beispiel der gemeinsamen Entwicklungslinie beider Varianten der cron-Programme — Vixie cron 3.0pl1 — zu erklären. Ich werde die Beispiele simplifizieren, indem ich komplizierende ifdef-Anweisungen weglasse und unwichtige Details auslasse.
Die Arbeit des Demons lässt sich in mehrere Phasen unterteilen:
- Initialisierung des Programms.
- Sammeln und Aktualisieren der Liste der zu startenden Aufgaben.
- Das Arbeiten des Hauptzyklus von cron.
- Starten der Aufgabe.
Schauen wir uns diese nacheinander an.
Initialisierung
Beim Start überprüft cron die Prozessargumente und richtet die Signalhandler für SIGCHLD und SIGHUP ein. Ersterer protokolliert das Ende eines Kindprozesses, letzterer schließt den Dateideskriptor der Protokolldatei:
signal(SIGCHLD, sigchld_handler);
signal(SIGHUP, sighup_handler);Der Cron-Daemon läuft im System immer als einziger, nur als Superuser und aus dem Hauptverzeichnis von Cron. Die folgenden Aufrufe erzeugen eine Lock-Datei mit der PID des Daemon-Prozesses, bestätigen, dass der Benutzer korrekt ist und ändern das aktuelle Verzeichnis auf das Hauptverzeichnis:
acquire_daemonlock(0);
set_cron_uid();
set_cron_cwd();Es wird ein Standardpfad festgelegt, der beim Starten von Prozessen verwendet wird:
setenv("PATH", _PATH_DEFPATH, 1);Der Prozess wird dann „daemonisiert“: Er erstellt eine Kindkopie des Prozesses mit einem Fork-Aufruf und eine neue Sitzung im Kindprozess (aufrufen von setsid). Im Elternprozess besteht keine weitere Notwendigkeit mehr – und er beendet die Ausführung:
switch (fork()) {
case -1:
/* kritischer Fehler und Beendigung der Ausführung */
exit(0);
break;
case 0:
/* Kindprozess */
(void) setsid();
break;
default:
/* Elternprozess beendet die Ausführung */
_exit(0);
}
Das Beenden des Elternprozesses gibt das Lock auf der Lock-Datei frei. Außerdem muss die PID in der Datei auf die des Kindprozesses aktualisiert werden. Danach wird die Aufgabenbasis gefüllt:
/* повторный захват лока */
acquire_daemonlock(0);
/* Заполнение БД */
database.head = NULL;
database.tail = NULL;
database.mtime = (time_t) 0;
load_database(&database);Danach geht Cron in die Hauptarbeitsroutine über. Doch bevor das geschieht, lohnt sich ein Blick auf die Auslastung der Aufgabenliste.
Sammlung und Aktualisierung der Aufgabenliste
Die Funktion load_database ist für das Laden der Aufgabenliste verantwortlich. Sie überprüft den Hauptsystem-crontab und das Verzeichnis mit den Benutzerdateien. Wenn sich die Dateien und das Verzeichnis nicht geändert haben, wird die Aufgabenliste nicht erneut geladen. Andernfalls wird mit der Bildung einer neuen Aufgabenliste begonnen.
Laden der Systemdatei mit speziellen Dateinamen und Tabelle:
/* если файл системной таблицы изменился, перечитываем */
if (syscron_stat.st_mtime) {
process_crontab("root", "*system*",
SYSCRONTAB, &syscron_stat,
&new_db, old_db);
}Laden der Benutzertabellen im Kreis:
while (NULL != (dp = readdir(dir))) {
char fname[MAXNAMLEN+1],
tabname[MAXNAMLEN+1];
/* Dateien mit Punkt müssen nicht gelesen werden */
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);
}
Danach wird die alte Datenbank durch die neue ersetzt.
In den obigen Beispielen stellt der Aufruf der Funktion process_crontab sicher, dass der Benutzer mit dem entsprechenden Dateinamen der Tabelle existiert (es sei denn, es handelt sich um einen Superuser), bevor load_user aufgerufen wird. Letztere liest die Datei zeilenweise:
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;
}
}Hier wird entweder eine Umgebungsvariable (Zeilen wie VAR=WERT) mit den Funktionen load_env / env_set gesetzt oder die Aufgabenbeschreibung gelesen (* * * * * /path/to/exec) mit der Funktion load_entry.
Das entry-Objekt, das von load_entry zurückgegeben wird, ist unsere Aufgabe, die in die gemeinsame Aufgabenliste eingefügt wird. In der Funktion wird eine ausführliche Analyse des Zeitformats durchgeführt, uns interessiert jedoch hauptsächlich die Erstellung der Umgebungsvariablen und der Startparameter der Aufgabe:
/* пользователь и группа для запуска задачи берутся из 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);Mit der aktuellen Aufgabenliste läuft die Hauptschleife.
Hauptschleife
Der ursprüngliche Cron aus Version 7 Unix arbeitete sehr einfach: Er las die Konfiguration in einer Schleife neu, führte Aufgaben für die aktuelle Minute mit Superuser-Rechten aus und schlief bis zum Beginn der nächsten Minute. Dieser einfache Ansatz erforderte auf alten Maschinen zu viele Ressourcen.
In SysV wurde eine alternative Version vorgeschlagen, bei der der Daemon entweder bis zur nächsten Minute, für die eine Aufgabe definiert ist, oder für 30 Minuten schlief. In diesem Modus wurden weniger Ressourcen für das Neulesen der Konfiguration und die Überprüfung der Aufgaben benötigt, aber es wurde unpraktisch, die Aufgabenliste schnell zu aktualisieren.
Vixie cron wurde so konfiguriert, dass die Aufgabenlisten einmal pro Minute überprüft werden. Glücklicherweise hatten die Standard-Unix-Rechner Ende der 80er Jahre deutlich mehr Ressourcen zur Verfügung.
/* первичная загрузка задач */
load_database(&database);
/* запустить задачи, поставленные к выполнению после перезагрузки системы */
run_reboot_jobs(&database);
/* сделать TargetTime началом ближайшей минуты */
cron_sync();
while (TRUE) {
/* выполнить задачи, после чего спать до TargetTime с поправкой на время, потраченное на задачи */
cron_sleep();
/* перечитать конфигурацию */
load_database(&database);
/* собрать задачи для данной минуты */
cron_tick(&database);
/* перевести TargetTime на начало следующей минуты */
TargetTime += 60;
}
Die Ausführung der Aufgaben erfolgt über die Funktion cron_sleep, die die Funktionen job_runqueue (Durchlauf und Ausführung der Aufgaben) und do_command (Ausführung jeder einzelnen Aufgabe) aufruft. Letztere Funktion verdient eine genauere Betrachtung.
Aufgabe starten
Die Funktion do_command ist im typischen Unix-Stil implementiert. Das bedeutet, dass sie für die asynchrone Ausführung der Aufgabe einen Fork durchführt. Der Elternprozess setzt die Ausführung der Aufgaben fort, während der Kindprozess sich mit der Vorbereitung des Aufgabenprozesses beschäftigt:
switch (fork()) {
case -1:
/* fork konnte nicht durchgeführt werden */
break;
case 0:
/* Kindprozess: versuchen wir vorsichtshalber erneut, den Hauptlock zu übernehmen */
acquire_daemonlock(1);
/* wechseln zur Erstellung des Aufgabenprozesses */
child_process(e, u);
/* nach Abschluss beendet der Kindprozess seine Arbeit */
_exit(OK_EXIT);
break;
default:
/* der Elternprozess setzt seine Arbeit fort */
break;
}Im child_process steckt eine Menge Logik: Er nimmt die Standardausgaben und Fehler für sich in Anspruch, um sie später per E-Mail zu versenden (falls in der Aufgabentabelle die Umgebungsvariable MAILTO angegeben ist) und wartet schließlich auf den Abschluss des Hauptprozesses der Aufgabe.
Der Aufgabenprozess wird durch einen weiteren Fork erzeugt:
switch (vfork()) {
case -1:
/* Bei einem Fehler wird die Arbeit sofort beendet */
exit(ERROR_EXIT);
case 0:
/* Der Kindprozess erstellt eine neue Sitzung, ein Terminal usw. */
(void) setsid();
/*
* дальше многословная настройка вывода процесса, опустим для краткости
*/
/* Verzeichnis, Benutzer und Gruppe ändern,
* der Prozess hat daher keine Superuser-Rechte mehr */
setgid(e->gid);
setuid(e->uid);
chdir(env_get("HOME", e->envp));
/* Start der eigentlichen Kommandoausführung */
{
/* Die Umgebungsvariable SHELL gibt den Interpreter an, der gestartet werden soll */
char *shell = env_get("SHELL", e->envp);
/* Der Prozess wird ohne die Umgebung des Elternprozesses gestartet,
* das heißt genau so, wie in der Benutzertasktabelle beschrieben */
execle(shell, shell, "-c", e->cmd, (char *)0, e->envp);
/* Ein Fehler — also hat der Prozess nicht gestartet? Beende die Arbeit */
perror("execl");
_exit(ERROR_EXIT);
}
break;
default:
/* Der Prozess läuft weiter: wartet auf Beendigung und Ausgabe */
break;
}Das ist im Wesentlichen der komplette cron. Einige interessante Details, wie z. B. die Berücksichtigung von entfernten Benutzern, habe ich weggelassen, aber die Hauptpunkte sind erklärt.
Nachwort
Cron — eine erstaunlich einfache und nützliche Software, die in den besten Traditionen der Unix-Welt entwickelt wurde. Sie macht nichts Überflüssiges, erfüllt jedoch ihre Aufgabe seit Jahrzehnten hervorragend. Das Durchsehen des Codes der Version, die mit Ubuntu geliefert wird, dauerte nicht länger als eine Stunde, und ich hatte dabei viel Freude! Ich hoffe, ich konnte dieses Erlebnis mit Ihnen teilen.
Ich weiß nicht, wie es Ihnen geht, aber ich finde es etwas traurig, dass modernes Programmieren mit seiner Neigung zur Überkomplexität und Überabstrahierung schon lange nicht mehr zu solch einer Einfachheit einlädt.
Es gibt viele moderne Alternativen zu cron: systemd-timers ermöglichen die Organisation komplexer Systeme mit Abhängigkeiten, während fcron flexiblere Möglichkeiten zur Regulierung des Ressourcenverbrauchs durch Aufgaben bietet. Aber persönlich habe ich immer mit den einfachsten crontab-Optionen auskommen müssen.
In jedem Fall, lieben Sie Unix, nutzen Sie einfache Programme und vergessen Sie nicht, die Man-Pages für Ihre Plattform zu lesen!
Quelle: habr.com
