Familie Cron -- Teil 2

Wem die Stunde schlägt

von Patricia Jung
 [ Dali: The_Disintegration_of_the_Persistence_of_Memory ]


So chaotisch Linuxer auch manchmal sein mögen -- meistens werkelt unbeachtet im Hintergrund ein Pünktlichkeitsfanatiker namens cron auf ihren Rechnern. Der erste Teil dieser Reihe (LM 08/98) stellte cron vor und erläuterte, wie ihn Linux-User in ihre Dienste stellen können. Im zweiten Teil wird gezeigt, wie er für die Systemadministration in Anspruch genommen werden kann, und das auch auf Maschinen, die nicht ständig laufen. Zudem werden ein paar Sicherheitsaspekte angesprochen und -- als Reminiszenz an jüngste Entwicklungen -- grafische Frontends für crontab begutachtet.

Es mag ganz nett sein, seinen Rechner dank cron als allmorgendlichen Wecker zu mißbrauchen -- doch gibt es auf einem Multiuser-/Multitaskingsystem noch viel langweiligere, immer wiederkehrende Aufgaben zu erfüllen. Wer möchte s chon die News des lokalen Newsservers jeden Tag per Hand expiren, die Datenbanken für locate oder man ständig auf dem Laufenden halten oder aufpassen müssen, daß die Platte nicht vor Logfiles überquillt? Abgesehen davon, daß Ruth normalerweise menschlich und somit vergeßlich ist, hätten wir kein Unix-System vor uns, gäbe es nicht die Möglichkeit, solche Aufgaben zu delegieren.

Die Zentrale

Die zentrale Anlaufstelle, um sich der lästigen Pflichten zu entledigen, heißt /etc/crontab. Wie in [1] erwähnt, kommt der Linux-Cron-Dämon aller minutenlang angestolpert, um indieser Datei und den persönlichen Crontabellen der User nachzuschauen, ob sich in diesen Aufgabenlisten ein Auftrag findet, den es in dieser Minute zu erledigen gilt. Während das Programm crontab bei privaten Crontabs zumeist die syntaktische Korrektheit der Aufträge für cron überwacht, liegt die Verantwortung für die systemweite Crontabelle allein bei Ruth. Sie wird ihren Lieblingseditor benutzen, um /etc/crontab zu editieren und dabei beachten, daß vor der Spalte mit der auszuführenden Kommandozeile noch die Benutzerin eingetragen werden muß, in deren Rolle cron schlüpfen soll, um den Auftrag auszuführen (Listing 1). Ein kleiner Wermutstropfen am Rande: Die in [1] vorgestellten @-Makros (siehe auch Tabelle 3) funktionieren mit einem Vanilla-Vixie-Cron lediglich in den persönlichen Crontabellen der User.

Listing 1: Beispiel einer systemweiten /etc/crontab

# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file.
# This file also has a username field, that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

42 6 * * * root run-parts /etc/cron.daily
47 6 * * 7 root run-parts /etc/cron.weekly
52 6 1 * * root run-parts /etc/cron.monthly

Obwohl in der Kommandospalte natürlich jedes halbwegs sinnvolle Kommando stehen kann, hat es sich eingebürgert, die systemweiten Cronjobs etwas systematischer zu ordnen. Jede Aktion, die einmal täglich ausgeführt werden soll, wird in ein Shellskript gepackt und z.B. in /etc/cron.daily (vgl. Tabelle 1) abgelegt (Ausführbarkeitsrechte nicht vergessen!), wöchentlich zu erledigende Aufgaben in /etc/cron.weekly usw. cron benutzt nun das Kommando run-parts, um alle Skripte im jeweiligen Verzeichnis abzuarbeiten. Diese Verfahrensweise wird von Debian, Red Hat und DLD verwendet. Caldera tanzt ein bißchen aus der Reihe, indem man statt dem Binary run-parts das Shellskript cronloop verwendet -- auch das DLDsche run-parts ist übrigens ein Skript. S.u.S.E. hingegen gefiel dieses Verzeichniskonzept bislang ganz und gar nicht: Bis Version 5.3 ruft /etc/crontab hier das Skript /root/bin/cron.daily auf, das täglich die zu erledigenden distributionsspezifische Aufgaben herunterrattert und zu guter Letzt auch noch das Skript /root/bin/daily.local für lokale Problemstellungen abarbeitet. Als sei das nicht schon unübersichtlich genug, wird zudem noch fröhlich und unsystematisch in /etc/crontab rumgewurstelt. Ab Version 6.0 schließt man einen Kompromiß und legt ebenfalls die besagten Verzeichnisse an. Während run-parts andernorten als universell einsetzbarer, von cron unabhängiger Skriptstarter konzipiert ist, werden die in den Verzeichnissen befindlichen Skripte bei S.u.S.E. 6.0 von einem einzigen spezialisierten Skript namens /usr/lib(sic!)/cron/run-crons aufgerufen.

