PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Syntax-Problem mit bash-Script



Fireball22
17-12-2007, 13:58
Hallo,

leider habe ich schon seit einiger Zeit ein Syntax mit meinem eigenen Start/Stop/Restart-Script für einen Shoutcast-Server.

Hier mal das Script:



#!/bin/bash
# Startprogramm für den SHOUTCasting-Server
# Copyright by Michael Kaps; www.michis-homepage.net

#################################### KONFIGURATION ########################################
################################################## #########################################
## Pfad zur Datei sc_serv des SHOUTCasting-Servers (Dateinamen nicht mehr mit angeben)
path_shoutcast="/home/shoutcast"
################################################## #########################################
## Screens zur Überwachung des Servers verwenden (Aufrufbar mit screen -r sc1) ( 0 = Aus / 1 = Ein)
use_screen="1"
################################################## #########################################
## Speziellen Benuzter wählen der den SHOUTCasting-Server starten soll (Erhöht die Sicherheit; User muss angelegt sein) ( 0 = Aus / 1 = Ein)
use_user="0"
username="shoutcast"
################################################## #########################################
#################################### KONFIGURATION ENDE ###################################

case "${1}" in
start)
## if [ "${start}" != "1" ]; then
if [[ ! -e "${path_shoutcast}/server.pid" ]]; then

# Falls Screen aktiviert
if [ "${use_screen}" == "1" ]; then
if [ "${use_user}" == "1" ]; then
su -c '"${path_shoutcast}/sc_serv"' "${username}"
else
screen -dmS sc1 "${path_shoutcast}/sc_serv"
fi

# Wenn Kommando fehlerfrei, dann PID-File anlegen
if [ "${?}" == "0" ]; then
echo "done"
touch "${path_shoutcast}/server.pid"
else
echo "false"
fi

# Falls Screen nicht aktiviert oder nicht eindeutig
else
if [ "${use_user}" == "1" ]; then
su -c '"${path_shoutcast}/sc_serv"' "${username}"
else
"${path_shoutcast}/sc_serv"
fi

# Wenn Kommando fehlerfrei, dann Variable auf gestartet setzen
if [ "${?}" == "0" ]; then
echo "done"
touch "${path_shoutcast}/server.pid"
else
echo "false"
fi
fi
else
echo "Server scheint bereits online zu sein!"
fi
;;
restart)
##if [ "${start}" == "1" ]; then
if [[ -e "${path_shoutcast}/server.pid" ]]
if [ "${use_screen}" == "1" ]; then
if [ "${use_user}" == "1" ]; then
su -c "killall -9 sc1" "${username}"
su -c 'screen -dmS sc1 "${path_shoutcast}/sc_serv"' "${username}"
else
killall -9 sc1
screen -dmS sc1 "${path_shoutcast}/sc_serv"
fi

if [ "${?}" == "0" ]; then
echo "done"
touch "${path_shoutcast}/server.pid"
else
echo "false"
fi
else
if [ "${use_user}" == "1" ]; then
su -c 'killall -9 "${path_shoutcast}/sc_serv" && "${path_shoutcast}/sc_serv"' "${username}"'
else
killall -9 "${path_shoutcast}/sc_serv" && "${path_shoutcast}/sc_serv"' "${username}"
fi

if [ "${?}" == "0" ]; then
echo "done"
touch "${path_shoutcast}/server.pid"
else
echo "false"
fi
fi
else
echo "Der Server scheint nicht online zu sein, bitte erst starten!"
fi
;;
status)
##if [ "${start}" == "1" ]; then
if [[ -e "${path_shoutcast}/server.pid" ]]
echo "Server scheint online zu sein!"
##elif [ "${start}" == "0" ]; then
elif [[ ! -e "${path_shoutcast}/server.pid" ]]
echo "Server scheint offline zu sein!"
fi
;;
stop)
##if [ "${start}" == "1" ]; then
if [[ -e "${path_shoutcast}/server.pid" ]]
if [ "${use_screen}" == "1" ]; then
if [ "${use_user}" == "1" ]; then
su -c 'killall -9 "sc1" "${username}"'
else
killall -9 sc1
fi

if [ "${?}" == "0" ]; then
echo "done"
rm -f "${path_shoutcast}/server.pid"
else
echo "false"
fi
else
if [ "${use_user}" == "1" ]; then
su -c 'killall -9 "${path_shoutcast}/sc_serv"'
else
killall -9 "${path_shoutcast}/sc_serv"
fi

if [ "${?}" == "0" ]; then
echo "done"
rm -f "${path_shoutcast}/server.pid"
else
echo "false"
fi
fi

##elif [ "${start}" == "0" ]; then
elif [[ ! -e "${path_shoutcast}/server.pid" ]]
echo "Server scheint nicht online zu sein, bitte erst starten!"
fi
;;
*)
echo "Syntax:"
echo "shoutcast (start|stop|status|restart)"
exit 2
;;
esac


Und hier die Fehlermeldung die ich bekomme:



hxxxxx:~# sh shoutcast_control.sh
: command not foundh: line 4:
: command not foundh: line 18:
'houtcast_control.sh: line 19: syntax error near unexpected token `in
'houtcast_control.sh: line 19: `case "${1}" in


An was könnte das denn liegen?
Ich kann leider einfach kein Syntaxfehler in Zeile 19 finden.
Ebenso seltsam erscheint mir der Fehler in Zeile 4 und 18, worüber er sich über eine leere Zeile beschwert.

MfG
Michael

jan61
17-12-2007, 22:59
Moin,

wo ist Dein Script entstanden? Die verstümmelten Fehlermeldungen lassen auf WinDOS-Editor schliessen (also auch auf WinDOS-Zeilenende \r\n). Versuch mal:
tr -d '\r' <DeinScript >DeinScript.tmp && mv DeinScript.tmp DeinScript und versuchs nochmal mit dem Start.

Jan

Fireball22
18-12-2007, 13:02
Vielen Dank für deine Antwort, genau das war das Problem! =)
Dann müsste es eig. auch reichen wenn ich in Zukunft das Zeichenlayout einfach von ANSI auf DOS umstelle, oder?

Allerdings beschwert er sich jetzt über eine angeblich überflüssige Else-Anweisung:


h852677:~# ./DeinScript
./DeinScript: line 56: syntax error near unexpected token `else'
./DeinScript: line 56: ` else'


Ich habe auch direkt in der Zeile 56 nachgeschaut, nur ist dort das else eig. ganz zu Recht vorhanden, nur wo steckt denn das Problem?

MfG
Michael

jan61
20-12-2007, 01:18
Vielen Dank für deine Antwort, genau das war das Problem! =)
Dann müsste es eig. auch reichen wenn ich in Zukunft das Zeichenlayout einfach von ANSI auf DOS umstelle, oder?

Eig. reicht das eben nicht. Wenn Du unter Win/DOS am Ende einer Zeile <ENTER> drückst, dann wird da immer ein <CR><LF> eingebaut, und Unix / Linux mag das nun mal nicht, dem reicht ein <LF>. Du hast 4 Möglichkeiten:

1. Die Naheliegende: Entwickle Deine Unix-Shellscripts unter Unix (mit kate z. B. hast Du einen recht vernünftigen Editor in KDE, das Nonplusultra aller Editoren ist natürlich vim, und wenn Du es ganz kompliziert magst, dann startest Du das Betriebssystem "emacs", da gibts auch einen Editor mitgeliefert ;-) SCNR

2. Die Umständliche: Du entwickelst weiter mit Deinem Lieblings-Editor unter Win/DOS und schubst danach jedesmal den "tr" aus meinem 1. Posting an.

3. Die Pragmatische: Du entwickelst in Zukunft unter Win/DOS mit einem vernünftigen Editor (z. B. UltraEdit oder TextPad), der Dateien auch im Unix-Format abspeichern kann (in UltraEdit zu finden unter Datei -> Konvertieren -> DOS->Unix).

4. Die Pfiffige: Wenn Du die Scripts per z. B. FTP auf den Server überträgst, dann achtest Du darauf, dass der Übertragungsmodus "ASCII" ist (in ftp mit "ascii" einzustellen), dann wird ftp die Zeilenenden selbstständig umwandeln.


Allerdings beschwert er sich jetzt über eine angeblich überflüssige Else-Anweisung:

Du machst es einem nicht gerade einfach. Ich habe mir jetzt Dein Script rauskopiert und auf meinem System abgespeichert, damit ich rausfinde, was überhaupt in Zeile 56 steht.

Sieht da oben erstmal ok aus, aber (wenn es nicht an immer noch vergriesgnaddelten Zeilenumbrüchen liegt) ein paar Sachen sind mir aufgefallen:

Was soll die Konstruktion z. B. in Zeile 22? (if [[ ... ]]; then) - warum hast Du da doppelt geklammert?

Dann vergiss bitte die "==" für einen Vergleich im "test"-Befehl (also in den eckigen Klammern), alphanumerisch ist der Vergleichsoperator "=" und numerisch heisst das "-eq" (equal) - die Abfrage des Returncodes eines Befehls sollte also so aussehen: "if [ $? -eq 0]; then".

In etlichen Zeilen ab 62 hast Du (neben der überflüssigen doppelten Klammerung) einen Syntax-Fehler, da fehlt das "...; then" (in den auskommentierten Zeilen darüber sind die noch da). Vielleicht bringt das den Parser durcheinander, so dass er Dir schon oben einen Fehler liefert.

Noch ein paar Bemerkungen zum Stil: Es ist ja sehr löblich, dass Du Variablen immer mit ${...} klammerst und immer in "" setzt - aber das macht das Script nicht unbedingt lesbarer. Eine Variable, die Du im Script selbst setzt (wie $use_screen oder $use_user), kannst Du IMHO getrost als vorhanden voraussetzen und brauchst die "" nicht, der Returncode $? muss weder geklammert noch in "" gesetzt werden, er ist immer da und danach folgende Zeichen wie z. B. $?0 ändern nicht die Bedeutung der Variablen $?. ${...} sollte man IMHO nur dann nutzen, wenn danach Zeichen kommen, die die Shell als Teil eines Variablennamens erkennen könnte, wenn Du die Variablen allein stehen hast, dann brauchst Du das nicht.

Der letzte Absatz ist meine persönliche Meinung, ich finde den Code ohne überflüssige "" und {} einfach besser lesbar. Es wird sicher Andere hier geben, die das Gegenteil behaupten ;-)

Jan

Fireball22
20-12-2007, 14:15
Vielen Dank für dein Posting!

Genau, dann werde ich einfach in meinem "Lieblings-Editor" TextPad das ganze immer in DOS konvertieren.

Und ich habe jetzt auch mal wirklich komplett alle deiner beschriebenen Änderungen an mein Script angewandt und jetzt sieht das ganze so aus:



#!/bin/bash
# Startprogramm f▒r den SHOUTCasting-Server
# Copyright by Michael Kaps; www.michis-homepage.net

#################################### KONFIGURATION ########################################
################################################## #########################################
## Pfad zur Datei sc_serv des SHOUTCasting-Servers (Dateinamen nicht mehr mit angeben)
path_shoutcast="/home/shoutcast"
################################################## #########################################
## Screens zur ▒berwachung des Servers verwenden (Aufrufbar mit screen -r sc1) ( 0 = Aus / 1 = Ein)
use_screen="1"
################################################## #########################################
## Speziellen Benuzter w▒hlen der den SHOUTCasting-Server starten soll (Erh▒ht die Sicherheit; User muss angelegt sein) ( 0 = Aus / 1 = Ein)
use_user="0"
username="shoutcast"
################################################## #########################################
#################################### KONFIGURATION ENDE ###################################

case "${1}" in
start)
## if [ "${start}" != "1" ]; then
if [ ! -e "${path_shoutcast}/server.pid" ]

# Falls Screen aktiviert
if [ ${use_screen} -eq 1 ]; then
if [ ${use_user} -eq 1 ]; then
su -c '"${path_shoutcast}/sc_serv"' "${username}"
else
screen -dmS sc1 "${path_shoutcast}/sc_serv"
fi

# Wenn Kommando fehlerfrei, dann PID-File anlegen
## if [ "${?}" == "0" ]; then
if [ $? -eq 0 ]; then
echo "done"
touch "${path_shoutcast}/server.pid"
else
echo "false"
fi

# Falls Screen nicht aktiviert oder nicht eindeutig
else
if [ ${use_user} -eq 1 ]; then
su -c '"${path_shoutcast}/sc_serv"' "${username}"
else
"${path_shoutcast}/sc_serv"
fi

# Wenn Kommando fehlerfrei, dann Variable auf gestartet setzen
if [ $? -eq 0 ]; then
echo "done"
touch "${path_shoutcast}/server.pid"
else
echo "false"
fi
fi
else
echo "Der Server scheint nicht online zu sein, bitte erst starten!"
fi
;;
status)
##if [ ${start} -eq 1 ]; then
if [ -e "${path_shoutcast}/server.pid" ]; then
echo "Server scheint online zu sein!"
##elif [ "${start}" == "0" ]; then
elif [ ! -e "${path_shoutcast}/server.pid" ]
echo "Server scheint offline zu sein!"
fi
;;
stop)
##if [ "${start}" == "1" ]; then
if [ -e "${path_shoutcast}/server.pid" ]; then
if [ ${use_screen} -eq 1 ]; then
if [ ${use_user} -eq 1 ]; then
su -c 'killall -9 "sc1" "${username}"'
else
killall -9 sc1
fi

if [ $? -eq 0 ]; then
echo "done"
rm -f "${path_shoutcast}/server.pid"
else
echo "false"
fi
else
if [ ${use_user} -eq 1 ]; then
su -c 'killall -9 "${path_shoutcast}/sc_serv"'
else
killall -9 "${path_shoutcast}/sc_serv"
fi

if [ $? -eq 0 ]; then
echo "done"
rm -f "${path_shoutcast}/server.pid"
else
echo "false"
fi
fi

##elif [ "${start}" == "0" ]; then
elif [ ! -e "${path_shoutcast}/server.pid" ]; then
echo "Server scheint nicht online zu sein, bitte erst starten!"
fi
;;
*)
echo "Syntax:"
echo "shoutcast (start|stop|status|restart)"
exit 2
;;
esac


Nun tritt der selbe Fehler aber allerdings immer noch in Zeile 57 auf.
An was kann das denn nur liegen?

MfG
Michael

jan61
20-12-2007, 18:51
...Nun tritt der selbe Fehler aber allerdings immer noch in Zeile 57 auf.
An was kann das denn nur liegen?


An Zeile 22. Da fehlt das "...; then" - war in der vorigen Version doch noch drin.

Jan

Fireball22
20-12-2007, 20:14
Ja vielen Dank, jetzt läuft endlich alles reibungslos, das Starten funktioniert auch ohne Probleme!
Nur gibt es jetzt noch ein kleines Problem beim killen des Screens.
Durch die Variablen löst sich der Pfad folgendermaßen auf, wodurch sich dieser Befehl im Script ergibt:


killall -9 "SCREEN -dmS sc1 /home/shoutcast/sc_serv


Nur leider bekomme ich - auch wenn ich diesen Befehl manuell außerhalb des Scripts ausführe - diese Fehlermeldung:



: Datei oder Verzeichnis nicht gefunden


An was liegt denn das?
Das ist doch keine Datei und kein Verzeichniss, das ist doch ein Prozes... hmm...

Oder gibt es noch eine saubere Möglichkeit einen bestimmten Screen mit seinem Namen zu killen?

MfG
Michael

Fireball22
21-12-2007, 20:31
Eig. könnte ich das Problem mit dem killen des Screens viel einfacher lösen, wenn ich direkt die PID beim anlegen des Screens in die PID-File schreibe, die so oder so angelegt wird und eig. so ja nur leer wäre!
Nur die Frage ist, wie ich die PID des Screens rausbekomm, weil ich nämlich mit $$ nur die PID der aktuellen Bash bekomme. Wenn ich diese allerdings kille, ist der Screen noch lange nicht weg.

Wie bekomme ich also am einfachsten und zuverlästigsten die PID des Screens?

MfG
Michael

jan61
31-12-2007, 13:00
... Durch die Variablen löst sich der Pfad folgendermaßen auf, wodurch sich dieser Befehl im Script ergibt:


killall -9 "SCREEN -dmS sc1 /home/shoutcast/sc_serv

Wenn der Befehl tatsächlich so ausgegeben wird, dann fehlt da ein Anführungszeichen am Ende.

Jan

jan61
31-12-2007, 13:03
Nur die Frage ist, wie ich die PID des Screens rausbekomm, weil ich nämlich mit $$ nur die PID der aktuellen Bash bekomme. Wenn ich diese allerdings kille, ist der Screen noch lange nicht weg...

Guck Dir mal pidof an. Auch mit den Optionen von ps kannst Du mal experimentieren (ggf. im Zusammenhang mit grep).

Jan

Fireball22
31-12-2007, 16:59
Ja stimmt, mit pidof wollte ich es auch schon versuchen und dann danach noch zum suchen einen "Regulären Ausdruck" verwenden, dass er nach beiden Parametern SCREEN und SC1 sucht, da er bis jetzt nur mit Suchprinzip ODER sucht und er mir somit alle PIDs von allen Screens ausgeben würde.
Laufen dann mehrere Screens im System, würde das Script entweder den falschen killen oder bei einer Schleife alle.

