15.3 Systemadministration
Die Systemadministration dürfte wohl eines der Hauptgründe sein, weshalb Sie sich entschieden haben, die Shellscript-Programmierung zu erlernen. Zur Systemadministration gehören u. a. zentrale Themen wie die Benutzer- und Prozessverwaltung, Systemüberwachung, Backup-Strategien und das Auswerten bzw. Analysieren von Log-Dateien. Zu jedem dieser Themen werden Sie ein Beispiel für die Praxis kennen lernen und, falls das Thema recht speziell ist, auch eine Einführung.
15.3.1 Benutzerverwaltung
Plattenplatzbenutzung einzelner Benutzer auf dem Rechner
Wenn Sie einen Rechner mit vielen Benutzern verwalten müssen, so sollte man dem einzelnen Benutzer auch eine gewisse Grenze setzen, was den Plattenverbrauch betrifft. Die einfachste Möglichkeit ist es, die Heimverzeichnisse der einzelnen User zu überprüfen. Natürlich schließt dies nicht nur das /home-Verzeichnis ein (auch wenn es im Beispiel so verwendet wird). Am einfachsten sucht man in entsprechenden Verzeichnissen nach Dateien, die einen bestimmten Benutzer als Eigentümer haben, und addiert die Größe einer jeden gefundenen Datei.
Damit auch alle Benutzer erfasst werden, deren User-ID größer als 99 ist, werden sie einfach alle aus /etc/passwd extrahiert. Die Werte zwischen 1 und 99 sind gewöhnlich den System-Daemons bzw. dem root vorbehalten. Ein guter Grund übrigens, dass Sie, wenn Sie einen neuen User anlegen, die UID immer über 100 wählen.
Hinweis Die meisten Systeme nutzen inzwischen auch UIDs für die User, die größer als 1000 sind. Diese Angabe kann von System zu System variieren. Viele Systeme verwenden als »uid_start« auch den Wert 1000. Es könnte also sein, dass der Wert 100 – wie hier verwendet – zu niedrig ist. Allerdings sollte es für Sie wohl kein Problem darstellen, diesen Wert im Script zu ändern.
|
Das folgende Shellscript analysiert also den Plattenplatzverbrauch einzelner Benutzer (im Beispiel beschränken wir uns auf das /home-Verzeichnis). Gewöhnlich benötigt man root-Rechte, um dieses Script auszuführen. Ohne diese Rechte können Sie nur den eigenen Account überprüfen. Hat ein Benutzer den Plattenplatz, der mit »maxUsage« MB begrenzt ist, überschritten, wird eine Mail mit entsprechender Nachricht gesendet. Im Beispiel wird das Kommando mail verwendet und kann jederzeit auch durch sendmail ausgetauscht werden (abhängig vom System).
Hinweis An dieser Stelle sollte auch auf das Quota-System hingewiesen werden. Das Quota-System wird verwendet, wenn Benutzer/Gruppen, die an einem System arbeiten und dort ein eigenes Verzeichnis besitzen, zu viele Daten in diesem Verzeichnis speichern/sammeln.
|
Mit Quota können Sie als Systemadministrator den verfügbaren Plattenplatz für jede/n Benutzer/Gruppe einschränken. Hierbei existieren zwei Grenzen, das Softlimit und das Hardlimit. Beim Softlimit darf der Benutzer die Grenze für eine kurze Zeit überschreiten. Dieser Zeitraum wird durch die »Grace Period« festgelegt. Beim Hardlimit darf der Benutzer (oder die Gruppe) diese Grenze keinesfalls überschreiten. Es gibt also keine Möglichkeit, dieses Limit zu umgehen. Das Quota-System liegt gewöhnlich jeder Distribution bei. Mehr dazu finden Sie auch in einem Mini-Howto in deutscher Sprache.
|
#!/bin/sh
# DiskQuota = Das Tool analysiert den Plattenplatzverbrauch
# einzelner Benutzer
# Limit der Speicherplatzbenutzung pro User in MB
maxUsage=100
# temporäre Log-Datei -> besser wäre in /tmp
logfile="loghogs.$$"
# Verzeichnis(se), das/die pro User erfasst werden sollen
dirs="/home"
# uid_start: Alle User-IDs unter 100 sind gewöhnlich dem root
# und anderen Diensten vorbehalten. Echte User beginnen
# gewöhnlich ab 100 oder manchmal gar ab 1000
uid_start=99
# Beim ordentlichen Beenden logfile wieder löschen
trap "/bin/rm -f $logfile" EXIT
for name in `cut -d: -f1,3 /etc/passwd | \
awk -F: '$2 > $uid_start { print $1 }'`
do
echo -n "$name "
find $dirs -user $name -xdev -type f -ls | \
awk '{ sum += $7 } END { print sum / (1024*1024) }'
done | awk "\$2 > $maxUsage { print \$0 }" > $logfile
# Wenn vorhanden, haben wir einen "Übertreter"
# gefunden, ansonsten ...
if [ ! -s $logfile ]
then
echo "Kein User hat das Limit ${maxUsage}MB überzogen"
exit 0
fi
while read user diskspace
do
cat <<MARKE | mail -s "Achtung Limit überzogen" $user
Hallo $user,
Soeben `date "+%Y-%h-%d %H:%M:%S "` wurde festgestellt, dass Sie
Ihr Limit von ${maxUsage}MB überzogen haben. Derzeit beträgt Ihr
verwendeter Speicher ${diskspace}MB. Bitte beheben Sie den
Umstand sobald wie möglich. Vielen Dank für das Verständnis.
MARKE
echo "User $user hat den Account überzogen\
(Ist:${diskspace}MB Soll:${maxUsage}MB)"
done < $logfile
Das Script bei der Ausführung:
# ./DiskQuota
User tot hat den Account überzogen (Ist:543,72MB Soll:100MB)
---- Inzwischen beim User tot ----
tot@host > mail
... ... ...
N 14 tot@linux.site Mon May 2 15:14 22/786 Limit überzogen
... ... ...
? 14
Message 14:
From: you@host.site (J.Wolf)
Hallo tot,
Soeben 2005-Mai-02 15:14:47 wurde festgestellt, dass Sie Ihr
Limit von 100MB überzogen haben. Derzeit beträgt Ihr verwendeter
Speicher 543,72MB. Bitte beheben Sie den Umstand sobald wie
möglich.
Vielen Dank für das Verständnis.
Hinweis Bitte beachten Sie, wenn Sie weitere Verzeichnisse angeben, in denen nach Dateien eines bestimmten Benutzers gesucht werden soll (oder gar das Wurzelverzeichnis), dass dies sehr viel Zeit in Anspruch nehmen kann.
|
Prozesse nach User sortiert mit Instanzen ausgeben
Einen weiteren Komfort, den man als Systemadministrator gern nutzen würde, wäre eine Ausgabe der Prozessüberwachung einzelner Benutzer, sortiert nach diesen. Das folgende, gut kommentierte Script sortiert die Prozesse nach Benutzern und gar nach deren einzelnen Instanzen, wenn der Benutzer von einer Instanz mehrere ausführt. Führt der Benutzer z. B. dreimal bash als Shell aus, finden Sie in der Zusammenfassung 3 Instanz(en) von /bin/bash, statt jede Instanz einzeln aufzulisten.
#!/bin/sh
# Name: psusers
# Voraussetzung, dass dieses Script funktioniert, ist, dass die
# Ausgabe von ps -ef auf Ihrem Rechner folgendes Format hat:
#
# you@host > ps -ef
# UID PID PPID C STIME TTY TIME CMD
# root 1 0 0 00:38 ? 00:00:04 init [5]
# root 2 1 0 00:38 ? 00:00:00 [ksoftirqd/0]
#
# Wenn die Ausgabe bei Ihnen etwas anders aussieht, müssen Sie
# das Script entsprechend anpassen (erste Zuweisung von USERNAME
# und PROGNAME)
# Variablen deklarieren
#
COUNTER=0; CHECKER=0; UCOUNT=1
PSPROG='/bin/ps -ef'
SORTPROG='/bin/sort +0 –1 +7 –8'
TMPFILE=/tmp/proclist_$$
# Beim ordentlichen Beenden TMPFILE wieder löschen
trap "/bin/rm -f $TMPFILE" EXIT
# Die aktuelle Prozessliste in TMPFILE speichern
#
$PSPROG | $SORTPROG > $TMPFILE
# Daten in TMPFILE verarbeiten
#
grep -v 'UID[ ]*PID' $TMPFILE | while read LINE
do
# Zeilen in einzelne Felder aufbrechen
set -- $LINE
# Einzelne Felder der Ausgabe von ps -ef lauten:
# UID PID PPID C STIME TTY TIME CMD
# Anzahl der Parameter einer Zeile größer als 0 ...
if [ $# -gt 0 ]
then
# Erstes Feld (UID) einer Zeile der Variablen
# USERNAME zuordnen
USERNAME=$1
# Die ersten sieben Felder einer Zeile entfernen
shift 7
# Kommandonamen (CMD) der Variablen PROGNAME zuordnen
PROGNAME=$*
fi
# Testet die Kopfzeile
#
if [ "$USERNAME" = "UID" ]
then
continue # nächsten Wert in der Schleife holen ...
fi
# Überprüfen, ob es sich um die erste Zeile von Daten handelt
#
if [ "$CHECKER" = "0" ]
then
CHECKER=1
UCOUNT=0
LASTUSERNAME="$USERNAME"
# Programmname für die Ausgabe formatieren
# auf 40 Zeichen beschränken ....
#
LASTPROGNAME=`echo $PROGNAME | \
awk '{print substr($0, 0, 40)}'`
COUNTER=1; LASTCOUNT=1
echo ""
echo "$USERNAME führt aus:....."
continue # nächsten Wert von USERNAME holen
fi
# Logische Überprüfung durchführen
#
if [ $CHECKER -gt 0 -a "$USERNAME" = "$LASTUSERNAME" ]
then
if [ "$PROGNAME" = "$LASTPROGNAME" ]
then
COUNTER=`expr $COUNTER + 1`
else
# Ausgabe auf dem Bildschirm ...
if [ $LASTCOUNT -gt 1 ]
then
echo " $LASTCOUNT Instanz(en) von ->"\
" $LASTPROGNAME"
else
echo " $LASTCOUNT Instanz(en) von ->"\
" $LASTPROGNAME"
fi
COUNTER=1
fi
# Programmname für die Ausgabe formatieren
# auf 40 Zeichen beschränken ....
#
LASTPROGNAME=`echo $PROGNAME | \
awk '{print substr($0, 0, 40)}'`
LASTCOUNT=$COUNTER
elif [ $CHECKER -gt 0 -a "$USERNAME" != "$LASTUSERNAME" ]
then
if [ $LASTCOUNT -gt 1 ]
then
echo " $LASTCOUNT Instanz(en) von >> $LASTPROGNAME"
else
echo " $LASTCOUNT Instanz(en) von >>"\
" $LASTPROGNAME"
fi
echo
echo "$USERNAME führt aus:....."
LASTUSERNAME="$USERNAME"
# Programmname für die Ausgabe formatieren
# auf 40 Zeichen beschränken ....
#
LASTPROGNAME=`echo $PROGNAME | \
awk '{print substr($0, 0, 40)}'`
COUNTER=1
LASTCOUNT=$COUNTER
fi
done
# DISPLAY THE FINAL USER INSTANCE DETAILS
#
if [ $COUNTER -eq 1 -a $LASTCOUNT -ge 1 ]
then
if [ $LASTCOUNT -gt 1 ]
then
echo " $LASTCOUNT Instanz(en) von >> $LASTPROGNAME"
else
echo " $LASTCOUNT Instanz(en) von >> $LASTPROGNAME"
fi
fi
echo "------"
echo "Fertig"
echo "------"
Das Script bei der Ausführung:
you@host > ./psusers
bin führt aus:.....
1 Instanz(en) von >> /sbin/portmap
lp führt aus:.....
1 Instanz(en) von >> /usr/sbin/cupsd
postfix führt aus:.....
1 Instanz(en) von -> pickup -l -t fifo -u
1 Instanz(en) von >> qmgr -l -t fifo -u
root führt aus:.....
1 Instanz(en) von -> -:0
1 Instanz(en) von -> [aio/0]
1 Instanz(en) von -> /bin/bash /sbin/hotplug pci
1 Instanz(en) von -> /bin/bash /etc/hotplug/pci.agent
...
you führt aus:.....
3 Instanz(en) von -> /bin/bash
1 Instanz(en) von -> /bin/ps -ef
1 Instanz(en) von -> /bin/sh /opt/kde3/bin/startkde
1 Instanz(en) von -> /bin/sh ./testscript
1 Instanz(en) von -> gpg-agent --daemon --no-detach
1 Instanz(en) von -> kaffeine -session 117f000002000111
1 Instanz(en) von -> kamix
1 Instanz(en) von -> kdeinit: Running...
...
Prozesse bestimmter Benutzer beenden
Häufig kommt es vor, dass bei einem Benutzer einige Prozesse »Amok« laufen bzw. man einen Prozess einfach beenden will (warum auch immer). Mit dem folgenden Script können Sie (als root) die Prozesse eines Benutzers mithilfe einer interaktiven Abfrage beenden. Nach der Eingabe des Benutzers werden alle laufenden Prozesse in einem Array gespeichert. Anschließend wird das komplette Array durchlaufen und nachgefragt, ob Sie den Prozess beenden wollen oder nicht. Zuerst wird immer versucht, den Prozess normal mit SIGTERM zu beenden. Gelingt dies nicht mehr, muss SIGKILL herhalten.
Hinweis Da dieses Script Arrays verwendet, ist es nur in der bash bzw. Korn-Shell ausführbar. Muss das Script unbedingt auch in einer Bourne-Shell laufen, so könnte man die einzelnen Prozesse statt in ein Array auch in eine Datei (zeilenweise) schreiben und aus dieser zeilenweise wieder lesen.
|
#!/bin/ksh
# Name: killuser
# Wegen der Benutzung von Arrays "nur" für bash und Korn-Shell
# nicht aber für Bourne-Shell (sh) geeignet
while true
do
# Bildschirm löschen
clear
echo "Diese Script erlaubt Ihnen bestimmte Benutzer Prozesse"
echo "zu beenden."
echo
echo "Name des Benutzers eingeben (mit q beenden) : " | \
tr -d '\n'
read unam
# Wurde kein Benutzer angegeben
unam=${unam:-null_value}
export unam
case $unam in
null_value)
echo "Bitte einen Namen eingeben!" ;;
[Qq])
exit 0 ;;
root)
echo "Benutzer 'root' ist nicht erlaubt!" ;;
*)
echo "Überprüfe $unam ..."
typeset -i x=0
typeset -i n=0
if $(ps -ef | grep "^[ ]*$unam" > /dev/null)
then
for a in $(ps -ef |
awk -v unam="$unam" '$1 ~ unam { print $2, $8}'| \
sort -nr +1 –2 )
do
if [ $n -eq 0 ]
then
x=`expr $x + 1`
var[$x]=$a
n=1
elif [ $n -eq 1 ]
then
var2[$x]=$a
n=0
fi
done
if [ $x -eq 0 ]
then
echo "Hier gibt es keine Prozesse zum Beenden!"
else
typeset -i y=1
clear
while [ $y -le $x ]
do
echo "Prozess beenden PID: ${var[$y]} -> CMD: "\
" ${var2[$y]} (J/N) : " | tr -d '\n'
read resp
case "$resp" in
[Jj]*)
echo "Prozess wird beendet ..."
# Zuerst versuchen, "normal" zu beenden
echo "Versuche, normal zu beenden " \
" (15=SIGTERM)"
kill –15 ${var[$y]} 2>/dev/null
# Überprüfen, ob es geklappt hat
# -> ansonsten
# mit dem Hammmer killen
if ps -p ${var[$y]} >/dev/null 2>&1
then
echo "Versuche, 'brutal' zu beenden"\
" (9=SIGKILL)"
kill –9 ${var[$y]} 2>/dev/null
fi
;;
*)
echo "Prozess wird weiter ausgeführt"\
" ( ${var2[y]} )"
;;
esac
y=`expr $y + 1`
echo
done
fi
fi
;;
esac
sleep 2
done
Das Script bei der Ausführung:
# ./killuser
Dieses Script erlaubt Ihnen, bestimmte Benutzer-Prozesse
zu beenden.
Name des Benutzers eingeben (mit q beenden) : john
Prozess beenden PID: 4388 -> CMD: sleep (J/N) : J
Prozess wird beendet ...
Versuche, normal zu beenden (15=SIGTERM)
Prozess beenden PID: 4259 -> CMD: holdonrunning (J/N) : N
Prozess wird weiter ausgeführt ( holdonrunning )
Prozess beenden PID: 4203 -> CMD: -csh (J/N) : ...
Überwachung, wer sich im System einloggt
Einen Überblick, wer sich alles im System einloggt und eingeloggt hat, können Sie sich wie bekannt mit dem Kommando last ermitteln lassen. Gern würde man sich den Aufruf von last ersparen, um so immer aktuell neu eingeloggte Benutzer im System zu ermitteln. Dies kann man dann z. B. verwenden, um dem Benutzer eine Nachricht zukommen zu lassen, oder eben zu Überwachungszwecken.
Das Überwachen, ob sich ein neuer Benutzer im System eingeloggt hat, lässt sich auch in einem Shellscript mit last relativ leicht ermitteln. Hierzu müssen Sie eigentlich nur die Anzahl von Zeilen von last zählen und in einer bestimmten Zeit wieder miteinander vergleichen, ob eine neue Zeile hinzugekommen ist. Die Differenz beider Werte lässt sich dann mit last und einer Pipe nach head ausgeben. Dabei werden immer nur die neu hinzugekommenen letzten Zeilen mit head ausgegeben. Im Beispiel wird die Differenz beider last-Aufrufe alle 30 Sekunden ermittelt. Dieser Wert lässt sich natürlich beliebig hoch- bzw. runtersetzen. Außerdem wird im Beispiel nur eine Ausgabe auf das aktuelle Terminal (/dev/tty) vorgenommen. Hierzu würde sich beispielsweise das Kommando write oder wall sehr gut eignen. Als root könnten Sie somit jederzeit einem User eine Nachricht zukommen lassen, wenn dieser sich einloggt.
#! /bin/sh
# Name: loguser
# Das Script überprüft, ob sich jemand im System eingeloggt hat
# Pseudonym für das aktuelle Terminal
outdev=/dev/tty
fcount=0; newcount=0; timer=30; displaylines=0
# Die Anzahl Zeilend des last-Kommandos zählen
fcount=`last | wc -l`
while true
do
# Erneut die Anzahl Zeilen des last-Kommandos zählen ...
newcount=`last | wc -l`
# ... und vergleichen, ob neue hinzugekommen sind
if [ $newcount -gt $fcount ]
then
# Wie viele neue Zeilen sind hinzugekommen ...
displaylines=`expr $newcount – $fcount`
# Entsprechend neue Zeilen ausgeben auf outdev
# Hier würde sich auch eine Datei oder das Kommando
# write sehr gut eignen, damit die Kommandozeile
# nicht blockiert wird ...
last | head -$displaylines > $outdev
# neuen Wert an fcount zuweisen
fcount=$newcount
# timer Sekunden warten, bis zur nächsten Überprüfung
sleep $timer
fi
done
Das Script bei der Ausführung:
you@host > ./loguser
john tty2 Wed May 4 23:46 still logged in
root tty4 Wed May 4 23:46 still logged in
tot tty2 Wed May 4 23:47 still logged in
you tty5 Wed May 4 23:49 still logged in
Benutzer komfortabel anlegen, löschen, sperren und wieder aufheben
Eine ziemlich wichtige und regelmäßige Aufgabe, die Ihnen als Systemadministrator zufällt, dürfte das Anlegen und Löschen neuer Benutzerkonten sein.
Hinweis Ich habe mir lange überlegt, diesen Part der User-Verwaltung wieder zu streichen. Zum einen zeigt das Script hervorragend, wie man sich eine eigene Userverwaltung bauen kann und was dabei alles so zu beachten ist. Allerdings bietet mittlerweile jede Distribution mindestens eine solche Userverwaltung (und das meistens erheblich komfortabler) an. Das Script sollte eigentlich nur unter Linux ordentlich laufen, aber selbst hier könnten Sie noch Probleme mit der Portabilität bekommen, weil auch die einzelnen Distributionen hier ihr eigenes Süppchen kochen, mal heißt es hier useradd dann wieder adduser, die Optionen von passwd bspw. sind teilweise auch unterschiedlich.
|
Um einen neuen Benutzer-Account anzulegen, wird ein neuer Eintrag in der Datei /etc/passwd angelegt. Dieser Eintrag beinhaltet gewöhnlich einen Benutzernamen aus acht Zeichen, eine User-ID (UID), eine Gruppen-ID (GID), ein Heimverzeichnis (/home) und eine Login-Shell. Die meisten Linux-/UNIX-Systeme speichern dann noch ein verschlüsseltes Password in /etc/shadow – was natürlich bedeutet, dass Sie auch hier einen Eintrag (mit passwd) vornehmen müssen. Beim Anlegen eines neuen Benutzers können Sie entweder zum Teil vorgegebene Standardwerte verwenden oder eben eigene Einträge anlegen. Es ist außerdem möglich, die Dauer der Gültigkeit des Accounts festzulegen.
Im Beispiel ist es nicht möglich, auch noch eine neue Gruppe anzulegen, sprich, Sie können nur einen neuen Benutzer anlegen und diesem eine bereits vorhandene Gruppe (setzt einen vorhandenen Eintrag in /etc/group voraus) zuweisen. Auf das Anlegen einer neuen Gruppe wurde aus Übersichtlichkeitsgründen verzichtet, da sich das Script sonst unnötig in die Länge ziehen würde. Allerdings sollte es Ihnen mit der Vorlage dieses Scripts nicht schwer fallen, ein recht ähnliches Script für das Anlegen einer Gruppe zu schreiben.
Nebenbei ist es auch realisierbar, einen Benutzer mit passwd zu sperren und die Sperre wieder aufzuheben. Beim Löschen eines Benutzers werden zuvor noch all seine Daten gesucht und gelöscht, bevor der eigentliche Benutzer-Account aus /etc/passwd gelöscht werden kann. Im Beispiel wird die Suche wieder nur auf das /home-Verzeichnis beschränkt, was Sie allerdings in der Praxis wieder den Gegebenheiten anpassen sollten.
#! /bin/sh
# Name: account
# Mit diesem Script können Sie einen Benutzer
# * Anlegen
# * Löschen
# * Sperren
# * Sperre wieder aufheben
# Pfade, die beim Löschen eines Accounts benötigt werden,
# ggf. erweitern und ergänzen um bspw. /var /tmp ...
# überall eben, wo sich Dateien vom Benutzer befinden können
searchpath="/home"
usage() {
echo "Usage: $0 Benutzer (Neuen Benutzer anlegen)"
echo "Usage: $0 -d Benutzer (Benutzer löschen)"
echo "Usage: $0 -l Benutzer (Benutzer sperren)"
echo "Usage: $0 -u Benutzer (Gesperrten Benutzer wieder freigeben)"
}
# Nur root darf dieses Script ausführen ...
#
if [ `id -u` != 0 ]
then
echo "Es werden root-Rechte für dieses Script benötigt!"
exit 1
fi
# Ist das Kommando useradd auf dem System vorhanden ...
#
which useradd > /dev/null 2>1&
if [ $? -ne 0 ]
then
echo "Das Kommando 'useradd' konnte auf dem System nicht "\
" gefunden werden!"
exit 1
fi
if [ $# -eq 0 ]
then
usage
exit 0
fi
if [ $# -eq 2 ]
then
case $1 in
-d)
# Existiert ein entsprechender Benutzer
if [ "`grep $2 /etc/passwd | \
awk -F : '{print $1}'`" = "$2" ]
then
echo "Dateien und Verzeichnisse von '$2' "\
"werden gelöscht"
# Alle Dateien und Verz. des Benutzers löschen
find $searchpath -user $2 -print | sort -r |
while read file
do
if [ -d $file ]
then
rmdir $file
else
rm $file
fi
done
else
echo "Ein Benutzer '$2' existiert nicht in "\
"/etc/passwd!"
exit 1
fi
# Benutzer aus /etc/passwd und /etc/shadow löschen
userdel -r $2 2>/dev/null
echo "Benutzer '$2' erfolgreich gelöscht!"
exit 0 ;;
-l)
# Existiert ein entsprechender Benutzer
if [ "`grep $2 /etc/passwd | \
awk -F : '{print $1}'`" = "$2" ]
then
passwd -l $2
fi
echo "Benutzer '$2' wurde gesperrt"
exit 0 ;;
-u)
# Existiert ein entsprechender Benutzer
if [ "`grep $2 /etc/passwd | \
awk -F : '{print $1}'`" = "$2" ]
then
passwd -u $2
fi
echo "Benutzer '$2': Sperre aufgehoben"
exit 0 ;;
-h) usage
exit 1 ;;
-*) usage
exit 1 ;;
*) usage
exit 1 ;;
esac
fi
if [ $# -gt 2 ]
then
usage
exit 1
fi
#####################################################
# Einen neuen Benutzer anlegen
#
# Existiert bereits ein entsprechender Benutzer
#
if [ "`grep $1 /etc/passwd | awk -F : '{print $1}'`" = "$1" ]
then
echo "Ein Benutzer '$1' existiert bereits in /etc/passwd ...!"
exit 1
fi
# Bildschirm löschen
clear
# Zuerst wird die erste freie verwendbare User-ID gesucht,
# vorgeschlagen und bei Bestätigung verwendet, oder es wird eine
# eingegebene User-ID verwendet, die allerdings ebenfalls
# überprüft wird, ob sie bereits in /etc/passwd existiert.
#
userid=`tail –1 /etc/passwd |awk -F : '{print $3 + 1}'`
echo "Eingabe der UID [default: $userid] " | tr -d '\n'
read _UIDOK
# ... wurde nur ENTER betätigt
if [ "$_UIDOK" = "" ]
then
_UIDOK=$userid
# ... es wurde eine UID eingegeben ->
# Überprüfen ob bereits vorhanden ...
elif [ `grep $_UIDOK /etc/passwd | awk -F : '{print $3}'` = "" ]
then
_UIDOK=$userid
else
echo "UID existiert bereits! ENTER=Neustart / STRG+C=Ende"
read
$0 $1
fi
# Selbiges mit Gruppen-ID
#
groupid=`grep users /etc/group |awk -F : '{print $3}'`
echo "Eingabe der GID: [default: $groupid] " | tr -d '\n'
read _GIDOK
if [ "$_GIDOK" = "" ]
then
_GIDOK=$groupid
elif [ "`grep $_GIDOK /etc/group`" = "" ]
then
echo "Dies Gruppe existiert nicht in /etc/group! "\
"ENTER=Neustart / STRG+C=Ende"
read
$0 $1
fi
# Das Benutzer-Heimverzeichnis /home abfragen
#
echo "Eingabe des Heimverzeichnisses: [default: /home/$1] " | \
tr -d '\n'
read _HOME
# Wurde nur ENTER gedrückt, default verwenden ...
if [ "$_HOME" = "" ]
then
_HOME="/home/$1"
fi
# Die Standard-Shell für den Benutzer festlegen
#
echo "Eingabe der Shell: [default: /bin/bash] " | tr -d '\n'
read _SHELL
# Wurde nur ENTER gedrückt, default verwenden ...
if [ "$_SHELL" = "" ]
then
_SHELL=/bin/bash
# Gibt es überhaupt eine solche Shell in /etc/shells ...
elif [ "`grep $_SHELL /etc/shells`" = "" ]
then
echo "'$_SHELL' gibt es nicht in /etc/shells! "\
" ENTER=Neustart / STRG+C=Ende"
read
$0 $1
fi
# Kommentar oder Namen eingeben
echo "Eingabe eines Namens: [beliebig] " | tr -d '\n'
read _REALNAME
# Expire date
echo "Ablaufdatum des Accounts: [MM/DD/YY] " | tr -d '\n'
read _EXPIRE
clear
echo
echo "Folgende Eingaben wurden erfasst:"
echo "---------------------------------"
echo "User-ID : [$_UIDOK]"
echo "Gruppen-ID : [$_GIDOK]"
echo "Heimverzeichnis : [$_HOME]"
echo "Login-Shell : [$_SHELL]"
echo "Name/Komentar : [$_REALNAME]"
echo "Account läuft aus : [$_EXPIRE]"
echo
echo "Account erstellen? (j/n) "
read _verify
case $_verify in
[nN]*)
echo "Account wurde nicht erstellt!" | tr -d '\n'
exit 0 ;;
[jJ]*)
useradd -u $_UIDOK -g $_GIDOK -d $_HOME -s $_SHELL \
-c "$_REALNAME" -e "$_EXPIRE" $1
cp -r /etc/skel $_HOME
chown -R $_UIDOK:$_GIDOK $_HOME
passwd $1
echo "Benutzer $1 [$_REALNAME] hinzugefügt "\
"am `date`" >> /var/adm/newuser.log
finger -m $1 |head –2
sleep 2
echo "Benutzer $1 erfolgreich hinzugefügt!" ;;
*) exit 1;;
esac
Das Script bei der Ausführung:
linux:/home/you # ./account jack
Eingabe der UID [default: 1003](ENTER)
Eingabe der GID: [default: 100](ENTER)
Eingabe des Heimverzeichnisses: [default: /home/jack](ENTER)
Eingabe der Shell: [default: /bin/bash](ENTER)
Eingabe eines Namens: [beliebig] J.Wolf
Ablaufdatum des Accounts : [MM/DD/YY](ENTER)
...
Folgende Eingaben wurden erfasst:
---------------------------------
User-ID : [1003]
Gruppen-ID : [100]
Heimverzeichnis : [/home/jack]
Login-Shell : [/bin/bash]
Name/Komentar : [J.Wolf]
Account läuft aus : []
Account erstellen? (j/n) j
Changing password for jack.
New password:********
Re-enter new password:********
Password changed
Login: jack Name: J.Wolf
Directory: /home/jack Shell: /bin/bash
Benutzer jack erfolgreich hinzugefügt!
linux:/home/you # ./account -l jack
Passwort geändert.
Benutzer 'jack' wurde gesperrt
linux:/home/you # ./account -u jack
Passwort geändert.
Benutzer 'jack': Sperre aufgehoben
linux:/home/you # ./account -d jack
Dateien und Verzeichnisse von 'jack' werden gelöscht
Benutzer 'jack' erfolgreich gelöscht!
15.3.2 Systemüberwachung
Warnung, dass der Plattenplatz des Dateisystems an seine Grenzen stößt
Gerade, wenn man mehrere Dateisysteme oder gar Server betreuen muss, fällt es oft schwer, sich auch noch über den Plattenplatz Gedanken zu machen. Hierzu eignet sich ein Script, mit dem Sie den fünften Wert von »df –k« auswerten und daraufhin überprüfen, ob eine bestimmte von Ihnen festgelegte Grenze erreicht wurde. Ist die Warnschwelle erreicht, können Sie eine Mail an eine bestimmte Adresse verschicken oder eventuell ein weiteres Script starten lassen, welches diverse Aufräum- oder Komprimierarbeiten durchführt. Natürlich macht dieses Script vor allem dann Sinn, wenn es im Intervall mit einem cron-Job gestartet wird.
Hinweis Auch hier sei nochmals auf das schon beschriebene Quota-System vor dem Script »DiskQuota« hingewiesen.
|
#!/bin/sh
# Name: chcklimit
# Dieses Script verschickt eine Mail, wenn der Plattenverbrauch
# eines Filesystems an ein bestimmtes Limit stösst.
# Ab wie viel Prozent soll ein Warnung verschickt werden
WARN_CAPACITY=80
# Wohin soll eine Mail verschickt werden
TOUSER=user@host.de
call_mail_fn() {
servername=`hostname`
msg_subject="$servername – Dateisystem(${FILESYSTEM}) "\
"verwendet ${FN_VAR1}% – festgestellt am: `date`"
echo $msg_subject | mail -s "${servername}:Warnung" $TOUSER
}
if [ $# -lt 1 ]
then
echo "usage: $0 FILESYSTEM"
echo "Bpsw.: $0 /dev/hda6"
fi
# Format von df -k:
# Dateisystem 1K-Blöcke Benutzt Verfügbar Ben% Eingehängt auf
# /dev/hda4 15528224 2610376 12917848 17 % /
# Den fünften Wert wollen wir haben: 'Ben%'
#
VAR1=`df -k ${1} | /usr/bin/tail –1 | \
/usr/bin/awk '{print $5}' `
# Prozentzeichen herausschneiden
VAR2=`echo $VAR1 | \
/usr/bin/awk '{ print substr($1,1,length($1)-1) }' `
# Wurde die Warnschwelle erreicht ... ?
if [ $VAR2 -ge ${WARN_CAPACITY} ]
then
FN_VAR1=$VAR2
call_mail_fn
fi
Das Script bei der Ausführung:
you@host > ./chcklimit /dev/hda6
...
you@host > mail
>N 1 tot@linux.site Mon May 2 16:18 18/602 linux:Warnung
? 1
Message 1:
From: tot@linux.site (J.Wolf)
linux – Dateisystem() verwendet 88 % – festgestellt am: Mo Mai 2 16:17:59 CEST 2005
Kommandos bzw. Scripts auf einem entfernten Rechner ausführen
Das Ausführen von Kommandos oder gar von Scripts auf mehreren Rechnern, gestartet vom lokalen Rechner, hört sich komplizierter an als es ist. Und vor allem es ist auch sicherer, als manch einer jetzt vielleicht denken mag. Dank guter Verschlüsselungstechnik und hoher Präsenz bietet sich hierzu ssh an (die r-Tools fallen wegen der Sicherheitslücken flach – siehe Abschnitt 14.12.10). Die Syntax, um mit ssh Kommandos oder Scripts auf einem anderen Rechner auszuführen, sieht wie folgt aus:
ssh username@hostname "kommando1 ; kommando2 ; script"
Mit diesem Wissen fällt es nicht schwer, sich ein entsprechendes Script zusammenzubasteln. Damit es ein wenig flexibler ist, soll es auch möglich sein, Shellscripts, die noch nicht auf dem entfernten Rechner liegen, zuvor noch mit scp in ein bestimmtes Verzeichnis hochzuladen, um es anschließend auszuführen. Ebenso soll es möglich sein, in ein bestimmtes Verzeichnis zu wechseln, um dann entsprechende Kommandos oder Scripts auszuführen. Natürlich setzt dies voraus, dass auf den Rechnern auch ein entsprechendes Verzeichnis existiert. Die Rechner, auf denen Kommandos oder Scripts ausgeführt werden sollen, tragen Sie in die Datei namens hostlist.txt ein. Bei mir sieht diese Datei wie folgt aus:
you@host > cat hostlist.txt
us10129@myhoster.de
jwolf@192.135.147.2
Im Beispiel finden Sie also zwei entfernte Rechner, bei denen das gleich folgende Script dafür sorgt, dass Sie von Ihrem lokalen Rechner aus schnell beliebige Kommandos bzw. Scripts ausführen können.
Hinweis Damit Sie nicht andauernd ein Passwort eingeben müssen, empfiehlt es sich auch hier, SSH-Schlüssel zu verwenden (siehe Abschnitt 14.12.12).
|
#!/bin/sh
# Name: sshell
# Kommandos bzw. Scripts auf entfernten Rechnern ausführen
# ggf. den Pfad zur Datei anpassen
HOSTS="hostlist.txt"
usage() {
echo "usage: progname [-option] [Verzeichnis] "\
" Kommando_oder_Script"
echo
echo "Option:"
echo "-d :in ein bestimmtes Verzeichnis auf dem Host wechseln"
echo "-s :Script in ein bestimmtes Verzeichnis hochladen und"\
" Ausführen"
echo
echo "Syntax der Host-Liste: "
echo "Username@hostname1"
echo "Username@hostname2"
echo "..."
exit 1
}
if [ $# -eq 0 ]
then
usage
fi
# Datei 'hostlist.txt' überprüfen
if [ -e $HOSTS ]
then :
else
echo "Datei $HOSTS existiert nicht ..."
touch hostlist.txt
if [ $? -ne 0 ]
then
echo "Konnte $HOSTS nicht anlegen ...!"
exit 1
else
echo "Datei $HOSTS erzeugt, aber noch leer ...!"
usage
exit 1
fi
fi
# Optionen überprüfen ...
case $1 in
-d)
if [ $# -lt 3 ]
then
usage
fi
DIR=$2
shift; shift ;;
-s)
if [ $# -lt 3 ]
then
usage
fi
DIR=$2
SCRIPT="yes"
shift; shift ;;
-*)
usage ;;
esac
# Die einzelnen Hosts durchlaufen ...
for host in `cat $HOSTS`
do
echo "$host : "
CMD=$*
if [ "$SCRIPT" = "yes" ]
then
scp $CMD ${host}:${DIR}
fi
ret=`ssh $host "cd $DIR; $CMD"`
echo "$ret"
done
Das Script bei der Ausführung:
Inhalt des Heimverzeichnisses ausgeben:
you@host > ./sshell ls -l
us10129@myhoster.de :
total 44
drwx------ 4 us10129 us10129 4096 May 14 13:45 backups
drwxr-xr-x 8 us10129 us10129 4096 May 9 10:13 beta.pronix.de
-rw-rw-r-- 1 us10129 us10129 66 Dec 2 02:13 db_cms.bak
drwxrwxr-x 2 us10129 us10129 4096 Mar 11 07:49 dump
-rw------- 1 us10129 us10129 952 May 14 14:00 mbox
drwxrwxr-x 2 us10129 us10129 4096 Mar 28 18:03 mysqldump
drwxr-xr-x 20 us10129 us10129 4096 May 19 19:56 www.pronix.de
jwolf@192.135.147.2 :
total 24
drwxr-xr-x 2 jwolf jwolf 512 May 8 14:03 backups
drwxr-xr-x 3 jwolf jwolf 21504 Sep 2 2004 dev
Inhalt des Verzeichnisses $HOME/backups ausgeben:
you@host > ./sshell -d backups ls -l
us10129@myhoster.de :
total 8
drwxrwxr-x 3 us10129 us10129 4096 May 18 18:38 Shellbuch
drwxrwxr-x 3 us10129 us10129 4096 May 14 13:46 Shellbuch_bak
-rw-rw-r-- 1 us10129 us10129 0 May 20 12:45 file1
-rw-rw-r-- 1 us10129 us10129 0 May 20 12:45 file2
-rw-rw-r-- 1 us10129 us10129 0 May 20 12:45 file3
jwolf@192.135.147.2 :
total 6
-rw-r--r-- 1 jwolf jwolf 0 May 8 13:38 file1
-rw-r--r-- 1 jwolf jwolf 0 May 8 13:38 file2
-rw-r--r-- 1 jwolf jwolf 0 May 8 13:38 file3
-rwx------ 1 jwolf jwolf 29 May 8 13:58 hallo.sh
-rwx------ 1 jwolf jwolf 29 May 8 13:48 mhallo
-rwx------ 1 jwolf jwolf 29 May 8 14:03 nhallo
Dateien beginnend mit »file*« im Verzeichnis $HOME/backups löschen:
you@host > ./sshell -d backups rm file*
us10129@myhoster.de :
jwolf@192.135.147.2 :
Inhalt des Verzeichnisses $HOME/backups erneut ausgeben:
you@host > ./sshell -d backups ls -l
us10129@myhoster.de :
total 5
drwxrwxr-x 3 us10129 us10129 4096 May 18 18:38 Shellbuch
drwxrwxr-x 3 us10129 us10129 4096 May 14 13:46 Shellbuch_bak
jwolf@192.135.147.2 :
total 3
-rwx------ 1 jwolf jwolf 29 May 8 13:58 hallo.sh
-rwx------ 1 jwolf jwolf 29 May 8 13:48 mhallo
-rwx------ 1 jwolf jwolf 29 May 8 14:03 nhallo
Neues Verzeichnis testdir anlegen:
you@host > ./sshell mkdir testdir
us10129@myhoster.de :
jwolf@192.135.147.2 :
Script hallo.sh ins neue Verzeichnis (testscript) schieben und ausführen:
you@host > ./sshell -s testdir ./hallo.sh
us10129@myhoster.de :
hallo.sh 100 % 67 0.1KB/s 00:00
Ich bin das Hallo Welt-Script!
jwolf@192.135.147.2 :
hallo.sh 100 % 67 0.1KB/s 00:00
Ich bin das Hallo Welt-Script!
Verzeichnis testdir wieder löschen:
tot@linux:~> ./sshell rm -r testdir
us10129@myhoster.de :
jwolf@192.135.147.2 :
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.
|