Die globalen Verzeichnisse für Cron-Skripte haben folgenden Vorteil: Viele Programmpakete ziehen für cron prädestinierte Aufgaben nach sich -- ein Newsserver möchte einmal am Tag News vom Feed holen und alte Postings expiren, die System-Log-Utilities syslogd und klogd sollten sichergehen können, daß Logdateien einmal die Woche gestutzt oder besser rotiert werden etc. Eine clevere Installationsroutine sorgt folglich dafür, daß mit der Installation auch gleich der passende Cronjob aufgesetzt wird. Schriebe sie einfach eine Zeile in /etc/crontab, sähe es da bald sehr unübersichtlich aus, und besonders geschickt deinstalliert sich so etwas auch nicht. Abgesehen davon, daß sich nicht immer alles halbwegs übersichtlich mit einer Zeile ausdrücken läßt. Also kopiert oder generiert die Installationsroutine ein nettes Shellskript, das Ruth gegebenenfalls auch anpassen kann, und legt es im passenden Verzeichnis ab.

Tabelle 1: Wo gehören systemweite Cron-Skripte hin?
Wann auszuführen? stündlich täglich wöchentlich monatlich zu anderen Zeiten
Caldera Open Linux 1.2--1.3
/etc/cron.d/Hourly/
/etc/cron.d/Daily/
/etc/cron.d/Weekly/
/etc/cron.d/Monthly/
/etc/cron.d/lib/
Debian 1.3.1 --
/etc/cron.daily/
/etc/cron.weekly/
/etc/cron.monthly/
--
Debian 2.0 --
/etc/cron.daily/
/etc/cron.weekly/
/etc/cron.monthly/
/etc/cron.d/
DLD 6.0
/etc/cron.hourly/
/etc/cron.daily/
/etc/cron.weekly/
/etc/cron.monthly/
--
Red Hat 4.2--5.2
/etc/cron.hourly/
/etc/cron.daily/
/etc/cron.weekly/
/etc/cron.monthly/
--
S.u.S.E. 5.2--5.3 --
/root/bin/cron.daily
(Skript für distributionsspezifische Jobs),
/root/bin/daily.local
(lokale Anpassungen und Erweiterungen)
-- -- --
S.u.S.E. 6.0
/etc/cron.hourly/
/etc/cron.daily/
/etc/cron.weekly/
/etc/cron.monthly/
--

Sicherheitsinspektion

Einen Nachteil hat die Verfahrensweise natürlich auch: Wenn der Newsserver Tag für Tag News holen will, soll er das gefälligst nicht als Ruth, sondern als weniger privilegierter Benutzer news o.ä. tun. Die locate-Datenbank soll zwar auch täglich, aber von nobody upgedatet werden. Und obwohl /etc/crontab eine so praktische Spalte für die Benutzerin, die den Cronjob ausführen soll, enthält, können wir da nur root eintragen, weil weder news noch nobody in der Lage wären, den jeweils anderen Job zu erledigen. So verletzen wir die Sicherheitsregel, Aufgaben immer nur durch Benutzer mit den minimal nötigen Privilegien ausführen zu lassen.

Natürlich werden die Skripte für die beiden Aufgaben jeweils ein su news bzw. su nobody enthalten, aber bis dahin hat root schon viel zu viele unnötige Dinge mit höchsten Privilegien getan, die unter Umständen von Angreifern ausgenutzt werden können. Das Problem ist, daß man oftmals nicht weiß, ob vom Skript aufgerufene Programme sicher sind oder nicht. Oberstes Gebot ist folglich, im Skript soviele Sicherheitsbarrieren wie möglich einzubauen, z.B.

Nun ist auch crontab als suid-root-Programm nicht gerade ein Waisenkind, was Systemsicherheit betrifft. So stellt sich die Frage, wozu cron überhaupt root-Privilegien braucht, wenn er doch sehr oft Aufgaben in Vertretung ausführt, die die jeweilige Benutzerin selbst unprivilegiert gestartet hätte, wäre sie nicht so erschreckend faul. Wenn beispielsweise der Newsserver News fetcht oder expiret, benötigt er dazu keinesfalls uneingeschränkten Zugriff aufs System. Und wenn cron nicht mehr mit root-Rechten liefe, käme auch crontab ohne suid-root-Bit aus.