Da es aber mit dem Regulären Ausdruck nicht funktioniert hat, habe ich es wie folgt versucht:


screen -r sc1 -X kill

Das bringt allerdings nur teilweise Erfolg. Damit killt er zwar den Screen selber, aber aus irgend einem Grund killt er nicht die Prozesse die auf dem Screen laufen.

So habe ich es soeben auch nochmal probiert:


killall -9 'SCREEN -dmS sc1 "${path_shoutcast}/sc_serv"'


Allerdings intepretiert er diese Anweisung mit SCREEN... als Befehl und nicht nur als normalen Text. Wie kann ihm dass den beibringen, dass er das als Text intepretiert?
Eig. sollte er dass doch schon durch die Anführungszeichen wissen, oder nicht?

Nen guten Rutsch ins neue Jahr 2008 wünsch ich euch allen! =)

MfG
Michael

jan61
01-01-2008, 14:51
Moin,


...So habe ich es soeben auch nochmal probiert:


killall -9 'SCREEN -dmS sc1 "${path_shoutcast}/sc_serv"'
Allerdings intepretiert er diese Anweisung mit SCREEN... als Befehl und nicht nur als normalen Text. Wie kann ihm dass den beibringen, dass er das als Text intepretiert?
Eig. sollte er dass doch schon durch die Anführungszeichen wissen, oder nicht?

In einfache Hochkommata eingeschlossener Text wird durch die Shell nicht ausgewertet, die Variable ${path_shoutcast} wird also nicht durch den Inhalt ersetzt. Versuchs mal so:
killall -9 "SCREEN -dmS sc1 \"${path_shoutcast}/sc_serv\""Jan

EDIT: Noch 2 allgemeine Tipps für die Fehlersuche in Shell-Scripts:
1. Setze an den Anfang des Scripts eine "set -x", dann werden alle Befehle so angezeigt, wie sie durch die Shell abgefeuert werden.
2. Wenn Du nicht sicher bist, wie ein Befehl nachher aussieht, kannst Du Dir auch so helfen, dass Du zuerst ein "echo" vor den auszuführenden Befehl setzt, dann siehst Du auch meist, was passieren würde.

Fireball22
01-01-2008, 19:28
Vielen Dank für deine Hilfe!

Ich habe jetzt mal eben ein "set -x" an den Anfang des Scripts gesetzt und es ohne Hochkommata probiert, nur allerdings erhalte ich immer noch die selber Fehlermeldung.

Das Script zeigt mir nun folgendes:




h852677:~# ./DeinScript_new stop
+ path_shoutcast=/home/shoutcast
+ use_screen=1
+ use_user=0
+ username=shoutcast
+ '[' -e /home/shoutcast/server.pid ']'
+ '[' 1 -eq 1 ']'
+ '[' 0 -eq 1 ']'
+ killall -9 'SCREEN -dmS sc1 "/home/shoutcast/sc_serv"'
SCREEN -dmS sc1 "/home/shoutcast/sc_serv": Datei oder Verzeichnis nicht gefunden
+ '[' 1 -eq 0 ']'
+ echo false
false


Leider interpretiert er jedoch immer noch SCREEN als Befehl.

Wie lässt sich denn dass nur verhindern?

MfG
Michael

jan61
03-01-2008, 19:07
...Leider interpretiert er jedoch immer noch SCREEN als Befehl...

Liese Dir mal die man-Page von killall durch (habe ich eben auch gemacht ;-):

...If the command name contains a slash (/), processes executing that particular file will be selected for killing, independent of their name...So kannst Du den killall also nicht aufrufen. Der laufende Prozess wäre in Deinem Beispiel SCREEN (aber überzeuge Dich z. B. per ps davon, dass der Prozess tatsächlich so in der Prozessliste steht), dann versuchs mal einfach mit dem Namen des Executables (also "killall SCREEN"), und hau nicht gleich per SIGKILL (-9) drauf, sondern gib ihm ne Chance, sich sauber runterzufahren.

Wenn es Kindprozesse des SCREEN gibt, dann nimm die Option -g des killall, damit erlegst Du die gesamte Prozessgruppe.

Jan

Fireball22
03-01-2008, 20:31
Vielen Dank für deine Antwort!
Genau das hab ich mir schon fast gedacht, dass ist mir beim probieren auch immer wieder
aufgefallen!

Jedoch ergibt folgender Befehl folgende Fehlermeldung:


h852677:~# killall -g SCREEN
SCREEN: Kein Prozess abgebrochen


Ich habe gestern auch nochmals den ganze Abend rumgetüftelt und ich bin auf folgenden - womöglich vorherigen Fehler - im Script gestoßen.
Denn vorher wurde wurde nämlich der Shoutcast-Server !!im!! Screen so gestartet:


screen -dmS sc1 "${path_shoutcast}/sc_serv"

Nur allerdings bin ich mir gar nicht sicher ob er den Befehl danach auch innerhalb des Screens ausgeführt hat und nicht extra, weil eig. überhaupt keine Verbindung zwischen dem Screen und dem Befehl besteht.

Dieses wollte ich durch folgenden Aufruf verbessern:


screen -dmSX sc1 "${path_shoutcast}/sc_serv"


Allerdings beschwert er sich nun über folgendes:
No screen session found.

Lässt sich das Problem noch beheben, würde sich eig. der Screen inkl. Shoutcast-Server ganz einfach über screen -r sc1 -X kill beenden lassen, oder?

MfG
Michael

jan61
03-01-2008, 21:05
Moin,

wenn da "screen" und nicht "SCREEN" gestartet wird, dann wäre das schon mal eine Variante zum Testen - für Unix ist nun mal ein kleiner fehltritt was anderes als ein grosses FETTNÄPPFCHEN. Da ich nicht vorhabe, einen Shoutcast-Server aufzubauen, kann ich auch nicht live testen (screen brauche ich im Allgemeinen auch nie, ich habe immer ca. 20 Shells offen - meine gültige Definition für eine grafische Oberfläche lautet: "Möglichkeit, mindestens 10 Terminalfenster gleichzeitig zu öffnen" ;-).

Mach bitte mal vor dem kill-Kommando ein "ps -ef | grep sc_serv" und schau Dir das Ergebnis an. Dann siehst Du, wie die abzumurksenden Prozesse tatsächlich heissen.

Jan

P.S.: Was mir so beim Nachdenken auffällt - gibt es einen bestimmten Grund, warum Du den sc_serv über screen startest?

Fireball22
04-01-2008, 14:00
Hallo!

So, nun habe ich mal weiter rumgetüftelt udn wieder mal herausgefunden, dass sich beim screen mit dem Parameter -X nicht einfach irgendwelche Befehle ausführen lassen.

Dann bleibt mir wohl nichts anderes übrig, als die PID so zu beziehen und dies dann über kill zu beenden:



ps aux | grep 'SCREEN -dmS sc1 /home/shoutcast/sc_serv' | grep -v grep | cut -c9-16 | sed s/" "/""/g


Leider bin ich aber im Moment überfragt, wieso er mir jetzt immer noch diese Fehlermeldung bringt:


h852677:~# kill "ps aux | grep 'SCREEN -dmS sc1 /home/shoutcast/sc_serv' | grep -v grep | cut -c9-16 | sed s/" "/""/g"
-bash: kill: ps aux | grep 'SCREEN -dmS sc1 /home/shoutcast/sc_serv' | grep -v grep | cut -c9-16 | sed s/: no such pid
-bash: kill: //g: no such pid


Führe ich den Befehl manuell einzeln ebenfalls in der Konsole aus, erhalte ich jedoch die PID:



h852677:~# ps aux | grep 'SCREEN -dmS sc1 /home/shoutcast/sc_serv' | grep -v grep | cut -c9-16 | sed s/" "/""/g
5349


An was könnte das denn liegen?

Und warum ich sc_serv in einem Screen starte hat eig. den Grund, dass man diesen dort besser beobachten kann.
Mit einem kleinen Befehl screen -r sc1 kann man sofort sehen was der Server gerade treibt.

Die Ausgabe von deinem Kommando ergibt übrigens folgendes:


h852677:~# ps -ef | grep sc_serv
root 5349 1 0 14:20 ? 00:00:00 SCREEN -dmS sc1 /home/shoutcast/sc_serv
root 5350 5349 0 14:20 pts/1 00:00:09 /home/shoutcast/sc_serv
root 11450 3296 0 15:00 pts/0 00:00:00 grep sc_serv


MfG
Michael

jan61
07-01-2008, 19:42
...Dann bleibt mir wohl nichts anderes übrig, als die PID so zu beziehen und dies dann über kill zu beenden:



ps aux | grep 'SCREEN -dmS sc1 /home/shoutcast/sc_serv' | grep -v grep | cut -c9-16 | sed s/" "/""/g
Leider bin ich aber im Moment überfragt, wieso er mir jetzt immer noch diese Fehlermeldung bringt:


h852677:~# kill "ps aux | grep 'SCREEN -dmS sc1 /home/shoutcast/sc_serv' | grep -v grep | cut -c9-16 | sed s/" "/""/g"
-bash: kill: ps aux | grep 'SCREEN -dmS sc1 /home/shoutcast/sc_serv' | grep -v grep | cut -c9-16 | sed s/: no such pid
-bash: kill: //g: no such pid
Führe ich den Befehl manuell einzeln ebenfalls in der Konsole aus, erhalte ich jedoch die PID...

Das ist kein Wunder - Du übergibst dem kill ja nicht die Ausgabe des Befehls, sondern einfach die Zeichenfolge des Befehls (der Teil "ps ..." wird also nicht ausgeführt, sondern als Argument an kill verfüttert). Dazu musst Du Backticks benutzen:
kill `ps aux ...`Zu Deinem Befehlsmarathon für die Ermittlung der PID: Das geht einfacher:
ps -o pid= -C 'SCREEN -dmS sc1 /home/shoutcast/sc_serv'Noch ein kleiner Tipp unabhängig davon: Wenn man eine Prozessliste greppt und dabei den grep nicht sehen will (logo, will man meist nicht), dann kann man sich den 2. "grep -v" mit folgendem Trick sparen:
ps aux | grep '[S]CREEN -dmS sc1 /home/shoutcast/sc_serv'Die eckigen Klammern um den 1. Buchstaben bilden für grep einen regulären Ausdruck, nämlich eine Menge aus genau einem Buchstaben - er findet also nach wie vor den SCREEN, aber nicht mehr sich selbst, weil da ja "[S]CREEN" steht.

Jan

EDIT: Ausserdem hast Du in der Befehlszeile einen Syntaxfehler. Mit dem ersten " im sed beendest Du das Argument, das mit dem " vor ps anfängt, ab dem "/... wird alles als neues Argument betrachtet (deshalb auch 2 Fehlermeldungen). Merke - innerhalb eines per "..." begrenzten Blocks muss jedes " entwertet werden (\").

Fireball22
08-01-2008, 15:23
Vielen Dank für deine Antwort!

Ich habe nun auch gleich mal deine Möglichkeit, die PID herauszufinden getestet, aber leider bringt mir der Befehl keine Ausgabe, obwohl das Kommando genau so in der Prozessliste steht.
An was könnte das liegen?

Die Ausgabe von ps aux:


root 28247 0.0 0.0 4348 1032 ? Ss 16:14 0:00 SCREEN -dmS sc1 /home/shoutcast/sc_serv
root 28248 0.2 0.0 37788 1764 pts/1 Ss+ 16:14 0:00 /home/shoutcast/sc_serv


Probier ich das ganze nun allerdings mit meinem "Befehlsmarathon", dann klappt das killen des screens zwar, nur beendet er dann nicht automatisch die Prozesse, die auf dem Screen laufen, was aber doch eig. der Fall sein möchte, oder nicht?
Gibt es da noch einen Trick um diesen direkt mitzukillen, oder muss ich den dann wohl oder über mit einer zweiten kill-Anweisung extra beenden?

Zudem bin ich gerade am überlegen, ob sich das ganze dann in so einem Prinzip verpacken lässt:

kill PID || kill -9 PID

Er würde dann so erstmal versuchen den Prozess BITTE beenden zu lassen, klappt das nicht, dann MUSS er eben den Prozess beenden?!
Nur ich bin mir nicht sicher, ob kill auch den richtigen Return-Code dafür zurückgibt um diese ODER-Anweisung richtig zu Verarbeiten?
Hast du damit vllt. schon Erfahrung?

MfG
Michael

PS: Und noch vielen Dank für die geniale Idee mit dem Regulären Ausdruck!
Da wär ich mal echt nicht drauf gekommen! ;)

meinereinerseiner
09-01-2008, 08:54
noch ein kleiner tip:

wenn du mit pid's & co. spielst, schaue dir mal pkill und pgrep und in deinem fall auch mit der option "-f" an. Das erleichtert das Scriptleben enorm.

der tom

jan61
10-01-2008, 22:12
Moin,


...Ich habe nun auch gleich mal deine Möglichkeit, die PID herauszufinden getestet, aber leider bringt mir der Befehl keine Ausgabe, obwohl das Kommando genau so in der Prozessliste steht.
An was könnte das liegen?


Schau Dir mal die Prozessliste mit einem "ps -ef" an. Der ps kann in 2 Modi laufen, nämlich dem "alten" UCB-Modus (das ist Dein "ps aux") und der heute eher gebräuchlichen SYSV-Syntax. Beide haben ihre Vorteile und Macken, aber die Ausgabe kann sich eben unterscheiden. Der Krieg ATT (aka SYSV-Unix) vs. UCB ist übrigens hier ganz nett beschrieben: http://www.livinginternet.com/i/iw_unix_war.htm - in der man-Page von ps findest Du beide Welten als "Linux" und "BSD" wieder. Aber das nur nebenbei.


Probier ich das ganze nun allerdings mit meinem "Befehlsmarathon", dann klappt das killen des screens zwar, nur beendet er dann nicht automatisch die Prozesse, die auf dem Screen laufen, was aber doch eig. der Fall sein möchte, oder nicht?
Gibt es da noch einen Trick um diesen direkt mitzukillen, oder muss ich den dann wohl oder über mit einer zweiten kill-Anweisung extra beenden?

Deshalb nutze ich immer die SYSV-Version des ps - damit kannst Du Dir z. B. alle Prozesse anzeigen lassen, die einer Session angehören (Option -s) und die dann in einem Rutsch killen. Es ist nicht zwingend so, dass die Kinder verrecken, wenn man den Papa abmurkst, das hängt davon ab, wie sie auf Signale des werten Erzeugers reagieren. Die Unix-Systeme gehen mit der Zeit - welches Kind hört heutzutage denn noch auf seine Eltern? :eek:


Zudem bin ich gerade am überlegen, ob sich das ganze dann in so einem Prinzip verpacken lässt:

kill PID || kill -9 PID

Er würde dann so erstmal versuchen den Prozess BITTE beenden zu lassen, klappt das nicht, dann MUSS er eben den Prozess beenden?!
Nur ich bin mir nicht sicher, ob kill auch den richtigen Return-Code dafür zurückgibt um diese ODER-Anweisung richtig zu Verarbeiten?
Hast du damit vllt. schon Erfahrung?

Nach meiner Erfahrung geht das so nicht. kill ist damit zufrieden, wenn er das Signal erfolgreich absetzen konnte. Wie die Prozesse darauf reagieren (sie können es z. B. per sigprocmask() einfach ignorieren oder sie warten gerade auf die Rückkehr eines System-Calls, dann sind sie im Status "nicht unterbrechbar"), ist deren Sache oder die des Kernels. Am besten ist es hier, das Verhalten eines Unix-Systems beim Shutdown nachzuahmen: Schicke zuerst mal ein "normales" kill an den Prozess, warte ein wenig (es kann sein, dass der Prozess ein wenig braucht, um Caches zu leeren, temp. Dateien aufzuräumen, einen Brief an die Freundin zu schicken ;-) und dann schicke ihm SIGKILL (-9) - dieses Signal kann kein Prozess ignorieren (es ist deshalb so unwiderstehlich, weil ein SIGIGNORE für dieses Signal technisch nicht funktioniert).

Jan

Fireball22
13-01-2008, 20:12
@meinereinerseiner
Vielen Dank für den Klasse Tipp mit dem pgrep und pkill, habe damit zwar schon auch vor ein paar Tagen etwas probiert, aber leider bin ich nie auf den Paramter -f gekommen, aber jetzt funktioniert das ganze ohne Probleme!

@jan61
Vielen Dank auch hier nochmals für deine genauen Erläuterungen zu meinem doch etwas "komplexeren" Problem!
Dann werde ich es einfach mal in diesem Stil versuchen:

pkill [SERVER]
wait
pkill -9 [SERVER] //Wenn Server nicht mehr läuft, wird ein Fehler ausgegeben
---
pkill [SCREEN]
wait
pkill -9 [SCREEN]