Hier setzt Ian Jacksons userv [3] an. Anstatt alle denkbaren Programme, deren Aufgaben gewisse Privilegien erfordern (cron, lpr, man, mount, MTAs etc.), ohne Unterschied mit root-Rechten laufen zu lassen (und damit viele potentielle Sicherheitslücken zu haben, da nun einmal nicht jede den Code jedes als root laufenden Programms darauf abklopfen kann, daß er auch garantiert sicher ist), treten sie in Kontakt mit userv, das dafür sorgt, daß die Programme mit exakt den nötigen Privilegien gestartet werden: Auf Userseite liest ein unprivilegiertes crontab die Benutzercrontabelle ein und bittet userv darum, cron Bescheid zu geben. cron, der mit den Rechten eines dafür zuständigen Benutzers läuft, führt Buch über die verschiedenen Termine und bittet seinerseits userv wochentags um 8.45 Uhr, Lieschens Weckruf als Lieschens Prozeß aufzurufen, täglich um 2.45 Uhr den Newsfetch mit den Rechten der Benutzerin news zu starten etc. Jetzt braucht man sich nur noch um die Sicherheit von userv kümmern, nicht mehr um die mehrerer Programme im einzelnen.

Unglücklicherweise gibt es für cron als userv-Applikation noch keine implementierte Lösung, sondern nur einen Draft. Im Auge behalten sollte man die Entwicklung im Interesse der Systemsicherheit auf alle Fälle.

Dabeisein ist alles

cron-Dämonen wie Vixie- oder Dillons cron gehen als Unix-Urgesteine ohne Wimpernzucken davon aus, daß der Rechner kontinuierlich durchläuft: Ist die Maschine zu einem Zeitpunkt down, wo ein Cronjob anfällt, fällt der schlichtweg unter den Tisch. So neumodische Sachen wie Linuxworkstations, die im heimischen Schlafzimmer in der Nacht besser Strom sparen und/oder die Nachtruhe nicht stören sollen, passen da nicht ins Konzept. Spätestens dann, wenn locate ein definitiv vorgestern installiertes Tool nicht findet, weil die Kiste zum Zeitpunkt des cron-gesteuerten updatedb-Laufs nicht an war, wird die gemeine Hobby-Sysadmine alle crons der Welt mehr oder weniger leise verfluchen.

Ein bißchen voreilig, wie ein Blick auf [4] beweist: Mit hc-cron, anacron und ucrond schicken sich gleich drei Dämonen an, den Crondienst auch auf Maschinen hoffähig zu machen, die sich nicht am "Meine Uptime ist länger als Deine"-Wettstreit beteiligen.

Der Oldie

Ursprünglich ein nur als Debian-Paket erhältliches Perlskript, das in /etc/anacrontab spezifizierte Jobs zu bestimmten Zeiten nach dem Booten abarbeitete, ist anacron mittlerweile zum C-Programm mutiert. anacron ersetzt den "normalen" Cron-Dämonen nicht, sondern ergänzt ihn vielmehr. Das hat den Vorteil, daß man den gewohnten Cron-Dämonen nicht zu ersetzen braucht, allerdings muß root nun zwei Crontabellen parallel verwalten und sich entsprechend Gedanken machen, welche Jobs sie in beide oder jeweils nur eine Tabelle einträgt. anacron ist zudem ausschließlich für den administrativen Gebrauch bestimmt: Die privaten Crontabs der Benutzer bleiben komplett außen vor.

Dreh- und Angelpunkt bei anacron ist die Datei /etc/anacrontab (Listing 2). Auf den ersten Blick scheint sie sich nicht grundlegend von einer "normalen" /etc/crontab zu unterscheiden, doch der Schein trügt: Zunächst fällt auf, daß kein Benutzer spezifiziert ist, mit dessen UserID der entsprechende Anacronjob abgesetzt werden soll. Alle Jobs laufen somit mit root-Rechten, was, wie oben bemerkt, kein besonders sicherheitsbewußter Ansatz ist. Außerdem "fehlen" die Spalten 3--5. Das rührt daher, daß anacron ein etwas vages Zeitschema benutzt: Jobs können lediglich aller x Tage ausgeführt werden (Tabelle 2). Wenn anacron z.B. durch ein Initskript aufgerufen wurde und seit der letzten Abarbeitung eines Jobs mindestens x Tage vergangen sind, wird er y Minuten nach anacron-Start ausgeführt. Hat anacron alle anfallenden Jobs abgearbeitet, beendet er sich, und das Spiel kann durch erneuten anacron-Aufruf zu beliebiger Zeit von vorn beginnen.