Nur die Frage ist jetzt noch, wie ich das mit dem "wait" realisiere, dass er eine bestimmte Zeit wartet, bis alle arbeiten für das Beenden des Prozesses erledigt sind, gibt es dafür ein passendes Kommando?

MfG
Michael

meinereinerseiner
13-01-2008, 20:19
Nur die Frage ist jetzt noch, wie ich das mit dem "wait" realisiere, dass er eine bestimmte Zeit wartet, bis alle arbeiten für das Beenden des Prozesses erledigt sind, gibt es dafür ein passendes Kommando?

MfG
Michael

z.B.: 5 Sekunden nichts tun:

sleep 5

tom

Fireball22
14-01-2008, 17:08
Vielen Dank für deine Antwort, habe jetzt geradeeben mal das ganze zusammengebaut und folgendes ist dabei rausgekommen:



./DeinScript_new: line 125: syntax error near unexpected token `('
./DeinScript_new: line 125: ` if [ $? -eq (0|1) ]; then'




if [ ${use_user} -eq 1 ]; then
su -c 'killall -9 "sc1" "${username}"'
else
## kill `ps aux | grep 'SCREEN -dmS sc1 /home/shoutcast/sc_serv' | grep -v grep | cut -c9-16 | sed s/" "/""/g`
pkill -f "${path_shoutcast}/sc_serv"
if [ $? -eq 0 ]; then
SUCCESS=1
fi
sleep 5
pkill -9 -f "${path_shoutcast}/sc_serv"
if [ $? -eq (0|1) ]; then
SUCCESS=1
fi
if [ ${success} -eq 1 ]; then
echo "done"
rm -f "${path_shoutcast}/server.pid"
else
echo "false"
fi

fi


Leider bin ich mir nicht genau sicher, ob dieser Regulärer Ausdruck stimmt, allerdings habe ich so etwas in einigen Berichten bei google gefunden.

MfG
Michael

jeebee
14-01-2008, 19:15
test, also [] kann nur "einfache" Werte vergleichen, falls ich deinen Code richtig interpretiere willst du:
if [ $? -eq 0 -o $? -eq 1 ]; then also Rückgabewert 0 oder 1.

Fireball22
14-01-2008, 19:54
Vielen Dank, genau nach so etwas habe ich schon vergeblich gesucht, habe das ganze auch schon mit ||-Operatoren versucht, aber damit möchte die BASH ja leider nicht arbeiten, aber jetzt klappts perfekt, vielen Dank! =)

MfG
Michael

jan61
14-01-2008, 21:22
Vorsicht mit der SUCCESS-Variablen. Wenn Du SUCCESS definierst, musst Du auch $SUCCESS abfragen, nicht $success.

Jan

P.S.: Die bash kann schon mit || arbeiten, aber der test nicht:

SUCCESS=1
pkill ...
[ $? -eq 0 -o $? -eq 1 ] || SUCCESS=0Die || signalisieren der bash: Wenn der vorhergehende Befehl einen Returncode ungleich 0 liefert, führe den danach folgenden Befehl aus. Analog mit &&:
SUCCESS=0
pkill ...
[ $? -eq 0 -o $? -eq 1 ] && SUCCESS=1Führt den 2. Befehl dann aus, wenn der davor mit Returncode 0 zurückkommt.

Fireball22
15-01-2008, 13:18
Vielen Dank, genau das habe ich gestern Abend auch noch herausgefunden, dass ich dort aus Versehen die Variable groß geschrieben habe, aber jetzt sollte auch das klappen =)

Genau, stimmt, nur leider funktioniert dieser Operator in den Tests nicht ;)

Aber ich werde jetzt naher gleich mal alle Funktionen des Scripts durchtesten und euch bescheid geben ob soweit alles funktioniert =)

MfG
Michael

Fireball22
17-01-2008, 14:58
So, jetzt habe ich mein Script in allen Kategorien komplett weiterentwickelt, aber leider hindert mich daran immer dieser Fehler:



h852677:~# su -c `pkill -f "/home/shoutcast/sc_serv"` 'shoutcast'
bash: line 1: shoutcast: command not found


Ich habe es mehrmals mit anderen Syntaxen probiert, obwohl dass doch soweit alles stimmen sollte, oder?

MfG
Michael

jan61
18-01-2008, 22:42
So, jetzt habe ich mein Script in allen Kategorien komplett weiterentwickelt, aber leider hindert mich daran immer dieser Fehler:



h852677:~# su -c `pkill -f "/home/shoutcast/sc_serv"` 'shoutcast'
bash: line 1: shoutcast: command not found
Ich habe es mehrmals mit anderen Syntaxen probiert, obwohl dass doch soweit alles stimmen sollte, oder?

MfG
Michael

Diese Syntax verstehe ich nicht. Was soll dieses 'shoutcast' am Ende? Und wieso übergibst Du die Standardausgabe des pkill-Kommandos an den "su -c" (das machst Du nämlich mit `..`)? pkill liefert auf stdout nichts zurück, wenn ich die man-Page richtig gelesen habe. Du willst doch alle Prozesse beenden, deren Kommandozeile auf "/home/shoutcast/sc_serv" matcht, oder? Dann sollte doch ein simples
pkill -f "/home/shoutcast/sc_serv"ausreichen, wenn Du das Script mit einem anderen Benutzer als root aufrufst, musst Du bei "su -c" dessen Passwort eingeben. Willst Du das?

Jan

Fireball22
19-01-2008, 10:46
Ja genau, so ähnlich möchte ich es.
Standardmäßig ist für den Benuzter shoutcast und ebenfalls in meinem Fall zwar kein Passwort festgelegt, aber um die Sicherheit in meinem Script zu erhöhen, möchte ich den Befehl gerne unter der Benutzerebene shoutcast killen, somit kann ich auch verhindern, dass andere Prozesse aus Versehen gekillt werden.

Eig. sollte das mit dem Befehl su -c COMMAND USER gehen, oder stimmt das nicht ganz?

MfG
Michael

rais
19-01-2008, 15:36
Moin moin,
versuch es mal mit


su -c 'pkill -f ".."' shoutcast

d. h., wenn der zu killende Prozess sowieso shoutcast gehört (und Du das darfst) vllt auch einfach


pkill -u shoutcast -f ".."

MfG,

Fireball22
19-01-2008, 17:14
Vielen Dank, genau so würde es funktionieren, allerdings sind die Pfade und der Benutzername ja variabel, und durch die Hochkomma werden die Variablen nicht mehr aufgelöst, siehe:



su -c `pkill -f "${path_shoutcast}/sc_serv"` "${username}"


Zudem finde ich die Idee, den User-Parameter direkt in pkill einzubauen nicht schlecht, aber aus Sicherheitsgründen ist es eher evtl. doch vllt. sicherer, wenn man direkt den ganzen Befehl mit einem niedrigeren User-Level ausführt.

Lässt sich da vllt. eine Möglichkeit finden?

MfG
Michael

rais
19-01-2008, 17:56
Moin moin,

Vielen Dank, genau so würde es funktionieren, allerdings sind die Pfade und der Benutzername ja variabel, und durch die Hochkomma werden die Variablen nicht mehr aufgelöst, siehe:



su -c `pkill -f "${path_shoutcast}/sc_serv"` "${username}"


warum -- schon wieder -- Backticks (`) und keine Hochkommata (')?
Ich hab das mal eben durchgespielt -- da ich sc_serv nicht hab, hab ich einfach stellvertretend xterm genommen und Testuser `bar' startet:


/usr/bin/xterm &

nun komm ich daher:


x=/usr/bin
su -c 'pkill -f "$x/xterm"' bar

und bars xterm verabschiedet sich.;)
MfG,

jan61
19-01-2008, 19:40
Moin,


warum -- schon wieder -- Backticks (`) und keine Hochkommata (')?

1. - ja, warum? Da hab ich doch extra einen (hoffentlich verständlichen) Satz zu geschrieben. Anmerkung: Das Hochkomma ist <SHIFT>#, der Backtick ist <SHIFT>´ (die Taste links neben dem <BACKSPACE> oben rechts).

2. Und warum Hochkommata? Die Variablen werden darin NICHT aufgelöst - hatte ich auch schon geschrieben!


Ich hab das mal eben durchgespielt -- da ich sc_serv nicht hab, hab ich einfach stellvertretend xterm genommen und Testuser `bar' startet:


/usr/bin/xterm &
nun komm ich daher:


x=/usr/bin
su -c 'pkill -f "$x/xterm"' bar
und bars xterm verabschiedet sich.

Das funktioniert nur deshalb, weil die -f-Option ein Pattern definiert, in Deinem pkill kommt nämlich 'pkill -f "/xterm"' an, das matcht eben auch auf "/usr/bin/xterm". Probiers aus:
su -c 'echo pkill -f "$x/xterm"' bar@Fireball22: Mach Dir doch das Leben nicht unnötig schwer. Du versiehst alles, was länger als eine halbe Sekunde stillhält, ohne Not mit ', ", {} oder ` - offenbar ohne Dir über die Auswirkungen im Klaren zu sein.

Ich versuche nochmal eine kleine Erklärung:

1. Eine Variable in der Shell wird mit variable=... definiert. Für den Teil nach dem = sind die Besonderheiten lt. 2. - 6. zu beachten.

2. Eine Variable in der Shell wird mit $variable abgefragt. Nur in den Fällen, in denen NACH dem VariablenNAMEN ein Zeichen folgt, das als Teil eines Variablennamens interpretiert werden könnte, muss die Schreibweise ${variable} verwendet werden. Ein Leerzeichen oder "" gehören definitiv nicht dazu, also reicht "$username".

3. Eine Variable in der Shell wird mit $variable abgefragt. Nur in den Fällen, in denen der VariablenINHALT einen Whitespace (Leer-, Tabulatorzeichen) oder Zeilenumbruch enthalten kann, der als Argument-Trenner interpretiert werden kann, muss die Variable mit "" umschlossen werden. Das trifft auf Benutzernamen definitiv nicht zu, also reicht ein $username.

4. Ein mit "" umschlossenes Argument entwertet z. B. Whitespaces, aber z. B. keine $-Zeichen, die die Shell als Beginn eines Variablen-Namens oder ``, die als auszuführender Befehl interpretiert werden. Variablen oder `...`-Kommandos innerhalb von "" werden also aufgelöst / ausgeführt.

5. Ein mit '' umschlossenes Argument entwertet ALLES, also auch $-Zeichen - es wird nix ausgewertet.

Das führt im o. a. Beispiel z. B. dazu, dass der su -c 'pkill -f "$x/xterm"' an die durch "su -c" gestartete Subshell das Kommando pkill -f "$x/xterm" durchreicht. In dieser Subshell ist $x aber gar nicht bekannt - sie wird folglich durch nix ersetzt, heraus kommt pkill -f /xterm. Wenn man das verhindern will, gibt es 2 Möglichkeiten: Entweder man exportiert die Variable x oder man ruft das Kommando so auf: su -c "pkill -f '$x/xterm'".

6. Die Backticks `` haben eine völlig andere Bedeutung. Alles, was innerhalb dieser Backticks steht, wird von der aufrufenden Shell als Kommando betrachtet und ausgeführt. Das, was dieses Kommando auf stdout ausgibt, wird an die Stelle des `..`-Blocks gesetzt. Auch hier gelten wieder die unter 4. und 5. genannten Besonderheiten.

7. Ein su $username -c kommando mag sicherer sein wegen der fehlenden Berechtigungen, aber rais hat auch eine bessere Variante beschrieben, nämlich stattdessen pkill -u $username -f "..." zu nutzen. Damit sparst Du eine Subshell. Ein Blick in die man-Page von pkill hätte Dir das auch verraten. Der su-Befehl würde Dir nämlich unnötige Fehlermeldungen bringen, wenn er sc_serv-Prozesse von anderen Benutzern killen will und nicht kann. die -u-Option des pkill schränkt die zu killenden Prozesse dagegen von vornherein auf die des angegebenen Benutzers ein und versucht gar nicht erst, in fremden Revieren zu wildern. Und ganz nebenbei: UserNAMEN sind Schall und Rauch, es kommt allein auf die UserID an. Wenn Dein shoutcast-Benutzer die UID 0 hat, würde der pkill trotzdem die sc_serv-Prozesse aller Benutzer killen.

Jan

P.S.: Das Verhalten der Shell in Bezug auf die o. g. Punkte ist in der (zugegebenermaßen ziemlich umfangreichen) man-Page der Shell ausführlich beschrieben. Ich hab sie mir vor ganz langer Zeit einfach mal ausgedruckt ...

Fireball22
19-01-2008, 19:44
Vielen Dank für deine Antwort!

Also ich habe mich darauf nur auf die Antwort #12 von jan61 bezogen:


In einfache Hochkommata eingeschlossener Text wird durch die Shell nicht ausgewertet, die Variable ${path_shoutcast} wird also nicht durch den Inhalt ersetzt.


Aber du hast echt recht, ich habe es gerade selber ausprobiert, es funktioniert tatsächlich! =)
Vielen Dank nochmals!

Aber wann nimmt man dann die Backsticks, die Hochkommata und wann die normalen Anführungszeichen?

MfG
Michael

EDIT:
@jan61
Hab mein Posting leider währenddessen verfasst, als du mir schon zurück geschrieben hast =)
Vielen Dank für deine ausführliche Erklärung!
Dass das ganze dann natürlich als Pattern interpretiert wird, erklärt alles ;)

Ich werd mich dann jetzt naher aufjedenfall auch nochmals deine Definitionen ganz genau durchlesen, dass ich in Bezug auf das ganze keine Fehler mehr in Zukunft machen werde!

Vielen Dank nochmals! =)

jan61
19-01-2008, 19:50
Moin,

4 Minuten vor Deiner Antwort hab ich meine abgeschickt - da steht (hoffentlich ,-) alles drin. Das hat sich offenbar überschnitten.

Jan

jan61
19-01-2008, 20:10
...@jan61
Hab mein Posting leider währenddessen verfasst, als du mir schon zurück geschrieben hast =)...

So kanns eben kommen :rolleyes: Während Du das EDIT verfasst hast, hab ich meine nächste Antwort geschrieben - ist eben asynchrone Kommunikation hier. Manchmal ist ein IRC doch nicht zu verachten ;-), aber da kann man nicht mehr korrigieren, wenn man Mist verzapft hat :o


Ich werd mich dann jetzt naher aufjedenfall auch nochmals deine Definitionen ganz genau durchlesen, dass ich in Bezug auf das ganze keine Fehler mehr in Zukunft machen werde!

Fehler passieren jedem - sonst wäre hier ja gar nix los ;-) - und solche Sachen wie Hochkomma, Backtick oder Anführungszeichen erschließen sich nun mal nicht sofort. Da hilft nur üben, üben, üben (und lesen, lesen, lesen) und da bist Du ja auf dem richtigen Weg.

Jan

P.S.: Hatte ich schon erwähnt, dass ein "set -x" am Anfang des Scripts wahre Wunder wirkt, wenn man dahinter steigen will, was die Shell wirklich veranstaltet? :cool:

Fireball22
20-01-2008, 11:53
Vielen Dank für deine Antwort!

Also das set -x steht seit einem deiner vorherigen Postings in meinem Script, das ist in der Tat echt sehr hilfreich!

Jetzt hätte ich allerdings noch ein paar Fragen:

1) Damit das Script weiß, ob bereits ein SHOUTCAST-Server läuft, legt das Script nach erfolgreichem starten eine leere PID-File an, welche dann beim nächsten Startversuch abgefragt wird, ob diese bereits existiert.
Allerdings wäre es etwas umständlicher auch möglich eine art Realtime-Abfrage unter den Prozessen zu machen, ob dieser in der Realität auch läuft und dieser nicht währenddessen manuell gekillt wurde, die PID-File aber allerdings nicht gelöscht wurde.
Meine Frage wäre jetzt, ob es ausreichend ist, diese Prüfung mit einer PID-File durchzuführen?

2) Um das Script möglichst klein zu halten, gilt für die Funktionen mit und ohne User der gleiche PID-File-Löschbefehl.


rm -f PFAD/ZUR/PID-FILE

Sollte ich aber auch speziell noch eine Methode anbieten, bei der auch die PID-File nur mit den Rechten des angegeben Users gelöscht wird, oder muss man da mit keinen Sicherheitsrisiken rechnen?

3) Mein Script bietet ja auch eine Restart-Funktion.
Gerne würde ich dort nicht den ganzen Code neu aufrollen um das Script so klein wie möglich zu halten.
Nur wie kann ich den Dateinamen des gerade laufenden Scripts ermitteln, da ich diesem ja im Script nicht fest definieren kann, falls dieser Dateiname mal geändert wird.

4) Es soll auch eine SCREEN-Methode geben, die unter einem bestimmten Benutzer läuft, da SCREEN aber leider selber keine Parameter dafür anbietet, würde ich das ganze gerne so realisieren:


screen -dmS sc1 'su -c "${path_shoutcast}/sc_serv" $username'


Das Script wird erfolgreich ohne Fehlermeldungen ausgeführt, allerdings wird trotzdem kein Server gestartet, was die Ausgabe von ps aux und ps -ef bestätigt.
Kann das mit dem exportieren der Variablen zusammenhängen?