Woher weiß anacron jedoch, wann einer seiner Vorgänger einen Job das letzte Mal am Wickel hatte? In Spalte 3 wird ein sogenannter Job-Identifikator festgelegt. Er darf außer Slashes ("/") alle druckbaren ASCII-Zeichen enthalten. In erster Linie benötigt anacron ihn, um seinen Nachfahren mitzuteilen, wann ein Job das letzte Mal ausgeführt wurde: Das entsprechende Datum wird in der Notation jjjjmmtt in einer Datei im Spoolverzeichnis /var/spool/anacron gespeichert, die den Namen des Job-Identifikators trägt. (Der Name des Spoolverzeichnisses läßt sich übrigens genau wie der Name der Anacrontabelle im Makefile ändern.) Da der Job-Identifikator bei allen jobspezifischen Mails mit angegeben wird, ist er auch für die Systemadministratorin nicht ganz uninteressant.

Listing 2: anacrons Schaltzentrale /etc/anacrontab

# /etc/anacrontab: configuration file for anacron

# See anacron(8) and anacrontab(5) for details.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# These entries are useful for a Debian system.
1       5       cron.daily      run-parts /etc/cron.daily
7       10      cron.weekly     run-parts /etc/cron.weekly
30      15      cron.monthly    run-parts /etc/cron.monthly

Tabelle 2: Die Syntax von /etc/anacrontab
x y Job-Identifikator Kommando
Alle wieviel Tage soll der Job ausgeführt werden? Wieviel Minuten sollen nach dem Start von anacron vergehen, bis der Job ausgeführt wird? Wie soll der Job heißen? Was soll getan werden?

anacrons Verhalten läßt sich mit Hilfe von Kommandozeilenoptionen modifizieren. Sehr nützlich ist beispielsweise das Flag -f ("force"), das veranlaßt, daß alle in der Anacrontabelle verzeichneten Jobs unabhängig von ihren Zeitstempeln ausgeführt werden, oder sein Antagonist -u, der lediglich die Zeitstempel neu setzt, aber keinen Job wirklich ausführt. Weitere Optionen lassen sich der Manpage zu anacron [5] entnehmen.

Der Überflieger

Einen völlig anderen Ansatz als anacron wählt hc-cron. Hierbei handelt es sich quasi um einen aufgebohrten Vixie-cron, und es lohnt sich tatsächlich, letzteren gegen hc-cron auszutauschen. Nicht nur, weil er es ermöglicht, Cronjobs, die anfallen, wenn der Rechner down ist, später doch noch auszuführen, sondern auch, weil hier seit Version 0.11 die in [1] vorgestellten undokumentierten @-Makros für User-Crontabellen genauso wie für die systemweite /etc/crontab korrekt funktionieren und zudem ordentlich dokumentiert sind (Tabelle 3).

Tabelle 3: Proprietäre Crontab-Erweiterungen für Vixie-Cron (funktionsfähig ab hc-cron 0.11)
Makro entspricht
@reboot
beim Reboot
@yearly
0 0 1 1 *
@annually
wie @yearly
@monthly
0 0 1 * *
@weekly
0 0 * * 1
@daily
0 0 * * *
@midnight
wie @daily
@hourly
0 * * * *

Wer einfach nur die Vixie-Cron- gegen die hc-cron-Binaries austauscht (und sich [6] nicht zu Gemüte führt), den Rechner herunter- und am nächsten Tag wieder hochfährt, wird sich zunächst einmal wundern, warum kein einziger in der Zwischenzeit fälliger Cronjob nachgeholt wird. hc-cron obläßt es der Benutzerin, ob sie einen Job nachholen will oder ob er verfallen darf. Eine Crontabelle -- sei es /etc/crontab oder eine benutzerseitige - in "normaler" Vixie-Cron-Syntax wird eben auch so behandelt, als gäbe es keine hc-cron-Erweiterungen für nicht kontinuierlich laufende Systeme.

Wie sagt man hc-cron nun eigentlich, welche Jobs nachgeholt werden sollen? Zu diesem Zweck verpaßt man einem Jobkommando ein einleitendes Flag (Tabelle 4). Das hat zwar den Nebeneffekt, daß "normale" Crondämonen die entsprechenden Kommandos nicht mehr finden (*echo gibt es nunmal nicht als Shellkommando), aber alles kann man halt nicht auf einmal haben...

Tabelle 4: Ob hc-cron einen Cronjob nachholt, wird durch ein Flag direkt vor dem Jobkommando bestimmt.
Flag Bedeutung
keins Kommando wird nur ausgeführt, wenn cron zur spezifizierten Zeit auch läuft.
*
Kommando wird genau so oft nachgeholt, wie es während der Downtime von cron aufgerufen worden wäre.
!
Kommando wird nur einmal nachgeholt, egal, wie oft es während der Downtime hätte ausgeführt werden sollen.
\
Escape-Zeichen. Erlaubt es, auch Kommandos auszuführen, die tatsächlich mit * oder ! beginnen.