MfG
Michael

jan61
20-01-2008, 13:54
...1) Damit das Script weiß, ob bereits ein SHOUTCAST-Server läuft, legt das Script nach erfolgreichem starten eine leere PID-File an, welche dann beim nächsten Startversuch abgefragt wird, ob diese bereits existiert.
Allerdings wäre es etwas umständlicher auch möglich eine art Realtime-Abfrage unter den Prozessen zu machen, ob dieser in der Realität auch läuft und dieser nicht währenddessen manuell gekillt wurde, die PID-File aber allerdings nicht gelöscht wurde.
Meine Frage wäre jetzt, ob es ausreichend ist, diese Prüfung mit einer PID-File durchzuführen?

Zur Realtime-Abfrage kannst Du eigentlich auf PID-Files verzichten und stattdessen das schon erwähnte pgrep benutzen (ist mit in der Man-Page von pkill beschrieben und versteht die gleichen Parameter). PID-Files haben den Nachteil, den Du ja schon erkannt hast: Wenn der Prozess von außen beendet wurde, kann er es nicht mehr abräumen. Eine andere Variante wäre es, die PID des Shoutcast-Servers in die Datei zu schreiben und diese dann zu prüfen. Macht aber mehr Aufwand.


2) Um das Script möglichst klein zu halten, gilt für die Funktionen mit und ohne User der gleiche PID-File-Löschbefehl.


rm -f PFAD/ZUR/PID-FILE
Sollte ich aber auch speziell noch eine Methode anbieten, bei der auch die PID-File nur mit den Rechten des angegeben Users gelöscht wird, oder muss man da mit keinen Sicherheitsrisiken rechnen?

Hängt davon ab, was Du willst. Wenn es verschiedene Shoutcast-Prozesse geben soll, die unter verschiedenen Benutzern gleichzeitig laufen, dann musst Du Dir sowieso um die Benennung der Dateien Gedanken machen. Wenn die Datei nur zur Markierung "hier läuft ein sc_serv" gedacht ist, dann sollte sie auch immer weggeputzt werden, wenn der Server gestoppt ist. Dann handelst Du Dir nur Probleme ein, wenn die Datei bei Stop nicht gelöscht wird.


3) Mein Script bietet ja auch eine Restart-Funktion.
Gerne würde ich dort nicht den ganzen Code neu aufrollen um das Script so klein wie möglich zu halten.
Nur wie kann ich den Dateinamen des gerade laufenden Scripts ermitteln, da ich diesem ja im Script nicht fest definieren kann, falls dieser Dateiname mal geändert wird.

Wenn ich mich recht erinnere, rufst Du doch immer das gleiche Script auf, nur mit anderen Parametern (start, stop, restart)? In dem Fall ist der effektivste Weg, die Funktionalität für "start" und "stop" in Funktionen auszulagern, dann brauchst Du für "restart" nur nacheinander die stop- und start-Funktion aufzurufen. Der Dateiname des Scripts steht in $0.


4) Es soll auch eine SCREEN-Methode geben, die unter einem bestimmten Benutzer läuft, da SCREEN aber leider selber keine Parameter dafür anbietet, würde ich das ganze gerne so realisieren:


screen -dmS sc1 'su -c "${path_shoutcast}/sc_serv" $username'
Das Script wird erfolgreich ohne Fehlermeldungen ausgeführt, allerdings wird trotzdem kein Server gestartet, was die Ausgabe von ps aux und ps -ef bestätigt.
Kann das mit dem exportieren der Variablen zusammenhängen?

Ja, da bist Du wieder in die '' / ""-Falle getappt. Mit Deiner Syntax kommt der Befehl im su -c unverändert an (ohne die Variablen zu ersetzen) und damit wirkt er nur dann, wenn $path_shoutcast und $username exportiert wurden. Letztendlich will su -c ausführen: "/sc_serv", weil beide Variablen in dieser Subshell nicht bekannt sind und damit leer ersetzt werden. Nimm die andere Reihenfolge:

screen -dmS sc1 "su -c '${path_shoutcast}/sc_serv' $username"
Den Unterschied müsstest Du eigentlich bei set -x in der Ausgabe sehen.

Jan

Fireball22
20-01-2008, 16:43
Vielen Dank für deine Antworten!

Dann werde ich das auch mit der Restart-Funktion alles so umsetzten und das ganze einfach kompakter halten!

Und mit dem Status-Check, ob der Server bereits gestartet ist oder nicht, werde ich es dann wohl so in der Art machen:



if [ 'pgrep -f "${path_shoutcast}/sc_serv"' -eq 0 ]; then
#CODE CODE CODE
fi


Und bezüglich des Exports:
Ich bekomme hier beim exportieren immer diesen Fehler:



h852677:~# ./DeinScript_new start
+ path_shoutcast=/home/shoutcast
+ use_screen=1
+ use_user=1
+ username=shoutcast
+ '[' '!' -e /home/shoutcast/server.pid ']'
+ '[' 1 -eq 1 ']'
+ '[' 1 -eq 1 ']'
+ export /home/shoutcast
./DeinScript_new: line 29: export: `/home/shoutcast': not a valid identifier
+ export shoutcast
+ screen -dmS sc1 'su -c '\''/home/shoutcast/sc_serv'\'' shoutcast'
+ '[' 0 -eq 0 ']'
+ echo 11694
+ echo -ne '\033[0;32mDONE\033[0m Server wurde gestartet\n\033[0;32mDONE\033[0m PID-File wurde erfolgreich angelegt\n'
DONE Server wurde gestartet
DONE PID-File wurde erfolgreich angelegt
+ exit 0


Der Code sieht so aus:



export $path_shoutcast
export $username
screen -dmS sc1 "su -c '${path_shoutcast}/sc_serv' $username"


Ich dachte am Anfang, dass sich das mit Anführungszeichen sämtlicher Art beheben lässt, aber leider ging es auch dann noch nicht.
Und der Server wird leider nach wie vor noch nicht gestartet... hmmm...

MfG
Michael

EDIT:
So, jetzt habe ich geradeeben den Restart-Bereich zusammengeschrieben und ausführlich getestet und das ist jetzt dabei rausgekommen. Es klappt alles perfekt, allerdings wollte ich doch nochmals Fragen, ob man noch etwas daran verbessern könnte. Z. B. gibt es bei PHP die Möglichkeit Code zu includieren, ist das in der Art unter Linux auch möglich, dass man nur eine bestimmte Code-Passage herausnimmt und nicht z .B. Variablen beim Aufruf des Parameters start nochmals setzt? (Das spielt hier natürlich keine Rolle auf das Script, aber vllt. gibt es ja so eine Möglichkeit wie unter PHP).


restart)
if [ -e "${path_shoutcast}/server.pid" ]; then
${0} stop
if [ $? -eq 0 ]; then
stop=1
fi
sleep 5
${0} start
if [ $? -eq 0 ]; then
start=1
fi
if [ $stop -eq 1 -a $start -eq 1 ]; then
echo -ne "\033[0;32mDONE\033[0m Server wurde erfolgreich neugestartet\n"
else
echo -ne "\033[0;31mERROR\033[0m Beim Neustarten des Servers ist ein Fehler aufgetreten...\nBitte Debug-Modus starten...\n"
fi
else
echo -ne "\033[0;31mERROR\033[0m Server scheint nicht online zu sein...\nBitte zuerst starten...\n"
fi
;;


Und dann wollte ich euch noch Fragen, was ihr von der Idee hält, dass ich das Script wenn es komplett fertig ist, hier veröffentliche, denn wenn ihr mir alle schon so sehr damit behilflich seit, dann würde ich das Script auch gerne der ganzen Welt zur Verfügung stellen, dann haben auch andere was davon, wenn sie genau solch ein Script suchen =)

rais
20-01-2008, 22:25
2. Und warum Hochkommata? Die Variablen werden darin NICHT aufgelöst - hatte ich auch schon geschrieben!

uups :o


Das funktioniert nur deshalb, weil die -f-Option ein Pattern definiert, in Deinem pkill kommt nämlich 'pkill -f "/xterm"' an, das matcht eben auch auf "/usr/bin/xterm". Probiers aus:
su -c 'echo pkill -f "$x/xterm"' bar

...und check -- und Danke;-)


5. Ein mit '' umschlossenes Argument entwertet ALLES, also auch $-Zeichen - es wird nix ausgewertet.

Das führt im o. a. Beispiel z. B. dazu, dass der su -c 'pkill -f "$x/xterm"' an die durch "su -c" gestartete Subshell das Kommando pkill -f "$x/xterm" durchreicht. In dieser Subshell ist $x aber gar nicht bekannt - sie wird folglich durch nix ersetzt, heraus kommt pkill -f /xterm. Wenn man das verhindern will, gibt es 2 Möglichkeiten: Entweder man exportiert die Variable x oder man ruft das Kommando so auf: su -c "pkill -f '$x/xterm'".

Damit hab ich gerade ein Verständnisproblem: bedeutet das, daß die umliegenden ".." die inneren '..' entwerten oder bin ich (schon wieder) auf dem Holzweg?





if [ 'pgrep -f "${path_shoutcast}/sc_serv"' -eq 0 ]; then
#CODE CODE CODE
fi


wenn ich Jan und Dich richtig verstanden hab: wolltest Du vielleicht ein


if [ -n `pgrep -f "${path_shoutcast}/sc_serv"` ]; then
?
Soweit ich das bisher verstanden hab, ist die Ausgabe von pgrep die entsprechende PID (so es nur um eine geht), aber Du vergleichst auf dessen Rückgabewert (0 für da gibt's was, 1 für nix passt etc.), wie es z. B. in $? direkt nach einem pgrep steht...
Aber in bezug auf die Shell hab ich mich schon öfter vertan;-)

MfG,

jan61
20-01-2008, 23:10
..Damit hab ich gerade ein Verständnisproblem: bedeutet das, daß die umliegenden ".." die inneren '..' entwerten oder bin ich (schon wieder) auf dem Holzweg?

Nö, da liegst Du richtig.


wenn ich Jan und Dich richtig verstanden hab: wolltest Du vielleicht ein


if [ -n `pgrep -f "${path_shoutcast}/sc_serv"` ]; then
?
Soweit ich das bisher verstanden hab, ist die Ausgabe von pgrep die entsprechende PID (so es nur um eine geht), aber Du vergleichst auf dessen Rückgabewert (0 für da gibt's was, 1 für nix passt etc.), wie es z. B. in $? direkt nach einem pgrep steht...

Naja, fast ;-) Bei Fireball22's Code wird verglichen, ob die Zeichenkette 'pgrep ...' numerisch gleich 0 ist - isse natürlich nie. Da hier '' und nicht `` verwendet werden, wird 1. nichts von der Shell expandiert und 2. nichts ausgeführt. Um den Returncode abzufragen, verwendet man entweder:
pgrep ...
if [ $? -eq 0 ]; then # Erfolg
...oder kurz:
if pgrep ...; thenDie 2. Variante klappt deshalb, weil die if-Abfrage der Shell ja nur wissen will, ob der übergebene Ausdruck = 0 = OK ist (der test macht auch nix anderes - er liefert 0 zurück, wenn die Bedingung erfüllt ist). So kann Fireball22 auch vorgehen, da pgrep 1 als Returncode liefert, wenn kein Prozess die Bedingung matcht (siehe Abschnitt "EXIT STATUS" im Manual).

Man kann natürlich auch wie von Dir vorgeschlagen vorgehen und prüfen, ob der pgrep eine PID (oder mehrere) zurückliefert. Und da liegt in Deinem Code eine Falle: Es können nämlich keine oder auch mehrere werden, und dann kriegst Du einen Syntax-Error, weil aus

if [ -n `pgrep -f "${path_shoutcast}/sc_serv"` ]; then
dann sowas wird:
# kein Prozess gefunden
if [ -n ]; then
# mehrere Prozesse gefunden
if [ -n 0815 4711 ]; then
Man muss also wieder tarnen:

# Variante 1
if [ -n "`pgrep -f '${path_shoutcast}/sc_serv'`" ]; then
# Variante 2
if [ -n "`pgrep -f \"${path_shoutcast}/sc_serv\"`" ]; then
In Variante 2 habe ich einfach die "" stehen lassen und sie nur vor der Shell versteckt, die das Teilchen zwischen den `` auswertet. Dann wird daraus nach Ausführen des in `` gepackten Kommandos:
# nix gefunden
if [ -n "" ]; then
# mehrere Treffer
if [ -n "0815 4711" ]; then
und die Shell (bzw. deren Vertreter test) ist zufrieden.

Jan

rais
21-01-2008, 18:17
Moin Jan,
Danke!



Man kann natürlich auch wie von Dir vorgeschlagen vorgehen und prüfen, ob der pgrep eine PID (oder mehrere) zurückliefert. Und da liegt in Deinem Code eine Falle: Es können nämlich keine oder auch mehrere werden, und dann kriegst Du einen Syntax-Error, weil aus

if [ -n `pgrep -f "${path_shoutcast}/sc_serv"` ]; then
dann sowas wird:
# kein Prozess gefunden
if [ -n ]; then
# mehrere Prozesse gefunden
if [ -n 0815 4711 ]; then


es ist auf dieser Kiste (OpenSuSE10.2) sogar noch schlimmer: Im Fall "kein Prozess gefunden" gibt es noch nicht einmal eine Fehlermeldung... und bei beiden Fällen (kein Prozess/mehrere Prozesse gefunden) ergibt sich der falsche Status.
Oha, da kann man sich selbst ganz schön mit reinlegen :eek:

Das zeigt doch wieder einmal wie wichtig es beim Testen ist, wirklich alle denkbaren Szenarien durchzuspielen.:cool:

@Fireball22: Apropos denkbare Szenarien: sollte man hier dem pgrep nicht auch die -u-Option mitgeben, damit nicht mit auf den Prozess eines anderen Benutzers gematcht wird?

MfG,

Fireball22
21-01-2008, 20:44
Vielen Dank für eure ganzen Tipps und Hilfe zu meinem Problem!

Dann wäre glaub die einzigste Methode, dass ich das ganze so prüfe, denn bei mir gibt es ja auch die Möglichkeit einen User anzugeben.



if [ [ `pgrep -f "${path_shoutcast}/sc_serv"` -a $use_user -eq 0 ] -o [ `pgrep -u $username -f "${path_shoutcast}/sc_serv"` -a $use_user -eq 1 ] ]; then
#...
fi


So müsste ich doch dann alles in einem Abfragen könne, ob ein Prozess läuft, wenn ein bestimmter User im Script festgelegt ist, mit dem Parameter -u und ansonsten ohne bestimmte User-Angabe.
Trifft keines der beiden Tests zu, dann wird die Fehlermeldung ausgegeben, dass der Server noch nicht gestartet ist, kann man das ganze so in der Art realisieren?

Und leider bin ich mit diesem Problem noch nicht weitergekommen, ich komm einfach nicht drauf, wo hier das Problem eig. liegt:


Und bezüglich des Exports:
Ich bekomme hier beim exportieren immer diesen Fehler:

Code:

h852677:~# ./DeinScript_new start
+ path_shoutcast=/home/shoutcast
+ use_screen=1
+ use_user=1
+ username=shoutcast
+ '[' '!' -e /home/shoutcast/server.pid ']'
+ '[' 1 -eq 1 ']'
+ '[' 1 -eq 1 ']'
+ export /home/shoutcast
./DeinScript_new: line 29: export: `/home/shoutcast': not a valid identifier
+ export shoutcast
+ screen -dmS sc1 'su -c '\''/home/shoutcast/sc_serv'\'' shoutcast'
+ '[' 0 -eq 0 ']'
+ echo 11694
+ echo -ne '\033[0;32mDONE\033[0m Server wurde gestartet\n\033[0;32mDONE\033[0m PID-File wurde erfolgreich angelegt\n'
DONE Server wurde gestartet
DONE PID-File wurde erfolgreich angelegt
+ exit 0

Der Code sieht so aus:

Code:

export $path_shoutcast
export $username
screen -dmS sc1 "su -c '${path_shoutcast}/sc_serv' $username"

Ich dachte am Anfang, dass sich das mit Anführungszeichen sämtlicher Art beheben lässt, aber leider ging es auch dann noch nicht.
Und der Server wird leider nach wie vor noch nicht gestartet... hmmm...


MfG
Michael

rais
21-01-2008, 23:25
hmm, mal sehen :)


Dann wäre glaub die einzigste Methode, dass ich das ganze so prüfe, denn bei mir gibt es ja auch die Möglichkeit einen User anzugeben.



if [ [ `pgrep -f "${path_shoutcast}/sc_serv"` -a $use_user -eq 0 ] -o [ `pgrep -u $username -f "${path_shoutcast}/sc_serv"` -a $use_user -eq 1 ] ]; then
#...
fi


hier machst Du es Dir imho noch zu einfach: was passiert, wenn Du das Skript bereits unter anderem Benutzernamen laufen lässt und diesmal ohne $use_user das Teil (re)startest? D. h., wer bist Du -- öhhm, der Nutzer Deines Programms -- denn, wenn $use_user 0 ist? Afaik wäre das $UID...;-)


Und leider bin ich mit diesem Problem noch nicht weitergekommen, ich komm einfach nicht drauf, wo hier das Problem eig. liegt:

Die Meldung


+ export /home/shoutcast
./DeinScript_new: line 29: export: `/home/shoutcast': not a valid identifier

klingt doch verdächtig danach, daß Du den export lieber mit


export path_shoutcast
versuchen solltest, statt mit


export $path_shoutcast

schließlich kannst Du auch den export direkt vor eine etwaige Zuweisung setzen:


export path_shoutcast=/home/shoutcast

...das würde bedeuten, daß $path_shoutcast bei Dir erst expandiert wird, bevor es exportiert wird -- zumindest klingt die Meldung so für mich, auch wenn ich das auf dieser Kiste nicht direkt nachvollziehen kann.;)
Und wenn es bei Dir auch eine Variable $shoutcast gibt, dann würde das erklären, warum Du beim export $username keinen Fehler bekommst -- statt username wird hier dann einfach shoutcast exportiert..

MfG,

Fireball22
22-01-2008, 20:59
Vielen Dank für dein Posting!

Bezüglich der If-Anweisung werde ich mir morgen nochmals gründlich Überlegungen darüber machen, aber die export-Anweisung habe ich geradeeben korrigiert =)

Also leider hab ich das jetzt aus der Fehlermeldung nicht so direkt rauslesen können, weil ich damit leider auch noch nicht so oft damit etwas zu tun hatte, aber jetzt weis ich bescheid =)

Der ausgeführte Code sieht nun so aus:


h852677:~# ./DeinScript_new start
+ path_shoutcast=/home/shoutcast
+ use_screen=1
+ use_user=1
+ username=shoutcast
+ '[' '!' -e /home/shoutcast/server.pid ']'
+ '[' 1 -eq 1 ']'
+ '[' 1 -eq 1 ']'
+ export path_shoutcast
+ export username
+ screen -dmS sc1 'su -c '\''/home/shoutcast/sc_serv'\'' shoutcast'
+ '[' 0 -eq 0 ']'
+ echo 10176
+ echo -ne '\033[0;32mDONE\033[0m Server wurde gestartet\n\033[0;32mDONE\033[0m PID-File wurde erfolgreich angelegt\n'
DONE Server wurde gestartet
DONE PID-File wurde erfolgreich angelegt
+ exit 0


Allerdings wird der Prozess immer noch nicht gestartet, wo könnte denn dort noch das Problem liegen?
Hmm... das ist echt seltsam, vorallem weil er ja auch die PID des Prozesses ausgibt, er aber nicht unter ps -ef oder ps aux erscheint...

MfG
Michael

rais
22-01-2008, 23:03
Moin moin,


Also leider hab ich das jetzt aus der Fehlermeldung nicht so direkt rauslesen können, weil ich damit leider auch noch nicht so oft damit etwas zu tun hatte, aber jetzt weis ich bescheid =)

naja, soo viel sagen mir die Meldungen ja auch noch nicht;-)

Und Korrektur: der vorherige export $username hat einfach die shoutcast-Variable exportiert, ob Du der nu was zugewiesen hast oder nicht.


Allerdings wird der Prozess immer noch nicht gestartet, wo könnte denn dort noch das Problem liegen?
Hmm... das ist echt seltsam, vorallem weil er ja auch die PID des Prozesses ausgibt, er aber nicht unter ps -ef oder ps aux erscheint...

Was passiert eigentlich, wenn Du den Aufruf umdrehst, so daß auch screen als shoutcast läuft?


su -c "screen -dmS sc1 '${path_shoutcast}/sc_serv'" $username

Das mag Dir im Script die falsche PID rausrücken, aber rein funktionell?

MfG,

Fireball22
23-01-2008, 15:14
Vielen Dank, so funktioniert das ganze perfekt!
Nur ich dachte immer, dass für andere Benutzer, die Rechte nicht ausreichend sind, um das Programm screen zu verwenden, so war es zumindest auf meinem alten Suse-System, jetzt verwende ich allerdings Debian 3.1 Sarge.



hmm, mal sehen
Zitat:
Zitat von Fireball22 Beitrag anzeigen
Dann wäre glaub die einzigste Methode, dass ich das ganze so prüfe, denn bei mir gibt es ja auch die Möglichkeit einen User anzugeben.

Code:

if [ [ `pgrep -f "${path_shoutcast}/sc_serv"` -a $use_user -eq 0 ] -o [ `pgrep -u $username -f "${path_shoutcast}/sc_serv"` -a $use_user -eq 1 ] ]; then
#...
fi

hier machst Du es Dir imho noch zu einfach: was passiert, wenn Du das Skript bereits unter anderem Benutzernamen laufen lässt und diesmal ohne $use_user das Teil (re)startest? D. h., wer bist Du -- öhhm, der Nutzer Deines Programms -- denn, wenn $use_user 0 ist? Afaik wäre das $UID...;-)


Hehe, also ich hab mir dein Posting jetzt mehrmals durchgelesen, aber ich vesteh leider nicht ganz wie du das meinst ;)
Meinst du damit, dass wenn man z. B. jetzt den Server startet, dann Parameter in meinem Script ändert und erneut starten möchte, er dann nicht erkennt, ob der Server bereits läuft?
An sowas hab ich ja aber allerdings noch nicht gedacht, da mein Script eig. für den Single-Server betrieb ausgelegt sein sollte.
Und meinst du auch, dass ich noch irgendwo die UID statt den Benutzernamen einbauen sollte?
Allerdings würde dass doch für den Anwender nur eine Umständlichkeit bedeuten, oder nicht?

MfG
Michael

jan61
23-01-2008, 22:15
...daß Du den export lieber mit


export path_shoutcast
versuchen solltest, statt mit


export $path_shoutcast
schließlich kannst Du auch den export direkt vor eine etwaige Zuweisung setzen:


export path_shoutcast=/home/shoutcast
...das würde bedeuten, daß $path_shoutcast bei Dir erst expandiert wird, bevor es exportiert wird...

Stimmt - export erwartet den Identifier (also Variablennamen) so wie eine Zuweisung ohne $. Kleiner Tipp noch: Wenn man sich über die Syntax in Shell-Scripts unsicher ist und nicht erst lange Doku wälzen will, hilft oft ein Blick nach /etc/init.d, in den Start-Scripts dort findet man vieles. Einfach mal ein "grep export *" dort absetzen.

Jan

jan61
23-01-2008, 22:22
...Meinst du damit, dass wenn man z. B. jetzt den Server startet, dann Parameter in meinem Script ändert und erneut starten möchte, er dann nicht erkennt, ob der Server bereits läuft?
An sowas hab ich ja aber allerdings noch nicht gedacht, da mein Script eig. für den Single-Server betrieb ausgelegt sein sollte.

Ich glaube, rais meinte es so:
1. Dürfen auf dem Rechner mehrere Shoutcast-Prozesse unterschiedlicher User gleichzeitig laufen oder immer nur einer?
2. Was ist der Unterschied zwischen einem sc_serv, der mit einem Usernamen gestartet wird und dem, der ohne User gestartet wird? Läuft der unter root?

Abhängig davon solltest Du das Script aufbauen. Wenn es eh nur einen geben kann, dann ist mir der Sinn der Option, den sc_serv mit einem Benutzernamen zu starten, nämlich nicht ganz klar.

Wenn es mehrere sc_serv geben kann - wofür ist dann das Starten / Stoppen ohne Benutzernamen gut? Zum Killen aller sc_serv-Prozesse?

usw.

Jan

Fireball22
25-01-2008, 22:45
Ja das stimmt schon, aber mein Script ist eigentlich auch nur dazu gedacht, um EINEN Shoutcast-Server, der egal unter welchem Nutzer läuft kontrolliert werden kann.

Bei der Möglichkeit, sc_serv ohne einen bestimmten User zu starten, wird der Server mit den aktuellen Rechten ausgeführt, was natürlich nicht zu empfehlen ist, da die meisten SHOUTCast-Server unter vollen Root-Rechten laufen.
Mit der User-Option wird die Sicherheit des Servers so noch einmal deutlich erhöht ;)
Das ist der Sinn dieser User-Option.
Allerdings ist es in beiden Fällen bis jetzt mit meinem Script nicht möglich, mehrere Server gleichzeitig im System laufen zu lassen. (Aber ich denke mal nicht, dass auf einem Server auf einem normalen Anwender-System gleich mehr als ein SHOUTCast-Server läuft, oder?)

Wenn das alles soweit passt, wäre dann die Test-Anweisung doch evtl. richtig? =)

Der Unterschied bei der Test-Anweisung besteht darin, dass er bei dem zweiten Test nochmals explizit nur nach dem Prozessen unter der USERNAME-Liste schaut und so gar nicht mal mit anderen Prozessen in "Berührung" kommt.

Ist das soweit richtig? =)

MfG
Michael

rais
26-01-2008, 17:25
Moin moin,

Ja das stimmt schon, aber mein Script ist eigentlich auch nur dazu gedacht, um EINEN Shoutcast-Server, der egal unter welchem Nutzer läuft kontrolliert werden kann.

also wenn es eh nur einen im System geben kann, dann bist Du mit dem von jan61 bereits gezeigtem


if pgrep ... ; then
bestens gerüstet -- dann interresiert Dich doch nur, ob so ein Teil bereits läuft.


Bei der Möglichkeit, sc_serv ohne einen bestimmten User zu starten, wird der Server mit den aktuellen Rechten ausgeführt, was natürlich nicht zu empfehlen ist, da die meisten SHOUTCast-Server unter vollen Root-Rechten laufen.

Wenn das sowieso nicht zu empfehlen ist, dann laß es doch gar nicht erst soweit kommen, als Ansatz vielleicht


if [ $UID -eq 0 ]; then
# hier Dein Code...
else
echo "Muttu erst root werden..."
fi



Allerdings ist es in beiden Fällen bis jetzt mit meinem Script nicht möglich, mehrere Server gleichzeitig im System laufen zu lassen. (Aber ich denke mal nicht, dass auf einem Server auf einem normalen Anwender-System gleich mehr als ein SHOUTCast-Server läuft, oder?)

Naja, mehrere SHOUTcast Server (http://www.shoutcast.com/support/docs/docs.phtml?filenumber=80&language=english&layout=normal&prevlayout=normal) -- wenn das hier nicht nur der gleiche Name ist -- würden das System wohl in die Knie zwingen.;-)

MfG,

jan61
26-01-2008, 22:09
Moin,

so ganz blicke ich noch nicht durch die Benutzergeschichten durch. Um mal ein wenig Struktur reinzubringen:

1. Der Server lauscht auf einem TCP-Port (ich war nun auch mal auf der Shoutcast-Seite - sehr übersichtlich finde ich das übrigens nicht), per Default ist das 8000. Es ist wie beim Highlander: "Es kann nur einen geben" - wenn ein Service auf einem Port lauscht, dann ist der besetzt. Steht übrigens auch auf der Seite. Die ganzen Diskussionen um mehr als einen Server sind also überflüssig.

2. "Quäle nie das 'root' zum Scherz, denn es könnt' geladen sein" - will meinen: Finger weg von Versuchen, das Ding als Superuser zu starten!

3. Wenn es sowieso nur einen geben kann - wieso dann das ganze Geraffel mit verschiedenen Usern??? Der entspr. Anwender soll das Ding einfach mit seinem normalen Benutzer starten (der hoffentlich nicht root-Rechte hat). Und dann braucht man die ganzen su -c usw. Verrenkungen auch nicht.

Damit vereinfacht sich der Ablauf meiner Ansicht nach auf folgende Schritte:
- Prüfen, ob irgendein sc_serv läuft. Wenn ja, dann ist es völlig egal, mit welchem Benutzer er startet, ein 2. Server ist eh nicht möglich.
- wenn gestoppt werden soll, dann muss man prüfen, ob der Prozess dem aktuellen Benutzer gehört - wenn nicht, kann er ihn auch nicht stoppen. Auf Multiuser-Systemen gehört sich sowas eh im Normalfall nicht.
- Wenn kein Server rennt, dann kann er ganz normal mit /pfad/zum/sc_serv gestartet werden, da ist kein su -c oder sonstwas nötig.

Als einzige Ausnahme würde ich einen Fall (z. B. "stop-force") einbauen, der den sc_serv als root weghaut - kann ja mal sein, dass ein Server Amok läuft. Damit ist man dann aber an den Superuser gebunden und muss das Script eh unter root starten. Wenn man das nicht tut, gibts eine Fehlermeldung (da der Prozess nicht gekillt werden kann), auch da braucht man eigentlich keine Vorwegprüfung der UID (höchstens, um eine entspr. Fehlermeldung zu zeigen). Alternative wäre ein Eintrag in die /etc/sudoers (siehe man sudo), das sollte man sich aber genau überlegen.

Man kann sich angucken, ob man verschiedene Shoutcast-Installationen auf einem System hinkriegt, um dann bei Bedarf auch mehrere Server auf unterschiedlichen Ports laufen zu lassen, aber da steht erstmal die Frage nach dem Sinn der Sache ;-)

Jan

Fireball22
26-01-2008, 23:12
Ja genau, als Standard ist der TCP-Port 8000 festgelegt, welcher sich allerdings in der Config des Servers beliebig ändern lässt.

Das mehrfache Starten eines Shoutcast-Servers ist zwar möglich, allerdings hast du - jan61 - dass auch schon genau richtig erkannt, es würde eigentlich keinen Sinn machen, gleich zwei solche Server auf einem System laufen zu lassen, vor allem auch, weil so eine Konstellation so gut wie nie vorkommen wird, außer auf Servern, deren Rechenleistung fern der Leistung normaler bezahlbarer Server für Privatanwender liegen.

Genau, eig. sollte ich die Funktion direkt sperren, um solch einen Server als root zu starten, aber vllt. ist es für manche Leute doch aus Testzwecken oder aus irgendwelchen anderen Gründen notwendig auch diesen mal als Root auszuführen, was meint ihr?
Sollte ich diese Funktion deshalb direkt sperren?

Und genau, dann werde ich direkt noch einen stop-force Befehl einbauen, die Frage ist nur, wie ich dass dann anstelle, dass er diesen auch speziell mit Root-Rechten killt.
Frägt er dann nach dem Root-Passwort oder lehnt er den Befehl nicht gleich direkt ab?

Und das prüfen wäre wie ich schon mal gepostet habe, aber schon von der Syntax und Logik soweit okay, oder?


if [ [ `pgrep -f "${path_shoutcast}/sc_serv"` -a $use_user -eq 0 ] -o [ `pgrep -u $username -f "${path_shoutcast}/sc_serv"` -a $use_user -eq 1 ] ]; then
#...
fi


Den Grund für den Parameter -u im zweiten Test ist einfach, dass er hier explizit nur die Prozesse eines bestimmten Users abfragt und nicht alle, falls noch andere Server außerhalb der Scriptreichweite laufen.

MfG
Michael

jan61
27-01-2008, 14:17
Moin,


Genau, eig. sollte ich die Funktion direkt sperren, um solch einen Server als root zu starten, aber vllt. ist es für manche Leute doch aus Testzwecken oder aus irgendwelchen anderen Gründen notwendig auch diesen mal als Root auszuführen, was meint ihr? Sollte ich diese Funktion deshalb direkt sperren?

Nochmal: Wenn der Anwender sich als root anmeldet und dann das Startscript aufruft, dann läuft der Server auch als root. Wenn er sich mit einem anderen Benutzer anmeldet und dann das Script startet, dann läuft es mit dessen User-ID. Dazu brauchst Du kein su -c und keinen $use_user-Schalter. Du kannst nat. eine Sperre einbauen (z. B.: Wenn $UID gleich 0 ist und Modus ungleich "stop-force", dann Fehlermeldung), ich würde aber nicht per Default eine Möglichkeit einbauen, ihn als root zu starten. Laut Webseite ist das nicht notwendig, also sollte man das auch nicht erlauben.


Und genau, dann werde ich direkt noch einen stop-force Befehl einbauen, die Frage ist nur, wie ich dass dann anstelle, dass er diesen auch speziell mit Root-Rechten killt.
Frägt er dann nach dem Root-Passwort oder lehnt er den Befehl nicht gleich direkt ab?

Da gibt es mehrere Möglichkeiten: Der Anwender startet das Script als root oder Du machst ein "su -c Befehl" (dann wird das root-Passwort abgefragt) oder Du startest per sudo, musst dann aber die /etc/sudoers anpassen.


Und das prüfen wäre wie ich schon mal gepostet habe, aber schon von der Syntax und Logik soweit okay, oder?


if [ [ `pgrep -f "${path_shoutcast}/sc_serv"` -a $use_user -eq 0 ] -o [ `pgrep -u $username -f "${path_shoutcast}/sc_serv"` -a $use_user -eq 1 ] ]; then
#...
fi


Nein, das ist es nicht - hast Du es denn schon mal ausprobiert?