Listing 3 zeigt drei Beispiele, bei denen eine unterschiedliche Behandlung während der Downtime sinnvoll ist: Wenn man seine Maschine erst nach dem Aufstehen bootet, hat man den liebevollen Weckruf mit Musik dienstags bis freitags um 7.25 Uhr vermutlich eh schon verpaßt und muß sich nicht extra bedudeln lassen. Ärger mit dem Vermieter kann es allerdings ersparen, wenn man sich nach dem mehrtägigen Besuch bei der Freundin erinnern läßt, daß am 1. des Monats die Miete fällig war und anhand der Anzahl eintrudelnder Mails auch gleich mitbekommt, wie lange man schon im Rückstand ist. Sein Homeverzeichnis wird man dagegen nur einmal täglich von leeren, core- und Backupdateien~ säubern wollen, egal, wie lange der Rechner tatsächlich down war.

Listing 3: Beispiel für eine persönliche Crontabelle mit hc-cron-Erweiterungen

# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/tmp/crontab.1514 installed on Wed Jan 6 21:44:50 1999)
# (Cron version -- $Id: cron2_red1.html,v 1.4 1999/03/06 22:44:46 lm Exp $)

# Der Audiowecker
25 7 * * Tue-Fri (/home/trish/bin/mix vb=50; /usr/bin/mpg123 -b 2048 -z `find /music -name \*.mp3`) > /dev/null 2>&1
# nach 10 Minuten Gedudel Wecker ausschalten
35 7 * * Tue-Fri killall mpg123

# Der Mietmahner
5 10,20 1 * * *echo -e "Miete schon ueberwiesen?\n\n\tDein cron"

# Der Aufraeumer
@midnight !find $HOME -name core -o -name \*~ -type f -o -empty -type f | xargs rm  

Der Revoluzzer

Der dritte im Bunde, ucrond, ist eine vollständige Neuimplementation eines Crondämonen und hat -- wie könnte es anders sein -- wieder eigene Vorstellungen davon, wie Crontabellen auszusehen haben. Zwar benutzt auch er als Grundstock die kanonische Syntax, allerdings dürfen hier zwischen den Zeitangaben und dem Kommando optional Parameter stehen, die die Behandlung des Jobs modifizieren (Tabelle 5).

Tabelle 5: Ob systemweite oder persönliche Crontabelle - bei ucrond kann mit der optionalen Spalte sechs die Ausführung eines Cronjobs beeinflußt werden.
Flag Bedeutung
keins Entspricht der kanonischen Syntax.
-B
Statt sofort zur angegebenen Zeit ausgeführt zu werden, landet ein so gekennzeichneter Job in einer FIFO-Queue, die sukzessive abgearbeitet wird. Verteilt die Systemlast bei mehreren gleichzeitig anfallenden Jobs.
-D
Falls zur spezifizierten Zeit das System down war (bzw. kein Crondämon lief), wird ein mit diesem Flag versehener Job sofort nach dem Restart nachgeholt.
-U=userID
ermöglicht in der rootschen Crontabelle die Angabe der UserID, unter der der Job ausgeführt werden soll.
-S=subject
legt das Subject für den Mail-Output des Jobs fest. Achtung: Es sind darin keine Leerzeichen oder Tabs erlaubt!

Verwirrend wird es, möchte man seine Zeitangaben nicht in absoluter lokaler Zeit, sondern - ähnlich wie bei anacron - relativ zur Uptime seines Systems angeben. In diesem Fall verschiebt sich nämlich die Bedeutung der ersten fünf Zeitspalten: Statt hintereinander Minute(n) Stunde(n) Tag(e) Monat(e) Wochentag(e) zu bezeichnen, schreibt man dann in die erste Spalte ein großes U und addiert die folgenden Minuten, Stunden, Tage und Wochen, um das Zeitintervall festzulegen, in dem, vom letzten Reboot gerechnet, der Cronjob ausgeführt werden soll.

Bevor wir uns das Ganze an der in Listing 4 gezeigten Beispiel-Crontab von root anschauen, gilt es, eine weitere Gewohnheit aus der gewohnten Cron-Welt abzulegen: ucrond kennt die Unterscheidung zwischen der nur manuell zu ändernden, systemweiten /etc/crontab und der mit crontab verwalteten persönlichen Crontabelle von root im Spoolverzeichnis nicht mehr: Ruth kümmert sich mit Hilfe von crontab nur noch um eine Datei im Spoolverzeichnis, deren Name im Makefile festgelegt wurde (default: crontab.main) und die natürlich auch ein Link auf /etc/crontab sein kann. Eine für Vixie-(hc-) oder Dillons Cron erstellte /etc/crontab muß dazu allerdings etwas umgeschrieben werden: Am besten setzt man vor die in der sechsten Spalte (vgl. Listing 1) stehenden UserIDs einfach ein U=, wobei U=root auch ganz weglassen werden kann. Die drei Runparts-Einträge in Listing 4 demonstrieren das.