1. Der Ausdruck `pgrep -f "${path_shoutcast}/sc_serv"` kann 0, 1 oder n PIDs liefern, nur bei genau einer PID geht der Ausdruck nicht schief (auch wenn da eigentlich ein Operator fehlt). Korrekt sollte man den Ausdruck so abfragen (siehe meine Erläuterungen zu Quotings):
if [ -n "`pgrep -f '${path_shoutcast}/sc_serv'`" ... Damit kommt immer genau ein Ausdruck für den -n-Operator an.

2. Du verschachtelst mehrere test-Aufrufe - das geht nicht. Um die Priorität von Bedingungen zu steuern, nutzt man () - entwertet, damit sie die aufrufende Shell nicht auswertet:
if [ \( -n "`pgrep -f '${path_shoutcast}/sc_serv'`" -a $use_user -eq 0 \) -o \( -n "`pgrep -u $username -f '${path_shoutcast}/sc_serv'`" -a $use_user -eq 1 \) ]; thenEine andere Alternative wäre die Verknüpfung von 2 test-Aufrufen so:
if [ -n "`pgrep -f '${path_shoutcast}/sc_serv'`" -a $use_user -eq 0 ] || [ -n "`pgrep -u $username -f '${path_shoutcast}/sc_serv'`" -a $use_user -eq 1 ]; thenHier wird die Verknüpfung außerhalb eines test durch die Shell erledigt.

3. siehe unten


Den Grund für den Parameter -u im zweiten Test ist einfach, dass er hier explizit nur die Prozesse eines bestimmten Users abfragt und nicht alle, falls noch andere Server außerhalb der Scriptreichweite laufen.

Wie denn, wenn es eh nur einer sein soll? Das geht technisch nicht - vor allem nicht mit dem gleichen Startpfad. Dann würde ja wohl auch die gleiche Konfig gezogen werden und damit auch der gleiche TCP-Port! Und das funktioniert nun mal nicht. Das Üble am 2. Test ist, dass er davon ausgehen würde, dass kein Server läuft, ihn zu starten versuchen um sich dann über Fehlermeldungen des sc_serv zu wundern.

Jan

rais
27-01-2008, 21:13
2. "Quäle nie das 'root' zum Scherz, denn es könnt' geladen sein" - will meinen: Finger weg von Versuchen, das Ding als Superuser zu starten!

OkOkOk -- ich tu es auch nie wieder:o
MfG,

Fireball22
28-01-2008, 16:47
Vielen Dank für dein Posting, das stimmt alles genau, eig. benötigt man zum starten des SHOUTCast-Servers keine Root-Rechte, womit ich die Fuktion eigentlich sperren könnte.
Das ganze bräuchte ich ja dann auch nur beim Parameter Start abfragen, wie folgt:


if [ \( $UID -eq 0 \) -a \( $check_root -eq 0 \) ]; then
echo "Das Starten des Servers mit vollen Rechten, stellt ein großes Sicherheitsrisiko dar, möchten sie dennoch starten? Dann tippen Sie bitte 1 ein, andernfalls drücken Sie die Return-Taste..."
read $option
if [ $option -eq 1 ]; then
#...CODE CODE
else
echo "Bitte geben Sie in der Konfig des Scripts den gewünschten Username ein"
#exit 1
fi
fi


Die Option $check_root habe ich deshalb noch eingebaut, dass auch das Starten des Servers möglich ist, wenn das Script automatisch vom System aus den /etc/init.d ausgerufen wird.
Das ist doch richtig so, oder?
Und dann würde ich hier noch gerne das Script nach dem letzten echo abbrechen wie es in PHP mit exit; funktioniert, das ist doch hier auch in der BASH möglich, oder? Welchen exit-Wert gebe ich dann allerdings aus?

Und leider scheint die BASH noch ein Problem mit regulären Ausdrücken zu sein, die es aufeinmal in der Test-Anweisung erkennt:



h852677:~# ./DeinScript_new status
+ path_shoutcast=/home/shoutcast
+ use_screen=1
+ use_user=1
+ username=shoutcast
++ pgrep -f '${path_shoutcast}/sc_serv'
Invalid preceding regular expression++ pgrep -u shoutcast -f '${path_shoutcast}/sc_serv'
Invalid preceding regular expression+ '[' '(' -n '' -a 1 -eq 0 ')' -o '(' -n '' -a 1 -eq 1 ')' ']'
++ pgrep -f '${path_shoutcast}/sc_serv'
Invalid preceding regular expression++ pgrep -u shoutcast -f '${path_shoutcast}/sc_serv'
Invalid preceding regular expression+ '[' '(' -z '' -a 1 -eq 0 ')' -o '(' -z '' -a 1 -eq 1 ')' ']'
+ echo -ne 'Server scheint \033[1;37mOFFLINE\033[0m zu sein...\n'
Server scheint OFFLINE zu sein...
+ exit 0


Ich hab mir die beiden Tests schon genau angeschaut, allerdings komm ich nicht drauf, was man daran machen könnte, dass dieser sich nicht über einen Fehlerhaften regulären Ausdruck beschwert... hmm...

MfG
Michael

jan61
28-01-2008, 21:04
Moin,


...Die Option $check_root habe ich deshalb noch eingebaut, dass auch das Starten des Servers möglich ist, wenn das Script automatisch vom System aus den /etc/init.d ausgerufen wird.
Das ist doch richtig so, oder?

Bedingt - auch aus einem rc-Script für den Systemstart heraus brauchst Du den Server nicht unter root laufen zu lassen. In DIESEM Fall kannst Du mit "su USER -c ..." dafür sorgen, dass der Server z. B. mit einem extra dafür angelegten Benutzer USER läuft. root kann "su ..." aufrufen, ohne nach dem Passwort gefragt zu werden.

Außerdem frage ich mich, warum Du da immer noch einen Usernamen abfragst. Was hat das für einen Sinn? Lass den Server doch unter dem Benutzer laufen, der das Startscript aufruft. Das geht ganz automatisch, ohne dass Du "su -c ..." oder Ähnliches bemühen musst und der Anwender hat nachher auch wieder die Chance, den Server auch ohne Verrenkungen zu stoppen, weil der Prozess ihm gehört.


Und dann würde ich hier noch gerne das Script nach dem letzten echo abbrechen wie es in PHP mit exit; funktioniert, das ist doch hier auch in der BASH möglich, oder? Welchen exit-Wert gebe ich dann allerdings aus?

Ganz einfache Regel: Wenn das Script als erfolgreich verarbeitet gelten soll, dann gibst Du 0 als Returncode zurück, wenn es einen Fehler signalisieren soll, dann irgendwas zwischen 1 und 127 (üblicherweise 1, wenn Du nicht zwischen verschiedenen Fehlersituationen unterscheiden willst).


Und leider scheint die BASH noch ein Problem mit regulären Ausdrücken zu sein, die es aufeinmal in der Test-Anweisung erkennt:...

Guck Dir bitte mein Beispiel nochmal genau an - hast Du aussen "" um die `...`-Befehlsfolge gelegt? Sieht nicht so aus, dann der Ausdruck ${path_shoutcast} wird bei dir nicht ausgewertet. Poste bitte zu den Meldungen des set -x immer auch die entsprechenden Codezeilen.

Jan

P.S.: Am besten, Du schickst mir das Script mal per PM, dann kriegst Du (und die Leser hier ;-) eine kommentierte Version zurück, die zeigt, wie ich das machen würde. Der Thread wird langsam unübersichtlich :cool:

jan61
29-01-2008, 00:11
Moin,


...
if [ -n "`pgrep -f '${path_shoutcast}/sc_serv'`" ... Damit kommt immer genau ein Ausdruck für den -n-Operator an....

Asche auf mein Haupt - genau in diesem Fall (eingeschlossener Befehl in Backticks) werden die '' an die ausführende Shell weitergereicht. Damit werden genau in diesem Fall die inneren '' nicht durch die umschließenden "" entwertet. In dem Fall muss man also so quoten:

if [ -n "`pgrep -f \"${path_shoutcast}/sc_serv\"`" ... damit in der Shell, die den ``-Befehl ausführt, die Variable ersetzt wird.

Sorry für die Verwirrung, so sieht das Ganze im RL aus:

jan@jack:~/tmp/elchtest/1> a=/home/jan
jan@jack:~/tmp/elchtest/1> echo "ls -d '$a'"
ls -d '/home/jan'
jan@jack:~/tmp/elchtest/1> echo "`ls -d '$a'`"
/bin/ls: $a: Datei oder Verzeichnis nicht gefunden

jan@jack:~/tmp/elchtest/1> echo "`ls -d \"$a\"`"
/home/jan
Jan

Fireball22
29-01-2008, 14:38
Vielen Dank, Jan, für deine Hilfe!

Hab dir soeben mal das Script per PN geschickt ;)

Eigentlich funktioniert jetzt alles soweit, bis auf die Option -z $option, die beim Parameter Start folgenden Fehler ausgibt:



h852677:~# ./DeinScript_new start
+ path_shoutcast=/home/shoutcast
+ use_screen=1
+ use_user=0
+ username=shoutcast
+ check_root=1
+ '[' '(' 0 -eq 0 ')' -a '(' 1 -eq 1 ')' -a '(' 0 -ne 1 ')' ']'
+ echo -ne '\033[0;31mWARNING\033[0m Server wird mit Superuser-Rechten gestartet, was ein enormes Sicherheitsrisiko darstellt...\nBitte gewuenschte Option waehlen:\n\n1) Startvorgang fortsetzen\n2) Startvorgang abbrechen\n\nOption: '
WARNING Server wird mit Superuser-Rechten gestartet, was ein enormes Sicherheitsrisiko darstellt...
Bitte gewuenschte Option waehlen:

1) Startvorgang fortsetzen
2) Startvorgang abbrechen

Option: + read option

+ '[' '(' -ne 1 ')' -o '(' -z ')' ']'
./DeinScript_new: line 31: [: `)' expected, found 1
++ pgrep -f /home/shoutcast/sc_serv
++ pgrep -u shoutcast -f /home/shoutcast/sc_serv
+ '[' '(' -z '' -a 0 -eq 0 ')' -o '(' -z '' -a 0 -eq 1 ')' ']'
+ '[' 1 -eq 1 ']'
+ '[' 0 -eq 1 ']'
+ screen -dmS sc1 /home/shoutcast/sc_serv
+ '[' 0 -eq 0 ']'
+ echo 22035
+ echo -ne '\033[0;32mDONE\033[0m Server wurde gestartet\n\033[0;32mDONE\033[0m PID-File wurde erfolgreich angelegt\n'
DONE Server wurde gestartet
DONE PID-File wurde erfolgreich angelegt
+ exit 0


Ja das stimmt, man könnte das Startscript gleich unter dem richtigen Benutzer öffnen, allerdings ist das ja oft nicht im wirklichen Einsatz der Fall und man öffnet dieses auch gerne mal als Root oder mit einem anderen User, oder es ist aus einem bestimmten Grund gar nicht möglich, das Script direkt unter einem bestimmten User zu öffnen, wobei man sich ja dann trotzdem keine Angst machen muss, da es ja die Option use_user gibt.

MfG
Michael

jan61
29-01-2008, 19:17
Moin,


...Hab dir soeben mal das Script per PN geschickt ;)

Schau ich mir nachher an.


Eigentlich funktioniert jetzt alles soweit, bis auf die Option -z $option, die beim Parameter Start folgenden Fehler ausgibt:

Das Problem ist hier, dass Du abprüfst, ob die Variable leer ist - wenn sie leer ist, dann steht da aber nix mehr, es fehlt also das Argument. Simple Lösung: ... -z "$option" ..., so kommt immer etwas an.

Jan

Fireball22
29-01-2008, 20:43
Okay super, ich freu mich schon auf deine Lösung!

Das mit dem -z "$option" habe ich gerade ausgebessert, allerdings scheint er damit immer noch einen Fehler zu haben:


+ '[' '(' -ne 1 ')' -o '(' -z '' ')' ']'
./DeinScript_new: line 31: [: `)' expected, found 1
++ pgrep -f /home/shoutcast/sc_serv
++ pgrep -u shoutcast -f /home/shoutcast/sc_serv
+ '[' '(' -z '' -a 0 -eq 0 ')' -o '(' -z '' -a 0 -eq 1 ')' ']'
+ '[' 1 -eq 1 ']'
+ '[' 0 -eq 1 ']'
+ screen -dmS sc1 /home/shoutcast/sc_serv
+ '[' 0 -eq 0 ']'
+ echo 8122
+ echo -ne '\033[0;32mDONE\033[0m Server wurde gestartet\n\033[0;32mDONE\033[0m PID-File wurde erfolgreich angelegt\n'
DONE Server wurde gestartet
DONE PID-File wurde erfolgreich angelegt


MfG
Michael

jan61
29-01-2008, 21:43
Moin,


...Das mit dem -z "$option" habe ich gerade ausgebessert, allerdings scheint er damit immer noch einen Fehler zu haben:


+ '[' '(' -ne 1 ')' -o '(' -z '' ')' ']'

Schau Dir mal diesen Teil an: '(' -ne 1 ')' - was fällt auf? Richtig, da steht ein -ne 1 Operator + Operand mutterseelenallein im Wald rum, wo doch -ne ein binärer Operator ist und 2 Operanden haben will, einen vorne und einen hinten. Auch hier schlägt wieder die Falle zu, dass $option nicht gequotet ist - das musst Du prinzipiell immer machen, wenn Du nicht sicher weisst, dass eine Variable einen Inhalt hat.

Ausserdem wirst Du auf die Nase fallen, wenn Du z. B. "X" eingibst, da bringt der numerische Test einen Syntaxfehler. Du willst ja die Eingabe nicht wirklich auf einen numerischen Wert abprüfen, sondern nur wissen, ob der Anwender das Zeichen "1" eingegeben hat, also solltest Du hier den alphanumerischen Operator "=" verwenden.

Wenn Du sauber quotest, kannst Du sogar die -z-Prüfung wegfallen lassen:
jan@jack:~/tmp> x=
jan@jack:~/tmp> if [ $x -ne 1 -o -z $x ]; then echo nok; fi
bash: [: too many arguments
jan@jack:~/tmp> if [ $x -ne 1 -o -z "$x" ]; then echo nok; fi
bash: [: too many arguments
jan@jack:~/tmp> if [ "$x" -ne 1 -o -z "$x" ]; then echo nok; fi
bash: [: : integer expression expected
jan@jack:~/tmp> if [ -z "$x" -o ! "$x" = "1" ]; then echo nok; fi
nok
jan@jack:~/tmp> if [ ! "$x" = "1" ]; then echo nok; fi
nok
Ein anderer Trick (geht aber nur bedingt, weil ein Buchstabe immer noch Fehler bringt):
jan@jack:~/tmp> if [ 0$x -ne 1 ]; then echo nok; fi
nok
Jan

Fireball22
30-01-2008, 21:02
Vielen Dank für die Tipps!
Genau so funktioniert es wohl am besten, wenn man diese direkt als alphanumerische Werte vergleicht!
Das ist echt ne ziemlich große Umstellung wenn man nebenbei auch noch ständig mit PHP arbeitet, da sind doch etliche Unterschiede drin ;)

Mein stop-force-Teil sieht bis jetzt so aus und funktioniert auch ohne Probleme, sollte da noch eine Abfrage rein, ob der Server bereits läuft, oder sollte man bei der Force-Methode generell alle Möglichkeiten offen lassen?



stop-force)
echo -ne "Beende Prozesse mit Superuser-Rechten...\nGebe Prozesse Chance sich sauber zu beenden..."
su -c "pkill -f \"${path_shoutcast}/sc_serv\""
if [ $? -eq 0 ]; then
success=1
fi
su -c "sleep 5"
echo "Zwinge noch laufende Prozesse sich zu beenden..."
su -c "pkill -9 -f \"${path_shoutcast}/sc_serv\""
if [ $? -eq 0 -o $? -eq 1 ]; then
success=1
fi

if [ ${success} -eq 1 ]; then
echo -ne "\033[0;32mDONE\033[0m Server wurde erfolgreich heruntergefahren\n"
rm -f "${path_shoutcast}/server.pid"
else
echo -ne "\033[0;31mERROR\033[0m Server konnte nicht ordnungsgemaess heruntergefahren werden...\nBitte Debug-Modus starten...\n"
fi
;;


MfG
Michael

jan61
30-01-2008, 22:16
Moin,


...Mein stop-force-Teil sieht bis jetzt so aus und funktioniert auch ohne Probleme, sollte da noch eine Abfrage rein, ob der Server bereits läuft, oder sollte man bei der Force-Methode generell alle Möglichkeiten offen lassen?...

naja, auch bei "Brute-Force"-Attacken macht es wenig Sinn, etwas killen zu wollen, was nicht existiert, oder?

So, ich habe meine Version fertig - so viele Kommentare habe ich selten in einem Script ;-) Folgende Dateien sind im anhängenden tar enthalten:
shoutcast_orig.sh - Dein Originalscript (ich hoffe, Du hast nichts dagegen, es macht sich besser zum Vergleichen der Unterschiede)
shoutcast.sh - meine Version
sc_serv - ein kleines Shellscript, das Unsinn auf der Konsole ausgibt und beim Versuch, es zu erlegen, empört aufschreit um dann eine zufällige Wartezeit zwischen 1 und 10 Sekunden vor dem exit einzulegen (um den Ablauf kill - warten - kill -9 testen zu können). Habe ich gebastelt, um was zum Testen zu haben.

Wundere Dich nicht über das geänderte Erscheinungsbild. Ich habe die Einrückungen von 8 auf 2 Leerzeichen verringert, weil mir sonst im vim zu schnell die Zeilen überlaufen. Aus dem gleichen Grund habe ich auch an einigen Stellen die Zeilen umgebrochen. Das ist aber reine Kosmetik und Geschmackssache und soll keine Empfehlung für Deinen Programmierstil darstellen. Unter diese Rubrik fällt auch das Ersetzen einiger "####..."-Zeilen durch Leerzeilen.

Die wichtigsten inhaltlichen Änderungen:
- Ich habe einige mehrfach benutzte Code-Abschnitte in Funktionen ausgelagert, um den Main-Teil übersichtlicher zu halten und Wiederholungen zu vermeiden
- Die Sicherheitsabfrage beim Start durch root habe ich ebenfalls in eine Funktion ausgelagert, die anzuzeigende Meldung in eine Variable am Anfang des Scripts gepackt und die Abfrage der Eingabe in eine Schleife gelegt, die bei Fehleingaben eine Meldung bringt und erneut abfragt.
- Beim Start per screen habe ich gemerkt, dass das Kommando immer 0 als Returncode liefert - egal wie das Ergebnis des Starts ist. Deshalb frage ich in diesem Fall per pgrep ab, ob der Prozess tatsächlich läuft.
- Vor alle "su -c"-Aufrufe habe ich zusätzliche Meldungen gesetzt, wenn der aufrufende Benutzer nicht root ist - damit er weiss, wessen Passwort er dann einzugeben hat.
- Das Erzeugen eines PID-Files habe ich rausgeschmissen - es wird nirgends ausgewertet und bringt deshalb nur unnötige potenzielle Fehlerquellen ins Script.
- Im Stop habe ich am meisten umgebaut. Hier macht es wenig Sinn, die eingebauten Schalter auszuwerten, es kommt allein darauf an, unter welcher User-ID der Serverprozess läuft und damit, ob und wie ich ihn killen kann (der Start kann ja mit ganz anderen Parametern erfolgt sein).
- Die Usage-Meldung bei ungültigem Aufruf habe ich an die allgemein übliche Syntax angepasst.
- Ich habe einen trap am Anfang der Hauptroutine eingebaut, um eine entspr. Meldung anzuzeigen und mit einem passenden Returncode auszusteigen - auch um mal zu demonstrieren, wie man diese nützliche Funktion verwendet.
- Die Returncodes des Scripts habe ich erweitert - sind am Anfang kommentiert.
- statt pkill benutze ich zum Stoppen den einfachen kill. Da pgrep mir bereits die zutreffenden PIDs liefert, ist es unnötig, dann nochmal den pkill per regex über die ganze Prozessliste zu jagen, kill mit den PIDs ist mit Sicherheit schneller.
- Die "kill ...; sleep 5; kill -9 ..."-Sequenz habe ich durch eine Warteschleife ersetzt, die pro Sekunde einmal guckt, ob noch Serverprozesse laufen. Nur wenn nach 5 Sekunden der sc_serv noch lebt, wird er per kill -9 ins Jenseits befördert.

So, viel Spaß beim Vergleichen ;-) Ach ja - ich habe zwar alle möglichen Varianten getestet, lege aber meine Hand nicht dafür ins Feuer, dass ALLES fehlerfrei ist. Dazu müsste man sich dann doch noch ein paar Stunden hinsetzen und systematisch alle Wege durch das Script abklappern.

Jan

P.S.: Wenn Du Dein Script unter GPL stellen willst, dann kannst Du Änderungen von mir gern übernehmen.

jan61
30-01-2008, 23:34
Moin,

noch 3 Hinweise zum stop-force:
1. Warum rufst Du den sleep per "su -c" auf? Schlafen kann jeder ;-)
2. Warum steigst Du nicht aus, wenn der erste kill bereits erfolgreich war?
3. Wenn Du beim Aufruf mit "stop-force" zum Anfang abprüfst, ob der Aufrufer root ist, dann kannst Du alle "su -c" sparen. Andernfalls muss der Anwender bei jedem "su -c" das root-Passwort eingeben, da ist es doch viel bequemer, wenn er gleich "su -c 'shoutcast.sh stop-force'" aufruft - dann muss er das nur einmal tun.

Jan

Fireball22
02-02-2008, 17:38
Wow, vielen Dank für deine Mühe!
Das ist ja echt heftig, was du hier zusammengeschrieben hast!

Ich bin das jetzt mal die letzten Tage alles durchgegangen und habe mir das alles angeschaut, alles durchprobiert, geschaut, wie du das angestellt hast und dann in meinem Script verbessert und noch einige kleine Fehler ausgebessert.

Die Idee mit den Funktionen ist echt super, aber leider ist mir das dann irgendwie zu unübersichtlich, weil ich ja dann speziell für jeden Fall in der Funktion etwas speziell definieren müsste.
Ohne Funktionen hat es zwar klar den Nachteil, dass ca. 10 gleiche Zeilen vorkommen, aber dafür find ich das schon etwas übersichtlicher ;)
Ich hoff du bist mir da nicht böse, dass ich das nicht ganz so verwenden werde.

Aber die Idee mit den Schleifen ist echt super und das habe ich auch alles direkt gleich alles angepasst.

Die Code-Teile für die PID-Files sind ebenfalls nun komplett draußen und die Usage-Ausgabe habe ich ebenfalls überarbeitet.

Ich bin vorhin zufällig im Internet noch auf eine Seite gestoßen, wo Scripte angeboten werden, die anhand einer PID-File feststellen, ob ein Server bereits gestartet bzw. beendet ist.
Deshalb habe ich mir gedacht, dass ich dann auch zum Download die PID-Variante anbieten werde.
Vllt. findet ja jemand damit Verwendung, auch wenn diese nicht wirklich zuverlässig ist.

Zum stop-force:
Wieso ich da noch nicht direkt aussteige, hat den Grund, dass pkill unter Umständen zwei Prozesse beenden muss. Einmal den eigentlichen Server-Prozess und noch den screen.
Es reicht schon ein gekillter Prozess aus, damit er den Return-Code 0 zurückgibt, obwohl noch gar nicht alles beendet wurde.
Deshalb killt er dann mit dem Signal -9 im Folgenden den Rest.
Und das mit dem su -c bei sleep stimmt zwar, aber diese Funktion ist ja speziell dazu da, weil sich der Server mit weniger Rechten bzw. auf Ebene !ANDERER! Benutzer nicht mehr killen lässt. Nehmen wir an, auf der Ebene des !ANDEREN! Benutzers gibt es einen totalen Crash, wodurch auch nichts mehr richtig ausgeführt werden kann, dann bleibt er trotzdem bei sleep 5 hängen.
Das ist zwar ein Fall, der warscheinlich kaum bis nie vorkommen wird, aber da setzte ich ja dann lieber einfach mal ein weiteres su -c.
Ich hoffe mein Gedankengang war soweit richtig... *g*

Eins muss ich hier auch noch hinzufügen:



pkill -u $username -f "${path_shoutcast}/sc_serv"

Musste von mir durch folgendes Ersetzt werden, da ich in einigen Tests mit verschiedenen Benutzern festgestellt habe, dass er unter einem anderen Benutzernamen, der ungleich $username entspricht, eine Fehlermeldung ausbringt und nicht nach dem Passwort von $username fragt. Er killt deshalb a auch keine Prozesse. So funktioniert es ohne Probleme:


su -c "pkill -u $username -f \"${path_shoutcast}/sc_serv\"" $username


Ich werde mich jetzt noch naher gleich ransetzten und die letzten Seite von meiner Page anpassen, dann könnt ihr euch das finale Script gerne anschauen und nochmals durchtesten.
Wenn es noch irgendwelche Probleme geben sollte, dann wäre es super, wenn ihr die noch kurz postet =)

MfG
Michael

Fireball22
02-02-2008, 23:37
So, nun ist es endlich soweit - bis jetzt sind gestern mehr als 4 Stunden Arbeit vergangen, bis endlich das ganze Download-Script funktioniert und die restlichen Fehler bei den letzten Tests behoben wurden:

http://www.michis-homepage.net/scripting.php

Ich würde mich sehr freuen, wenn ihr euch die Realtime-Version und die PID-Version nochmal anschauend würdet und auf evtl. Fehler überprüfen könntet.

Vor allem hoffe ich nun auch, dass die stop-Funktion überall problemlos funktioniert, wo du (Jan) mir ja bereits mitgeteilt hast, dass da was noch nicht stimmt...

MfG
Michael

jan61
03-02-2008, 21:38
Moin,


...Die Idee mit den Funktionen ist echt super, aber leider ist mir das dann irgendwie zu unübersichtlich, weil ich ja dann speziell für jeden Fall in der Funktion etwas speziell definieren müsste.

Den Satz verstehe ich nicht ;-) Funktionen sollen Codeteile kapseln, die an mehreren Stellen benutzt werden (oder die Main-Funktion zu unübersichtlich machen). Daher sollen sie eigentlich der Übersichtlichkeit dienen. Wenn zu viele Parameter übergeben werden müssen oder zu viele Abhängigkeiten von globalen Variablen auftreten, dann kapsele ich eben noch mal - eine Funktion kann prima von einer anderen Funktion aufgerufen werden (habe ich ja mit der show_msg-Funktion schon gezeigt).

Natürlich muss man sich beim Code-Lesen daran gewöhnen, dass es Code-Teile gibt, in die man reinhüpft. Ohne diese Art von strukturierter Programmierung ist man aber bei jedem etwas größeren Projekt erschossen, darum sollte man sich daran so schnell wie möglich gewöhnen. Vergleiche z. B. mal den Aufwand, wenn Du die Farbe einer "ERROR"-Meldung in Deiner und in meiner Version ändern willst. In meiner Version ist es exakt 1 Zeile - und bei Dir?


...Ich hoff du bist mir da nicht böse, dass ich das nicht ganz so verwenden werde.

Ich bin Dir nicht böse, ich habe nur Vorschläge gemacht. Es ist Dein Script.


Ich bin vorhin zufällig im Internet noch auf eine Seite gestoßen, wo Scripte angeboten werden, die anhand einer PID-File feststellen, ob ein Server bereits gestartet bzw. beendet ist.
Deshalb habe ich mir gedacht, dass ich dann auch zum Download die PID-Variante anbieten werde.
Vllt. findet ja jemand damit Verwendung, auch wenn diese nicht wirklich zuverlässig ist.

Naja, das könnte eigentlich nur dann sein, wenn pgrep & Co. nicht installiert sind. Dann solltest Du das aber auch abprüfen, z. B. so:

if test -z "`which pgrep`"; then ...Es macht keinen Sinn, eine unsichere Variante eines Scripts anzubieten, wenn eine bessere existiert.


Zum stop-force:
Wieso ich da noch nicht direkt aussteige, hat den Grund, dass pkill unter Umständen zwei Prozesse beenden muss. Einmal den eigentlichen Server-Prozess und noch den screen. Es reicht schon ein gekillter Prozess aus, damit er den Return-Code 0 zurückgibt, obwohl noch gar nicht alles beendet wurde.
Deshalb killt er dann mit dem Signal -9 im Folgenden den Rest.

OK, ist zwar unlogisch (siehe man screen, Abschnitt DESCRIPTION - ich habe bei meinen Tests nie einen übrig gebliebenen screen entdecken können) aber vielleicht tritt der Fall mal auf - aber wieso lässt Du Dir dafür 5 Sekunden Zeit und prüfst nicht erstmal, ob noch was zum Killen da ist?


Und das mit dem su -c bei sleep stimmt zwar, aber diese Funktion ist ja speziell dazu da, weil sich der Server mit weniger Rechten bzw. auf Ebene !ANDERER! Benutzer nicht mehr killen lässt. Nehmen wir an, auf der Ebene des !ANDEREN! Benutzers gibt es einen totalen Crash, wodurch auch nichts mehr richtig ausgeführt werden kann, dann bleibt er trotzdem bei sleep 5 hängen.
Das ist zwar ein Fall, der warscheinlich kaum bis nie vorkommen wird, aber da setzte ich ja dann lieber einfach mal ein weiteres su -c.
Ich hoffe mein Gedankengang war soweit richtig... *g*

Naja, für mich nicht nachvollziehbar %-/ Völlig unabhängig davon, was Du vorher oder nachher machst (und mit welchem User das passiert), macht "sleep 5" einfach nur 5 Sekunden Pause. Der "su -c" rundrum ist und bleibt unsinnig!


Eins muss ich hier auch noch hinzufügen:



pkill -u $username -f "${path_shoutcast}/sc_serv"
Musste von mir durch folgendes Ersetzt werden, da ich in einigen Tests mit verschiedenen Benutzern festgestellt habe, dass er unter einem anderen Benutzernamen, der ungleich $username entspricht, eine Fehlermeldung ausbringt und nicht nach dem Passwort von $username fragt. Er killt deshalb a auch keine Prozesse. So funktioniert es ohne Probleme:


su -c "pkill -u $username -f \"${path_shoutcast}/sc_serv\"" $username
Stimmt - deshalb habe ich ja in meinem Script nicht pkill, sondern kill mit den PIDs aufgerufen, und dies immer mit mit dem User, der auch das Recht zum Killen hat (also im Zweifel per "su -c"). Du machst hier wieder Deinen klassischen Denkfehler: Du killst nur die Prozesse, die dem $username-Benutzer gehören - das bringt Dir aber überhaupt nichts, wenn das Script beim Start mit der Konfig-Einstellung use_user=0 aufgerufen wurde - dann gibts nur einen sc_serv, der unter einem völlig anderen User läuft (nämlich dem, der das Script gestartet hat). Den erwischst Du mit dieser Konstruktion nicht (kriegst auch keinen Fehler) und kannst anschließend auch keinen neuen Prozess starten, weil nämlich immer noch einer auf dem konfigurierten TCP-Port hängt.

Rate mal, warum ich keinen "stop-force" in mein Script eingebaut habe: Nachdem ich mich mal intensiv mit Deinem Script auseinandergesetzt hatte, als ich meine Version aufgebaut habe, habe ich nämlich gesehen, dass das überflüssig ist. Dazu dient in meinem Script in der stop_server-Funktion die Abfrage, ob ich einen laufenden Prozess killen kann. Wenn ich das nicht kann, dann gebe ich die Meldung aus, dies doch mal unter root zu versuchen. Entweder ich kann die Prozesse killen oder nicht. Es spielt keine Rolle, wie die Konfig ausieht - wenn ich einen laufenden Prozess nicht killen kann, dann ist das ein Fehler, der Server läuft nämlich danach noch!!!

Jan

Fireball22
04-02-2008, 12:53
Vielen Dank nochmals für deine Tipps & deine Hilfe!

Die su -c um die sleep 5 herum sind nun komplett weg, das würde eig. echt keinen wirklichen Sinn machen.
Ich habe mir auch gerade Gedanken um die Warteschleife gemacht, allerdings würde das für den Anwender teilweise ja nur unnütze Arbeit bedeuten, in dem er ständig das für den User benötigte Passwort eingibt:



wait_cnt=1
while test -n "`pgrep -f \"$path_shoutcast/sc_serv\"`"; do
wait_cnt=`expr $wait_cnt + 1`
test $wait_cnt -gt 5 && break
sleep 1
done

Das muss er zwar in dieser Code-Konstellation noch nicht, aber allerdings würde das hier auch alles "greppen", und nicht nur die sc_serv des bestimmten Users.

Und folgendes dient jetzt noch dazu, PID-Files zu verwenden, falls pgrep nicht installiert ist:



if [ -z "`which pgrep`" ]; then
use_pid=1
else
use_pid=0
fi




test "$use_pid" -eq 0 && if [ \( -z "`pgrep -f \"${path_shoutcast}/sc_serv\"`" -a $use_user -eq 0 \) -o \( -z "`pgrep -u $username -f \"${path_shoutcast}/sc_serv\"`" -a $use_user -eq 1 \) ]; then
test "$use_pid" -eq 1 && if [ ! -e "${path_shoutcast}/server.pid" ]; then


Allerdings beschwert er sich dann über ein "unexpected ;;", d. h. über das Ende der Start-Funktion.

Wo liegt denn da der Fehler, oder kann man das allgemein nicht so machen und mann muss den ganzen Code-Teil extra aufrollen?



Stimmt - deshalb habe ich ja in meinem Script nicht pkill, sondern kill mit den PIDs aufgerufen, und dies immer mit mit dem User, der auch das Recht zum Killen hat (also im Zweifel per "su -c"). Du machst hier wieder Deinen klassischen Denkfehler: Du killst nur die Prozesse, die dem $username-Benutzer gehören - das bringt Dir aber überhaupt nichts, wenn das Script beim Start mit der Konfig-Einstellung use_user=0 aufgerufen wurde - dann gibts nur einen sc_serv, der unter einem völlig anderen User läuft (nämlich dem, der das Script gestartet hat). Den erwischst Du mit dieser Konstruktion nicht (kriegst auch keinen Fehler) und kannst anschließend auch keinen neuen Prozess starten, weil nämlich immer noch einer auf dem konfigurierten TCP-Port hängt.