Im nächsten Eintrag bekommt der Benutzer news etwas zu tun: Unter seiner UserID sollen täglich um 0.46 Uhr veraltete Newsbeiträge auf dem lokalen Newsserver (hier: leafnode) gelöscht werden. Das soll natürlich auch dann passieren, wenn um 0.46 Uhr kein Crondämon lief, z.B., weil der Rechner aus war (-D). Weil diese Aufgabe jedoch nicht sooo dringend ist, daß sie unbedingt sofort nach dem Restart erfüllt werden muß, setzen wir sie mit der Option -B in die First-In-First-Out-Warteschlange. Sollten weitere Jobs mit -DB bezeichnet sein, würden die jetzt nicht alle auf einmal das System belasten, sondern einer nach dem anderen die Last zeitlich verteilen.

Fehler bei der Abarbeitung des Jobs und Meldungen auf der Standardausgabe werden wie üblich an die Besitzerin der Crontabelle gemailt (die Adressatin läßt sich auch bei ucrond durch Setzen der Umgebungsvariablen MAILTO ändern [1]), dank des Flags -S sogar mit dem aussagekräftigen Subject "leafnode_expiration_report". So nett dieses Feature ist: Das Subject darf auf keinen Fall Leerzeichen oder Tabulatoren enthalten, denn ucrond interpretiert alles nach einem dieser Whitespacezeichen als Kommando -- es sei denn, es handelt sich um einen durch ein Minus eingeleiteten String. Da hilft auch alles Quoten nichts.

Beim Auftrag für Benutzer nobody wird es dann spannend: Das U in der ersten Spalte kennzeichnet, daß wir uns hier nicht mit absoluten, sondern mit Zeitangaben relativ zur Uptime des Systems zu tun haben. Alle 0 Minuten, 24 Stunden, 0 Tage und 0 Monate nach dem Start des Crondämonen wird nobody die locate-Datenbank aktualisieren. Genau im selben Zeitintervall (120 Minuten plus 22 Stunden sind in der Summe ebenfalls ein Tag) soll auch unter User trishs Regie eine Liste der auf dem System verfügbaren Mp3-Musikstücke erstellt werden, allerdings reiht sich dieser Job mit -B freiwillig in die FIFO-Warteschlange ein.

Listing 4: Beispiel für die Crontabelle der Systemverwalterin bei der Benutzung von ucrond

# Runparts wie gewohnt ausfuehren
42 6 * * * U=root  run-parts --report /etc/cron.daily
47 6 * * 7         run-parts --report /etc/cron.weekly
52 6 1 * *         run-parts --report /etc/cron.monthly   

# News expiren lassen
46 0 * * * -DB -U=news -S=leafnode_expiration_report /usr/sbin/texpire

# Die locate-Datenbank vom Systemstart an gerechnet aller 24 Stunden updaten
U 0 24 0 0 nice -U=nobody updatedb --prunepaths='/tmp /var/tmp /usr/tmp /cdrom /proc'

# Musikliste aktualisieren
U 120 22 0 0 -U=trish -B find /music -name \*.mp3 > /music/music.list

Ruth könnte ihn (und alle anderen auf die crond-Uptime bezogenen Jobs) sowie alle wegen ihrer -D-Kennzeichnung nach einen Restart nachzuholenden Prozesse jedoch auch auf die FIFO-Queue zwingen, wenn sie crond mit dem Flag -b aufruft. Ein Blick in ucrond-Manpage [7] verrät weitere Kommandozeilenoptionen: Mit -r gestartet, merkt sich ucrond einen Job, bei deren Ausführung er beendet wurde und arbeitet ihn nach dem Restart noch einmal richtig ab. Jobs, die noch in der Queue waren, als crond sterben mußte, werden dabei leider nicht mit berücksichtigt, ebensowenig Jobs, die nicht mit der Option -D oder als U markiert wurden.