Jetzt versteh ich das ganze!
Okay, ich hab mir gerade eben mal die Parameter von pgrep angeschaut und da scheint es leider keine Möglichkeit zu geben, die UID des Prozesses rauszufinden um ihn dann mit den entsprechenden Userrechten zu killen.
Geht dass dann nur mit Root?

Und das ganze betrifft aber dann nur den Aufruf, wenn $use_user = 0 ist, oder?
Das andere alles läuft ohne Probleme? =)

Okay, und wegen des stop-force werde ich gleich nochmal nachschauen ;)

MfG
Michael

jan61
04-02-2008, 21:24
Moin,


...Ich habe mir auch gerade Gedanken um die Warteschleife gemacht, allerdings würde das für den Anwender teilweise ja nur unnütze Arbeit bedeuten, in dem er ständig das für den User benötigte Passwort eingibt:

Nein, das muss er nicht (wie Dein Codeblock ja zeigt) und die Abfrage nach den Prozessen aller User ist doch ok - beim Stoppen müssen alle weg.


Und folgendes dient jetzt noch dazu, PID-Files zu verwenden, falls pgrep nicht installiert ist:...
Wo liegt denn da der Fehler, oder kann man das allgemein nicht so machen und mann muss den ganzen Code-Teil extra aufrollen?

Mach lieber ne saubere if - then - else Abfrage, dann sieht der Code auch gleich lesbarer aus :-) Und teste die Existenz des PID-Files bitte nicht mit -e; der sagt Dir nicht, ob das tatsächlich eine Datei ist und ob Du sie auch lesen kannst.


Okay, ich hab mir gerade eben mal die Parameter von pgrep angeschaut und da scheint es leider keine Möglichkeit zu geben, die UID des Prozesses rauszufinden um ihn dann mit den entsprechenden Userrechten zu killen.

Das ginge z. B., indem Du die gefundenen PIDs per ps auswertest, der hat entsprechende Optionen:
jan@jack:~/tmp> ps -o user= -o pid= -p `pgrep bash`
jan 7122
jan 7130

Und das ganze betrifft aber dann nur den Aufruf, wenn $use_user = 0 ist, oder?

Nein, das ist ja gerade der springende Punkt: Wenn Du stop aufrufst, musst Du immer die Prozesse aller Benutzer berücksichtigen. Du weisst ja nicht, wie Dein Script beim vorigen Start aufgerufen wurde. Es ist völlig wurscht, wie Dein Script beim stop parametrisiert wurde, Du willst einen bestehenden sc_serv killen. Und dabei musst Du erstmal davon ausgehen, dass er unter einem beliebigen User laufen kann. Genau deshalb habe ich die Stop-Funktion so erweitert, dass alle möglichen Fälle (sc_serv gehört mir, sc_serv gehört $username, sc_serv gehört einem anderen User) separat behandle.

Jan

Fireball22
05-02-2008, 18:25
So, okay, da werde ich dann wohl den ganzen Abend noch rumbasteln & alles durchtesten.

Allerdings habe ich noch eine Frage wie ich das am besten mit der If-Anweisung anstelle, weil dann hätte ich den größten Teil des Codes doppelt, selbst wenn ich das ganze in eine Funktion packe, habe ich einige Zeilen doppelt.
Aber da muss es doch eine Möglichkeit geben, dass alles in eine If-Anweisung zu packen, oder?

Sinngemäß müsste ungefähr so ausschauen, wie ich das aber in Echt anstelle weiß ich leider echt noch nicht... hmmm...


if [ ($use_pid = 0 -a(DANN) pgrep...) -o ($use_pid = 1 -a ! -e PID-FILE) ]; then


Ich habe mir schon fast gedacht, dass ich das irgendwie so machen könnte:



if [ -z "`which pgrep`" ]; then
use_pid=1
if_start='! -e \"${path_shoutcast}/server.pid\"'
else
use_pid=0
if_start='\( -z "`pgrep -f \"${path_shoutcast}/sc_serv\"`" -a $use_user -eq 0 \) -o \( -z "`pgrep -u $username -f \"${path_shoutcast}/sc_serv\"`" -a $use_user -eq 1 \)'
fi


und hier dann so:


if [ $if_start ]; then


Das wäre immerhin eine Möglichkeit?
Nur leider bekomme ich folgende Fehlermeldung:



h852677:~/bash-scripting# ./shoutcast-control start
+ path_shoutcast=/home/shoutcast
+ use_screen=1
+ use_user=1
+ username=shoutcast
+ check_root=1
++ which pgrep
+ '[' -z /usr/bin/pgrep ']'
+ use_pid=0
+ if_start=\( -z "`pgrep -f \"${path_shoutcast}/sc_serv\"`" -a $use_user -eq 0 \) -o \( -z "`pgrep -u $username -f \"${path_shoutcast}/sc_serv\"`" -a $use_user -eq 1 \)
+ '[' '(' 0 -eq 0 ')' -a '(' 1 -eq 1 ')' -a '(' 1 -ne 1 ')' ']'
+ '[' '\(' -z '"`pgrep' -f '\"${path_shoutcast}/sc_serv\"`"' -a '$use_user' -eq 0 '\)' -o '\(' -z '"`pgrep' -u '$username' -f '\"${path_shoutcast}/sc_serv\"`"' -a '$use_user' -eq 1 '\)' ']'
./shoutcast-control: line 57: [: too many arguments
+ echo -ne '\033[0;31mERROR\033[0m Server scheint bereits online zu sein...\n'
ERROR Server scheint bereits online zu sein...
+ exit 1


Aber wie gesagt, gäb es da vllt. eine Möglichkeit das ganze in eine Anweisung zu packen?

MfG
Michael

EDIT:

So, jetzt hab ich das ganze nochmal durchdacht und bin auf folgende If-Anweisung bekommen, die rein theoretisch alles genau so erfüllen müsste, wie ich mir das vorstelle =)
Allerdings kommt folgendes dabei raus:


h852677:~/bash-scripting# ./shoutcast-control start
+ path_shoutcast=/home/shoutcast
+ use_screen=1
+ use_user=1
+ username=shoutcast
+ check_root=1
++ which pgrep
+ '[' -z /usr/bin/pgrep ']'
+ use_pid=0
+ '[' '(' 0 -eq 0 ')' -a '(' 1 -eq 1 ')' -a '(' 1 -ne 1 ')' ']'
++ pgrep -f /home/shoutcast/sc_serv
++ pgrep -u shoutcast -f /home/shoutcast/sc_serv
+ '[' '((' 0 = 0 ')' -a '(' -z '' -a 1 -eq 0 ')' -o '(' -z '' -a 1 -eq 1 '))' -o '((' 0 = 1 ')' -a '(' '!' -e /home/shoutcast/server.pid '))' ']'
./shoutcast-control: line 55: [: too many arguments
+ echo -ne '\033[0;31mERROR\033[0m Server scheint bereits online zu sein...\n'
ERROR Server scheint bereits online zu sein...
+ exit 1

Kann das sein, dass er bei so einer geringen Anzahl an Anweisungen schon schlapp macht?

Die If-Anweisung dazu:


if [ \(\( $use_pid = 0 \) -a \( -z "`pgrep -f \"${path_shoutcast}/sc_serv\"`" -a $use_user -eq 0 \) -o \( -z "`pgrep -u $username -f \"${path_shoutcast}/sc_serv\"`" -a $use_user -eq 1 \)\) -o \(\( $use_pid = 1 \) -a \( ! -e "${path_shoutcast}/server.pid" \)\) ]; then


MfG
Michael

jan61
06-02-2008, 02:08
Moin,


...Die If-Anweisung dazu:


if [ \(\( $use_pid = 0 \) -a \( -z "`pgrep -f \"${path_shoutcast}/sc_serv\"`" -a $use_user -eq 0 \) -o \( -z "`pgrep -u $username -f \"${path_shoutcast}/sc_serv\"`" -a $use_user -eq 1 \)\) -o \(\( $use_pid = 1 \) -a \( ! -e "${path_shoutcast}/server.pid" \)\) ]; then


Geschachtelte Klammern in einer test-Anweisung müssen mit einem Leerzeichen getrennt werden:


if [ \( \( $use_pid = 0 \) -a \( -z "`pgrep -f \"${path_shoutcast}/sc_serv\"`" -a $use_user -eq 0 \) -o \( -z "`pgrep -u $username -f \"${path_shoutcast}/sc_serv\"`" -a $use_user -eq 1 \) \) -o \( \( $use_pid = 1 \) -a \( ! -e "${path_shoutcast}/server.pid" \) \) ]; then
Nur so können sie als separate Argumente des test erkannt werden.

Jan

P.S.: Du fragst für den stop immer noch den Parameter $use_user ab - DAS BRINGT NICHTS! Das habe ich jetzt schon etliche Male zu erklären versucht - Du weisst nicht, mit welchen Parametern der sc_serv gestartet wurde! Er kann mit einem beliebigen User laufen, völlig unabhängig davon, wie Du das stop-Script aufrufst. Du kriegst ihn nicht gestoppt (bzw. erkennst nicht mal, das da überhaupt noch einer läuft), wenn Du weiter mit dieser unsinnigen Abfrage rumhantierst. Das Gleiche gilt für den Start: Du kriegst keinen neuen sc_serv gestartet, wenn da noch einer läuft (es ist schnurzpiepegal, von wem der gestartet wurde).

Bau Dir doch mal eine Testumgebung, wo Du das prüfen kannst: Kopier Dir das Start-Script, setze einmal use_user auf 0 und einmal auf 1, starte beide Varianten (unter einem User, der NICHT $username ist) und schau Dir dann mal an, wie der start / stop abläuft (beide Scriptvarianten abwechselnd in unterschiedlicher Reihenfolge aufrufen).

P.P.S.: Ich wiederhole auch das nochmal - [ -e datei ] testet nur die Existenz der Datei - das kann ein Verzeichnis, eine Named Pipe oder ein Device sein und Du brauchst keine Leseberechtigung auf das Ding - das nützt Dir überhaupt nix! Wenn Du ein PID-File auswerten willst, muss es eine reguläre Datei sein und Du musst sie lesen können. Nimm -f und -r stattdessen. Und wenn Du sie löschen / neu anlegen willst, dann brauchst Du Schreibberechtigung im Verzeichnis.

Fireball22
06-02-2008, 12:48
Vielen Dank nochmals für deine Hilfe!

Jetzt klappt es auch mit der If-Anweisung! =)

Zu den Tests für die PID-File:
Eig. reicht aber -e vollkommen aus, da ich ja keine PIDs aus der Datei auslesen, sondern nur nachschaue ob dieses "Objekt" existiert.
Mein Script schreibt nicht einmal irgendetwas in diese File, dieses ist eig. komplett leer und signalisiert nur den Status des Servers.

Allerdings verstehe ich das leider immer noch nicht ganz wie du das meinst, dass mein Script das ganze dann nicht killen kann!

Weil ich habe mir das ganze so vorgestellt, dass man den Server mit diesem Script startet, alle Variablen so belässt und daraufhin den Server mit diesem Script wieder stoppt.

Ich bin gerademal (fast) alle möglichen Fälle durchgegangen:

$use_user = 1
START:
Script wird beispielsweise unter Benutzer "tux" gestartet.
Server läuft inkl. Screen unter der Benutzerebene "shoutcast".

STOP:
- Server wird inkl. Screen mit su -c und pkill -u Parametern gekillt, egal mit welchem User das Script aufgerufen wird, da er immer den User nimmt, der bereits in der Variable $username festgelegt wurde, da $use_use = 1.

$use_use = 0
START:
1) Als Root
2) Als "tux1"
3) Als "tux2"

STOP:
1) pkill wird unter root ausgeführt: Ausreichende Rechte um alle Prozesse, die unter Root gestartet wurden zu killen
2) pkill wird unter "tux1" ausgführt: Ausreichende Rechte um alle Prozesse, die unter "tux1" laufen zu killen
3) Ebenfalls ausreichende Rechte wie bei Fall 2

NUR wenn ich jetzt versuche, den Server in Fall2 zu starten und ihn dann in Fall3 stoppe, werde ich Probleme haben, da der Server (evtl. mit Screen) unter "tux1" läuft und "tux2" keine Rechte hat, diesen zu beenden und dieses das Script auch nicht vorsieht.
Das Script würde mit einer Fehlermeldung abbrechen.
Aber dafür ist das Script eig. auch gar nicht gedacht, denn für das Handling und das Starten/Stoppen MIT und UNTER unterschiedlichen Benutzern gibt es ja die Funktion $use_user.

Und das ist auch so gedacht, denn es gibt aufjedenfall Möglichkeiten, mehrere SHOUTcast-Server auf einem Rechner laufen zu lassen, dazu gibt es ettliche Mods.
Und daher möchte ich auch nicht alle "sc_serv"s von allen Benutzern killen, sondern echt nimmer nur explizit diesen Servern, der mit dem Script gestartet wurde.

Das ist doch soweit richtig, oder?

MfG
Michael

EDIT:

Beim testen ist mir noch aufgefallen, dass er bei folgendem Code IMMER nach dem Passwort frägt, auch wenn man als $username eingeloggt ist, außer man ist Root.


su -c "screen -dmS sc1 '${path_shoutcast}/sc_serv'" $username

Kann man dieses Problem irgendwie umgehen, oder helfen da nur extra Startanweisungen dazu?

jan61
07-02-2008, 02:22
Moin,

ich fasse mich mal kurz:

1. PID-File
Beim Start willst Du es anlegen - beim Stop löschen können. Versuch mal ein "rm /pfad/zum/PID_file", wenn das ein Verzeichnis ist. Und bevor Du mir schreibst, dass da ja nur Dein Script hinschreiben will - wie willst Du das absichern? Die Arbeit mit PID-Files will ein wenig überlegt sein - immerhin sind das Dateien, die laufend erzeugt / geändert / gelöscht werden, und das u. U. von verschiedenen Benutzern, ggf. sogar zeitgleich.

2. "Ich stoppe nur Prozesse, die mein Script gestartet hat"
Wie willst Du das denn überprüfen??? Jeder, der Dein Script ausführen kann, kann es auch kopieren, ändern und dann diese Kopie starten:

Benutzer devil hat das Passwort von $username vergessen. er kopiert sich das Script in sein $HOME, ändert $use_user auf 0 und startet es dann. Schwupps hast Du einen sc_serv unter User devil und alle braven Benutzer wundern sich, warum sie beim Status keinen laufenden Prozess sehen, demzufolge auch keinen stoppen können - aber ein Start klappt auch nicht (da ist nämlich dieser verflixte IP-Port bereits vergeben).

3. Wie willst Du verhindern, dass sich ein Anwender Dein Script in einen Editor lädt, die Startzeile (ohne su -c) kopiert und die dann einfach ausführt? Solange Du diese ganzen Optionen zulässt, musst Du nämlich auch das sc_serv-Binary für jeden ausführbar lassen.

4. Deine neu entdeckten Mods, um mehrere sc_serv zuzulassen:
Am Anfang dieses (mittlerweile rekordverdächtigen) Threads hast Du auf meine diesbezügliche Frage (sollen mehrere Server gleichzeitig laufen können?) noch exakt andersrum geantwortet - nämlich mit "Nein" - jetzt ist draus "Ja" geworden.

Ich glaube Dir nicht, wenn Du jetzt behauptest "Und das ist auch so gedacht" - das ist es nämlich definitiv nicht und bis eben war das auch nie Dein Ziel (lies Deine eigenen vergangenen Postings nochmal, wenn Du mir nicht glaubst).

Dein Script (und auch mein Vorschlag) sind auf keine der Situationen und möglichen Sicherheitsrisiken auch nur im Geringsten vorbereitet, die eine "Multi-sc_serv"-Umgebung mit sich bringt (notwendige Überwachung der IP-Ports, bessere regex, um zutreffende Server zu identifizieren, Ausschließen von Race Conditions bei den PID-Files, ...). Für eine so komplexe Aufgabe (der Server soll ja unter den verschiedensten Usern, Ports usw. zu starten und betriebssicher auch wieder zu stoppen sein) braucht man dann doch ein paar Tage mehr Zeit.

Ich mache Dir einen Vorschlag: Du gibst mir für 15 Minuten Shell-Zugang auf Dein System, ich benutze nur Dein Script, sc_serv (inkl. aller Deiner Mods) und die normalen Shell-Mittel und wir posten hier dann einen Mitschnitt meiner Kommandos und einen Screenshot des top zu dem Zeitpunkt, zu dem Dein System das letzte Mal benutzbar war - ok?

5. Was willst Du hier kriegen? Hilfe? Oder die Bestätigung, dass Deine Programmier- und Design-Fehler keine sind?

Jan