Mindestens ebenso interessant sind die beiden Optionen -n bzw. -m. Beiden folgt der Default-Nice-Level, mit dem Prozesse aus der root- bzw. den User-Crontabs gestartet werden. crond -n 9 -m 19 sorgt beispielsweise dafür, daß die Cronjobs den normalen Systembetrieb möglichst wenig stören: Die Jobs der nichtprivilegierten Benutzer(innen) bekommen allerniedrigste Priorität (19), während die Jobs aus der von Ruth verwalteten Crontabelle mit Nicelevel 9 zwar allen nicht-geniceten Prozessen den Vortritt lassen, sich aber immer noch mehr an der zu verteilenden CPU-Zeit bedienen dürfen als die übrigen Cronjobs. Dennoch sollte Ruth diese Optionen mit Bedacht einsetzen: Wenn der Mp3-Wecker aus einer User-Crontab bei Nicelevel 19 mangels Prozessorzeit statt Musik nur noch knackende Geräusche von sich gibt, mag das eine Garantie für's Aufstehen sein - beheben kann es außer Ruth niemand mehr, denn Prioritäten darf nur sie erhöhen.

Auch hinter den Kulissen arbeitet ucrond ein wenig anders als beispielsweise Vixie-Cron. So verwendet sein crontab statt temporären Files zum Zwischenspeichern der zu editierenden Crontabellen eine Named Pipe im Spoolverzeichnis - vom Sicherheitsaspekt her sicher keine schlechte Idee.

Einen großen Nachteil hat die ucrontab-Implementierung gegenüber Vixie-crontab: Während letztere pedantisch Syntaxverletzungen und unsinnige Zeitangaben bemängelt, übernimmt erstere ohne Murren die haarsträubendsten Einträge. Auch, wenn ucrond Jobs mit unsinnigen Zeitangaben lediglich stillschweigend ignoriert, kann ein kleiner Vertipper ganz schön Ärger machen: Wer denkt schon als erstes daran, daß man sich vor ein paar Wochen in einem Cronfile vertippt hat, wenn die Logdateien die Partition sprengen, locate nur noch veraltete Einträge ausspuckt und der Geburtstag der Liebsten gestern war?

Mausfreunde

Nun gehört das Erstellen von Cron-Einträgen nicht gerade zu den Dingen, bei denen man automatisch in Form bleibt, weil man sie täglich mindestens zweimal tut. Da schleicht sich ein Fehlerchen in der Zeitangabe oder bei der Syntax nur all zu leicht ein. Und manchen Einsteiger mögen die syntaktischen Hürden derart abschrecken, daß er gänzlichst auf dieses nützliche Werkzeug verzichtet. Grafische crontab-Frontends drängen sich als Ausweg aus dem Dilemma förmlich auf. Und dafür, daß es im Frühjahr letzten Jahres gerade erste Ansätze für Programme gab, mit denen man persönliche Crontabellen per Mausklick erstellen kann, hat sich auf diesem Gebiet einiges getan.

Mit vcron [8] hilft ein Tcl/Tk-8.0-basiertes Interface zu crontab und at, die syntaktischen Tücken einer Crontabelle oder eines At-Jobs elegant zu umgehen (Abbildung 1). Allerdings sollte man sich dabei strikt an die in [1] vorgestellte, kanonische Syntax halten: vcron hält die Benutzerin in der aktuellen Version 1.3 zwar nicht davon ab, dem Kommando die ucrondsche sechste Spalte oder hc-cron-spezifische Flags voranzustellen; mit einem ! eingeleitete Kommandos, wie hc-cron sie verwendet, lassen sich jedoch nicht modifizieren. Daß vcron mit den @-Makros aus Tabelle 3 nichts anfangen kann oder über ucron-spezifische, durch U eingeleitete Zeitangaben stolpert, ist sicher verzeihlich (oder im Sinne der reinen Syntax-Lehre sogar zu begrüßen), daß er jedoch auch keine Möglichkeit bietet, Umgebungsvariablen zu setzen, vermißt man dann doch ein wenig. Allerdings sollte man dem Autor keinen Strick daraus drehen, daß er sich auf die Standard-Cron-Syntax beschränkt. Das von vcron nicht unterstützte Einfügen von Kommentaren gehört allerdings schon zum Standardrepertoire. Daß vcron beim Modifizieren eines Jobs aus doppelten Anführungszeichen im Kommando geschweifte Klammern macht oder sich weigert, Pipes zu parsen, wenn sie nicht von Leerzeichen umrahmt sind, ist jedenfalls nicht ganz im Sinne des Erfinders...


Abb. 1: Mit Visual Cron lassen sich einfache Crontabellen im Rahmen der Standard-Cron-Syntax zusammenklicken.

kcrontab [9], der Crontab-Manager des KDE-Projekts (Abbildung 2), hat sich mittlerweile auch zu einem mit Abstrichen brauchbaren crontab-Frontend gemausert und liegt subjektiv besser in der Hand, äh, Maus als vcron. Zwar lassen sich in Version 0.22 (noch) keine Umgebungsvariablen setzen, dafür bietet es die Möglichkeit, Kommentare einzufügen. kcrontab parst und verarbeitet Cronjobs mit und ohne hc-cron-spezifische Erweiterungen ohne Beanstandungen, die ucronsche sechste Optionsspalte wird ebenfalls als Teil der Kommandospalte aufgefaßt. Allerdings sollte man es dringend vermeiden, damit Crontabellen mit Vixie-Cron-spezifischen @-Makros zu editieren: Diese Einträge werden nämlich vollständig zerschossen. Auch bei mit einem U eingeleitete ucron-Einträge sollte man möglichst so lassen, wie sie sind: Beim Editieren stürzt kcrontab leider ab. Aber genau wie bei vcron gilt natürlich die Fairneß-Regel, daß die Unterstützung nichtkanonischer Syntax nur dann auch gefordert werden darf, wenn sie explizit versprochen wird.


Abb. 2: Bei kcrontab muß man ob seiner Jugend (Version 0.22) noch mit einigen Eskapaden rechnen.

Bleibt die Wiederauferstehung eines Scheintoten zu vermelden: Vom alten Scheme-Codes des Crontab-Frontend-Veteranen cromagnon (siehe [1]) ist in der neuen Version 0.1 nichts mehr übriggeblieben, und da der GNOME-Desktop mittlerweile benutzbar ist, gibt es für seine Reimplementierung in C immerhin eine sinnvolle Einsatzmöglichkeit. Ohne GNOME ist mit ihm leider nur unter größten Klimmzügen etwas anzufangen.

Wie für seinen Bruder aus dem K-Lager sind Variablen für CroMagnon kein Thema; Kommentare dagegen lassen sich nicht nur, sondern müssen sogar in der Spalte Description eintragen werden. Anhand der von ihm generierten, mit #CroMagnon: eingeleiteten Kommentarzeilen erkennt CroMagnon nämlich, ob er sich zutraut, den in der folgenden Crontab-Zeile stehenden Eintrag zu modifizieren. Alle nicht derart gekennzeichneten Cronjobs sind für Cromagnon schlichtweg tabu -- was einerseits ärgerlich ist, weil die mühsam von Hand erstellte Crontabelle sich nicht ändern läßt. Andererseits hat das den Vorteil, daß ucrond-typische Einträge, bei denen er sonst abstürzt, Vixie-Cron-Makros, die er verstümmelt, und hc-cron-spezifische Erweiterungen, die keine Probleme bereiten, gekapselt bleiben. Mögen sich hier erstaunliche Parallelen zu kcrontab ergeben -- im Augenblick hat Cromagnon noch einen ganz gewaltigen Nachteil: Der GNOME-Crontab-Manager erzeugt persönliche Crontabellen bislang nur. Für ihren Weg ins Spoolverzeichnis muß man derzeit noch selbst Hand anlegen: Die generierte Crontab gilt es abspeichern und mit crontab <Dateiname> zu implementieren.


Abb. 3: Blackbox: CroMagnon erkennt nur selbstgeschriebene Crontabeinträge.

Fazit: GUIs für crontab mögen Einsteigern helfen, die doch etwas gewöhnungsbedürftigen Zeitangaben für einfache Cronjobs richtig zu setzen -- für anspruchsvollere Zeitgenossen stecken sie einfach noch zu sehr in den Kinderschuhen, und zur Verwaltung von /etc/crontab ist Ruth sowieso auf den persönlichen Lieblingseditor angewiesen.

Infos

[1] Patricia Jung: Linux-Magazin 1998, 8, 63
[2] Sourcen, Manpages und READMEs zu cron(d) und crontab
[3] http://www.chiark.greenend.org.uk/~ijackson/userv/spec.html
[4] Sunsite-Archiv zu cron-Fragen: ftp://sunsite.unc.edu/pub/Linux/system/daemons/cron/
[5] Manpages zu anacron (8) und anacrontab (5)
[6] hc-cron-Manpages zu cron (8), crontab (1) und crontab (5)
[7] ucrond-Manpages zu crond (8) und crontab (1)
[8] http://www.linux-kheops.com/pub/vcron/vcronGB.html
[9] ftp://ftp.kde.org/pub/kde/unstable/apps/admin/kcrontab*
[10] http://www.andrews.edu/~aldy/cromagnon.html

Die Autorin

Patricia Jung findet seit Kernel 1.2.12, daß Linux das perfekte Betriebssystem für Mädchen ist (Spätestens seit Linus Version 2.0 weiblich ist, sollte das eigentlich auch der weiblichen Hälfte der Menschheit so langsam klar werden *hoff*...). Patricia ist zu erreichen unter pjung@linux-magazin.de.

Copyright © 1999 Linux-Magazin Verlag