Mehrere Drucker, printserv-Prozesse und semaphore-Problem

Der Name der Datei ist egal, die Major und Minor Nummer nicht. Oder mal anders formuliert, warum übergibt man dem printserv überhaupt den Namen einer Gerätedatei, wenn es nicht von Bedeutung wäre, welches Gerät über diese Datei angesprochen wird?
Als ich dieses schrieb, hatte ich gerade den Fall, dass ich die printserv Prozesse alle gekillt hatte und dann mit vertauschten Gerätedateien neu gestartet. Trotzdem wurde auf den selben Drucker umgeleitet wie zuvor. Nur das Vertauschen der Portnummern hatte in dem Fall eine Auswirkung. Ein anderes Mal hatte es hingegen sehr wohl Auswirkungen, die Gerätedateien zu vertauschen. Erklärbar ist so ein Verhalten bislang nicht.

Wenn ich von "ein anderes Mal" spreche, meine ich immer, dass ich zwischendurch den Hub getrennt und wieder eingesteckt hatte. Das habe ich mittlerweile rund 50 Mal gemacht ohne den Router neu zu starten (und dabei auch festgestellt, dass die USB Device-ID nach 127 wieder mit 0 beginnt (7 Bit)).

Wenn ich rekapituliere, was ich hier schon so alles geschrieben habe, bekomme ich selbst den Eindruck, als sei ich geistig halb umnachtet. Weil ich mal das eine schreibe und dann wieder was völlig Gegensätzliches. Aber das liegt nicht an mir, sondern daran, dass sich das Gerät wirklich völlig unterschiedlich verhält. Und völlig unvorhersehbar. Mal so - und dann mal wieder vollkommen anders.

Kurz gesagt, printserv bekommt einen TCP-Port angegeben, unter dem er die Daten annimmt, und eine Gerätedatei, auf die er die Daten schreibt. printserv leitet garantiert nicht die Daten von Port 9104 an Node 0 weiter. Woher sollte er denn wissen, was Du mit Port 9104 vorhast?
Auf diese Idee war ich - wie oben gesagt - gekommen, weil es einmal den Fall gab, dass ich bei -d angeben konnte was ich wollte und trotzdem immer auf den selben Drucker gedruckt wurde. Und ja: Es waren zuvor wirklich alle printserv Prozesse gekillt worden. Es sei denn, "ps" macht falsche Angaben.

In manchen Fällen geht es jedes Mal, und in anderen Fällen nicht. Mit anderen Worten, es funktioniert nicht jedes Mal. [..]
Das freut mich für Dich, wenn es so ist, aber einige Deiner vorherigen Beiträge habe ich so verstanden, dass dem nicht so ist.
Was ich mit "manche Fälle" meinte, war der jeweilige Zustand des Routers nach dem Trennen und wieder Einstecken des USB Hubs. Danach war es in manchen Fällen egal, in welcher Reihenfolge man printserv für die einzelnen Drucker/Nodes startete und in manchen wiederum nicht. Wenn es aber egal war, dann war es das jedes Mal, also so lange, wie der Hub drin steckte. Und wenn nicht, galt dies auch so lange, bis der Hub getrennt wurde. Es klingt alles sehr verwirrend. Wenn man aber davon ausgeht, dass es zwei "Vergabestellen" für Minor-Numbers gibt (Kernel und Script), wie du angedeutet hast, erklärt sich dies.

Es gibt diese feste Verdrahtung nicht. Angenommen Du startest das System, und beide Drucker sind ausgeschaltet oder das Kabel nicht verbunden, was hier aufs gleiche heraus kommt. Du verbindest jetzt zunächst den Drucker auf USB3 das System erkennt einen USB Drucker und vergibt für diesen die Nummer 0. Damit meine ich nicht das Skript, sondern den Kernel selbst.
Du willst damit sagen, dass der Kernel schon intern (virtuell) die Nodes vergibt und es dann die Aufgabe des Scripts ist zu erraten, welche Node der Kernel zufällig vergeben hat und diese dann über das Anlegen eines Node-Files zu manifestieren? Na gute Nacht, wenn das so ist! Warum legt der Kernel dann nicht selbst die Gerätedatei unter der richtigen Node an?

Mit anderen Worten, es kommt nicht darauf an, wie die Datei heißt, die mit -d übergeben wird, sondern nur darauf, welche Gerätenummer hinter dieser Datei liegt. Die Gerätenummer legt nämlich fest, welches Geräte zu der Gerätedatei gehört. Und hier wenigstens ist die Zuordnung eindeutig, Minor Nummer 0 gehört zu usblp0 usw.
Wenn es immer so wäre, wäre es schön. Das erklärt aber nicht, warum ich hin und wieder die Gerätedateien beim printserv vertauschen konnte und es keine Änderung bewirkte.

Wenn Du nur einen Drucker entfernst, wird dessen Minor Nummer frei. Wenn dann dieser Drucker (oder ein anderer) wieder verbunden wird, bekommt er die gleiche Minor Nummer, weil es die erste freie Nummer ist. Er kann folglich auch unter dem gleichen Namen wie vorher angesprochen werden. Wenn der Drucker aber an einem anderen USB Port hängt, liest das Skript einen anderen Wert von TOPO aus und wählt daher einen anderen TCP Port für den Drucker aus.
Stimmt, das war ein Fehler bei mir. Ich hatte gar nicht daran gedacht, dass sich der TCP-Port dadurch ja geändert hat und es deshalb nicht mehr funktionierte. Aber diesen Test hatte ich auch nur einmal durchgeführt.

Das ist dann logisch, wenn die Anschlüsse am USB Hub parallel abgefragt werden. Eines der beiden Geräte antwortet einige Sekundenbruchteile früher als das andere, also bekommt es Minor 0, das zweite Geräte bekommt Minor 1, welches auch immer es ist.
Moment! WO bekommt es die Minor 0? Im Kernel oder vom Script? Das scheinen ja zwei verschiedene Paar Schuhe zu sein. Wenn das so ist, könnte es einen Teil des Durcheinanders erklären. Weil das Script hier quasi "raten" muss.

Nur um meine Verwirrung mal zu dokumentieren, habe ich ein Beispiel ausgesucht für das, was ich so erlebt habe. Es würde aber deine Aussage mit den unsichtbaren, kernel-internen Node-Nummern untermauern. Ich dokumentierte den Ablauf des Scripts über eine Protokolldatei. Und dabei erlebte ich die auf den ersten Blick verrücktesten Dinge. Hier mal ein Beispiel. lsusb zeigte folgendes:

Code:
BUS=001
DEV=104
VID=1a86
PID=7584
CLS=00
SCL=00
SPEED='full'
VER='1.1'
PROD='USB2.0-Print '
TOPO=22
ISOC=0
INUM=1
ICLS1=07
ISCL1=01

BUS=001
DEV=105
VID=04a9
PID=1051
CLS=00
SCL=00
SPEED='full'
VER='1.1'
MANU='Canon'
PROD='BJC-3000'
SNUM='67H9gp'
TOPO=32
ISOC=0
INUM=1
ICLS1=07
ISCL1=01

Also Device-ID 104 für den USB2.0-Print und ID 105 für den BJC-3000. Ich hatte alle Druckerprozesse mit "remove" über das Script getrennt. Es gab also keine Gerätedateien und keinen printserv Prozess mehr.

Daraufhin wollte ich dann den Drucker mit der ID 105 (BJC-3000) neu hinzufügen. Der chronologische Ablauf ist von oben nach unten. Rot ist der Teil, den ich selbst angestoßen habe. Blau sind die beiden Prozesse, die in der Folge vom Kernel automatisch angestoßen wurden, ohne dass ich dies veranlasst hätte.

Code:
[COLOR="#FF0000"]root@fritz:/etc/hotplug# ./printer add /proc/bus/usb/001/105 1 1 1
Start Script (manuell)
Parameter: >add< >/proc/bus/usb/001/105< >1< >1< >1<
UNUM: 105
UPRT: 3
PORT: 9106
DEVICE: /proc/bus/usb/001/105
DEVID: USB-proc-bus-usb-001-105
HANDLE: /var/USB-proc-bus-usb-001-105-printer
passeeren UNUM_105/UPRT_3/PORT_9106
mknod -m 666 /dev/usb_prntsvr-105.0 c 180 0[/COLOR]
										[COLOR="#0000FF"]Start Script (automatisch)
										Parameter: >remove< >/proc/bus/usb/001/104< >1< >< ><
										UNUM: 104
										UPRT: 0
										PORT: 9100
										DEVICE: /proc/bus/usb/001/104
										DEVID: USB-proc-bus-usb-001-104
										HANDLE: /var/USB-proc-bus-usb-001-104-printer
										passeeren UNUM_104/UPRT_0/PORT_9100[/COLOR]
[COLOR="#FF0000"]/sbin/printserv -d /dev/usb_prntsvr-105.0 -p 9106 -c /dev/console
eventadd 153 # Fehler!!!
eventadd 150 9106
Ende Script UNUM_105/UPRT_3/PORT_9106
vrijgeven UNUM_105/UPRT_3/PORT_9106[/COLOR]
										[COLOR="#0000FF"]Ende Script UNUM_104/UPRT_0/PORT_9100
										vrijgeven UNUM_104/UPRT_0/PORT_9100
Start Script (automatisch)
Parameter: >add< >/proc/bus/usb/001/106< >1a86< >7584< >0<
UNUM: 106
UPRT: 2
PORT: 9104
DEVICE: /proc/bus/usb/001/106
DEVID: USB-proc-bus-usb-001-106
HANDLE: /var/USB-proc-bus-usb-001-106-printer
passeeren UNUM_106/UPRT_2/PORT_9104
mknod -m 666 /dev/usb_prntsvr-106.1 c 180 1
/sbin/printserv -d /dev/usb_prntsvr-106.1 -p 9104 -c /dev/console
eventadd 150 9104
Ende Script UNUM_106/UPRT_2/PORT_9104
vrijgeven UNUM_106/UPRT_2/PORT_9104[/COLOR]

Obwohl ich eigentlich den Canon-Drucker /proc/bus/usb/001/105 auf USB3/Port9106 manuell hinzufügen wollte, wurde stattdessen der Laserdrucker auf USB2/Port9104 mit der DEV-ID 104 entfernt und mit einer neuen DEV-ID 106 gestartet. Erreichbar ist danach auf Port 9104 nicht der Laserdrucker, sondern der Canon-Drucker. Das zuvor vom Script schon erzeugte Node-File für den Canon-Drucker (mknod -m 666 /dev/usb_prntsvr-105.0 c 180 0) bleibt auch erhalten, obwohl der Start des Printservers für diesen Drucker mit einem Fehler beendet wurde. Wenn der Printserver für den Drucker nicht gestartet werden konnte, sollte das Node-File vorzugsweise entfernt werden. Aber das ist nicht das Problem.

Danach sieht lsusb dann so aus:

Code:
BUS=001
DEV=106
VID=1a86
PID=7584
CLS=00
SCL=00
SPEED='full'
VER='1.1'
PROD='USB2.0-Print '
TOPO=22
ISOC=0
INUM=1
ICLS1=07
ISCL1=01

BUS=001
DEV=105
VID=04a9
PID=1051
CLS=00
SCL=00
SPEED='full'
VER='1.1'
MANU='Canon'
PROD='BJC-3000'
SNUM='67H9gp'
TOPO=32
ISOC=0
INUM=1
ICLS1=07
ISCL1=01

Der Drucker am niedrigeren USB-Port hat nun die höhere ID. Warum der Drucker mit ID 104 (USB2.0-Print) in dem Moment entfernt wurde, als mknod für den Drucker mit der ID 105 (BJC-3000) aufgerufen wurde, bleibt auf den ersten Blick ein Rätsel. Eine Erklärung könnte aber sein, dass der Kernel intern (wie du Anfangs sagtest) die Node 0 für den Drucker 104 (USB2.0-Print) reserviert hatte und ne Krise kriegte, als ich den Drucker 105 (BJC-3000), der eigentlich zur Node 1 gehörte, der Node 0 zuordnen wollte. Danach ist dann unter Port 9104 (der der Node 1 zugeordnet wurde) der Drucker mit ID 105 (BJC-3000) erreichbar, weil dieser ja von Anfang an die Node 1 hatte.

Das stützt alles die Annahme, dass der Kernel seine Nodes intern zuordnet und das Script diese dann erraten muss. Dann verstehe ich allerdings nicht, warum der Kernel nicht immer auch die Scripte in der Reihenfolge startet, in der er die Nodes an die Drucker vergeben hat! Und das tut er definitiv nicht, das belegen meine Protokolle zweifelsfrei. Sonst könnte es ja auch nicht den Fehler mit der Vertauschung geben.

Konkret: Der Kernel vergibt z.B. die Node 0 an Drucker DEV:100 an USB2 und die Node 1 an den Drucker DEV:101 an USB3. Aber er startet das Script zuerst für DEV:101 und danach für DEV:100. Und dann kommt es zur Vertauschung. Hier ein Protokoll so einer Vertauschung:

Code:
[COLOR="#FF0000"]Start Script 1[/COLOR]
										[COLOR="#0000FF"]Start Script 2[/COLOR]
[COLOR="#FF0000"]Parameter: >add< >/proc/bus/usb/001/101< >04a9< >1051< >0<
UNUM: 101
UPRT: 3
PORT: 9106
DEVICE: /proc/bus/usb/001/101
DEVID: USB-proc-bus-usb-001-101
HANDLE: /var/USB-proc-bus-usb-001-101-printer
passeeren UNUM_101/UPRT_3/PORT_9106
mknod -m 666 /dev/usb_prntsvr-101.0 c 180 0[/COLOR]
										[COLOR="#0000FF"]Parameter: >add< >/proc/bus/usb/001/100< >1a86< >7584< >0<
										UNUM: 100
										UPRT: 2
										PORT: 9104
										DEVICE: /proc/bus/usb/001/100
										DEVID: USB-proc-bus-usb-001-100
										HANDLE: /var/USB-proc-bus-usb-001-100-printer
										passeeren UNUM_100/UPRT_2/PORT_9104[/COLOR]
[COLOR="#FF0000"]/sbin/printserv -d /dev/usb_prntsvr-101.0 -p 9106 -c /dev/console
eventadd 150 9106
Ende Script UNUM_101/UPRT_3/PORT_9106
vrijgeven UNUM_101/UPRT_3/PORT_9106[/COLOR]
										[COLOR="#0000FF"]mknod -m 666 /dev/usb_prntsvr-100.1 c 180 1
										/sbin/printserv -d /dev/usb_prntsvr-100.1 -p 9104 -c /dev/console
										eventadd 150 9104
										Ende Script UNUM_100/UPRT_2/PORT_9104
										vrijgeven UNUM_100/UPRT_2/PORT_9104[/COLOR]


Damit garantierst Du, dass der Hauptteil vom Skript für die niedrigere Portnummer zuerst ausgeführt wird. Das Skript wird daraufhin für den niedrigeren Port die Minor Nummer 0 verwenden. Du schreibst aber ein paar Sätze weiter oben, dass es völlig zufällig und beliebig zu sein scheint, welche Minor nun letztlich welchem USB-Port zugeordnet wird. Somit ist es nicht wirklich sicher, dass die Zuordnung nachher auch passt. Wenn die Minor Nummer 0 für den Drucker am zweiten Port zugeteilt wurde, wird das Skript trotzdem diese mit dem niedrigeren TCP Port verbinden.
Da haben wir beide uns missverständlich ausgedrückt. Wir sollten immer dazu schreiben, WER die Minor-Number nun vergeben hat. Der Kernel (intern) oder das Script (explizit) durch mknod. Mein sleep funktioniert, wenn die Minor-Nummern vom Kernel immer in der Reihenfolge vergeben werden, in der auch die physikalischen USB-Ports sortiert sind. Sollten die Minor-Nummern allerdings eher in der Reihenfolge vergeben werden, wie die DEV-IDs vergeben wurden, hilft das Script nicht. Dann müsste die Startreihenfolge von den DEV-IDs abhängen und die kann ich nicht direkt heranziehen, um mit sleep zu verzögern. Da müsste man dann etwas tricksen.

Ich werde das durch Tests nochmal verifizieren. Aber bisher sieht es so aus, als würden die Nodes vom Kernel immer in der Reihenfolge der physikalischen USB-Ports vergeben. Allerdings nur beim Starten des Routers oder Einstecken des Hubs. Umstecken der Drucker im laufenden Betrieb ist mit dieser Topologie wegen der den physikalischen USB-Ports fest zugeordneten TCP-Ports eh strengstens verboten.

Ergänzung: Ich habe den Hub jetzt 20 Mal aus- und eingesteckt. Es hat immer funtkioniert, obwohl laut Protokoll in etwa 50% der Fälle das Script zuerst mit der höheren und danach erst mit der niedrigeren Device-ID gestartet wurde. Sonst kam es dann immer zu Vertauschungen. Seit dem sleep nicht mehr. Das deutet also darauf hin, dass meine Annahme korrekt war. Ich werde jetzt ein neues Image bauen und das sleep in mein Printer-Patchfile einarbeiten.
 
Zuletzt bearbeitet:
Als ich dieses schrieb, hatte ich gerade den Fall, dass ich die printserv Prozesse alle gekillt hatte und dann mit vertauschten Gerätedateien neu gestartet. Trotzdem wurde auf den selben Drucker umgeleitet wie zuvor. Nur das Vertauschen der Portnummern hatte in dem Fall eine Auswirkung. Ein anderes Mal hatte es hingegen sehr wohl Auswirkungen, die Gerätedateien zu vertauschen. Erklärbar ist so ein Verhalten bislang nicht.
Was für Ports meinst Du hier? TCP Ports, USB Hub Ports, sonstige Ports?
Wenn sowohl die Vergabe der Minor Nummern als auf die Reihenfolge des Aufrufs des Skripts nicht definiert ist, gibt es vier Fälle. Beide werden in der Reihenfolge zugewiesen, wie das Skript es erwartet, dann passt alles. Eines von beiden wird wie erwartet ausgeführt, das andere nicht, das sind zwei Fälle, in denen die Zuordnung nicht passt. Der vierte Fall ist, dass beides vertauscht ist. Bei nur zwei Druckern passt dann wieder alles zusammen. Bei mehr als zwei Druckern gäbe es viele spannende Kombinationen.
Auf diese Idee war ich - wie oben gesagt - gekommen, weil es einmal den Fall gab, dass ich bei -d angeben konnte was ich wollte und trotzdem immer auf den selben Drucker gedruckt wurde. Und ja: Es waren zuvor wirklich alle printserv Prozesse gekillt worden. Es sei denn, "ps" macht falsche Angaben.
Du schreibst, es waren alle printserv Prozesse gekillt worden. Meinst Du damit, dass Du die printserv Prozesse gekillt hast und sonst nichts, oder dass Du das Skript mit remove für beide Drucker aufgerufen hast, was unter anderem die printserv Prozesse stoppt, aber auch noch einiges sonst tut? Das ist ein wichtiger Unterschied.
Du willst damit sagen, dass der Kernel schon intern (virtuell) die Nodes vergibt und es dann die Aufgabe des Scripts ist zu erraten, welche Node der Kernel zufällig vergeben hat und diese dann über das Anlegen eines Node-Files zu manifestieren? Na gute Nacht, wenn das so ist! Warum legt der Kernel dann nicht selbst die Gerätedatei unter der richtigen Node an?
Ich würde es nicht ganz so formulieren, aber im Kern ist es das, was ich seit #28 im letzten Absatz schreibe. Das Kernel Modul usblp erkennt ein neues USB Gerät, das sich als Drucker identifiziert, also zum Treiber passt. Daraufhin bekommt der gerade neu erkannte Drucker die nächste freie Nummer. Die Aufgabe des Skripts ist nicht, zu erraten, welche Nummer der Drucker bekommen hat, sondern das festzustellen. Leider stellt das Skript das nicht fest, sondern ratet statt dessen, was zugegebenermaßen einfacher ist. Ein Problem mit der Art, wie das Skript funktioniert ist, dass das Modul usblp erst aufgerufen wird, wenn der erste Drucker erkannt wird, aber nachdem die Nummer geraten wurde, die der Drucker bekommen soll. Bevor das Modul usblp geladen wird, sind noch gar keine Nummern vergeben worden, also kann das Skript auch nicht viel anderes tun als raten. Ich weiß aber nicht, ob dies dem Autor des Skripts bewusst war. Nun ist die Architektur hier von AVM vorgegeben, und für einen Drucker funktioniert dies auch. Es funktioniert auch für mehrere Drucker, solange immer einer nach dem anderen eingeschaltet oder eingesteckt wird. Es funktioniert eben nicht zuverlässig, wenn beide Drucker gleichzeitig erkannt werden.
Der Kernel legt normalerweise selbst keine Gerätedateien an. Er ruft statt dessen ein Skript auf, das dies tun soll. Dieses Skript startet letztlich /etc/hotplug/printer, was wiederum die Gerätedateien anlegt.
Aber selbst angenommen, der Kernel würde selbst die Gerätedateien selbst anlegen. Dann gäbe es zunächst ein /dev/usb/lp0 und kurz danach ein /dev/usb/lp1. Abgesehen davon, dass davon noch kein printserv gestartet ist, weißt Du auch nicht ob lp0 jetzt der eine oder der andere Drucker ist.

Moment! WO bekommt es die Minor 0? Im Kernel oder vom Script? Das scheinen ja zwei verschiedene Paar Schuhe zu sein. Wenn das so ist, könnte es einen Teil des Durcheinanders erklären. Weil das Script hier quasi "raten" muss.
Es ist immer der Kernel, der die Minor Nummern vergibt, und zwar in der Reihenfolge, in der das usblp Modul sich mit den Druckern verbindet. Das ist nicht zwangsläufig die Reihenfolge, in der die USB Geräte gefunden werden, wie wir gesehen haben. Der Kernel erkennt zunächst ein USB Gerät. Dann fragt er, welche Funktionen das Gerät unterstützt. Für alle diese Funktionen werden dann passende Treiber gesucht. Es gibt auch USB Geräte mit mehreren Funktionen, zum Beispiel USB Drucker, Scanner, Massenspeicher (SD Karte, usw.). Oder Tastatur und Maus in einem Gerät. Es werden also einige Anfragen an das USB Gerät geschickt, und auf Antworten gewartet. In der Zeit, wo ein Prozess auf eine Antwort wartet, kann ein anderer Prozess laufen.
Das Skript muss nicht zwangsläufig raten, aber es ist das, was es derzeit tut. Wobei die Alternative wie gesagt deutlich komplizierter ist.

Nur um meine Verwirrung mal zu dokumentieren, habe ich ein Beispiel ausgesucht für das, was ich so erlebt habe. Es würde aber deine Aussage mit den unsichtbaren, kernel-internen Node-Nummern untermauern. Ich dokumentierte den Ablauf des Scripts über eine Protokolldatei. Und dabei erlebte ich die auf den ersten Blick verrücktesten Dinge. Hier mal ein Beispiel.
Das ist allerdings seltsam. Es wäre interessant, was das Kernel Protokoll dazu sagt.
Es zeigt auch, dass das Skript beim Remove keine Informationen zum Port bekommt. Vermutlich ruft es lsusb auf, aber lsusb gibt keine Ausgabe, weil das Gerät eben nicht mehr da ist. Daher setzt es die Port Nummer auf 0.
Obwohl ich eigentlich den Canon-Drucker /proc/bus/usb/001/105 auf USB3/Port9106 manuell hinzufügen wollte, wurde stattdessen der Laserdrucker auf USB2/Port9104 mit der DEV-ID 104 entfernt und mit einer neuen DEV-ID 106 gestartet.
Genau das ist seltsam, das System meldet ein Entfernen des Gerätes, und es wird nachher unter einer neuen Nummer wieder erkannt. Was für eine Box ist es denn? Die USB Implementierung von AVM ist auf manchen Boxen besser als auf anderen.
Erreichbar ist danach auf Port 9104 nicht der Laserdrucker, sondern der Canon-Drucker. Das zuvor vom Script schon erzeugte Node-File für den Canon-Drucker (mknod -m 666 /dev/usb_prntsvr-105.0 c 180 0) bleibt auch erhalten, obwohl der Start des Printservers für diesen Drucker mit einem Fehler beendet wurde. Wenn der Printserver für den Drucker nicht gestartet werden konnte, sollte das Node-File vorzugsweise entfernt werden.
Und welcher war vorher unter TCP Port 9104 erreichbar?
Was ist denn der Fehler, weswegen printserv beendet wird? Vermutlich, dass die Minor Nummer 0 nicht mehr vorhanden war, weil die durch das Entfernen von USB 104 weggefallen ist. Mit dem Parameter -c kann man dem printserv sagen, wohin Ausgaben sollen. Es steht aber "TTY for output", daher ist nicht sicher, ob er auch eine reguläre Datei akzeptiert. Jedenfalls hat man nichts von /dev/console, wenn man nicht wirklich eine Konsole angeschlossen hat.
Der Drucker am niedrigeren USB-Port hat nun die höhere ID. Warum der Drucker mit ID 104 (USB2.0-Print) in dem Moment entfernt wurde, als mknod für den Drucker mit der ID 105 (BJC-3000) aufgerufen wurde, bleibt auf den ersten Blick ein Rätsel. Eine Erklärung könnte aber sein, dass der Kernel intern (wie du Anfangs sagtest) die Node 0 für den Drucker 104 (USB2.0-Print) reserviert hatte und ne Krise kriegte, als ich den Drucker 105 (BJC-3000), der eigentlich zur Node 1 gehörte, der Node 0 zuordnen wollte. Danach ist dann unter Port 9104 (der der Node 1 zugeordnet wurde) der Drucker mit ID 105 (BJC-3000) erreichbar, weil dieser ja von Anfang an die Node 1 hatte.
Der Drucker mit der ID 104 wird nicht in dem Moment entfernt, wo mknod aufgerufen wird, sondern zwischen dort, wo die Debug Ausgabe für mknod erzeugt wird und der Stelle, wo die nächste Ausgabe kommt, also über den Aufruf von printserv. Wenn ich mir das Skript anschaue, sind dazwischen noch einige andere Befehle drin, unter anderem "modprobe usblp", "lsusb", und je nachdem, wo Du die Ausgaben plaziert hast, auch printserv. Dazwischen sind noch andere Befehle, die aber eher nichts damit zu tun haben.
Der Kernel hat keine Meinung dazu, welcher Drucker zu welcher Minor Nummer gehört, und erst recht hat er keine Meinung dazu, dass und von welchem TCP Port Daten auf diesen Druckern landen sollen. Er kriegt daher auch sicher keine Krise, weil eine Zuordnung gemacht wird, die nicht Deinen Vorstellungen entspricht. Es muss irgend etwas geben, was den USB Disconnect veranlasst hat, und das ist entweder ein Hardware Problem, aber eher eine Folge von dem, was das Skript da tut, aber nicht vom mknod Aufruf selbst.

Das stützt alles die Annahme, dass der Kernel seine Nodes intern zuordnet und das Script diese dann erraten muss. Dann verstehe ich allerdings nicht, warum der Kernel nicht immer auch die Scripte in der Reihenfolge startet, in der er die Nodes an die Drucker vergeben hat! Und das tut er definitiv nicht, das belegen meine Protokolle zweifelsfrei. Sonst könnte es ja auch nicht den Fehler mit der Vertauschung geben.

Konkret: Der Kernel vergibt z.B. die Node 0 an Drucker DEV:100 an USB2 und die Node 1 an den Drucker DEV:101 an USB3. Aber er startet das Script zuerst für DEV:101 und danach für DEV:100. Und dann kommt es zur Vertauschung.
Es ist auf jeden Fall so, dass der Kernel die Minor Nummern vergibt, und das Skript diese herausfinden sollte. Es ist auch so, dass das Skript es statt dessen mit raten versucht, aber das muss nicht so sein, es ist nur einfacher.
Der Kernel hat beim ersten Aufruf des Skripts noch gar keine Minor Nummern vergeben. Es wurde noch nicht einmal das Modul usblp geladen, was letztlich die Drucker abfragen und die Nummern zuordnen wird. Der Kernel kann also noch gar nicht wissen, dass diese Skript das Modul usblp laden wird und dieses dann Minor Nummern für die Drucker vergeben wird. Folglich kann der Kernel auch nicht das Skript in der Reihenfolge starten.
Statt dessen wird das Skript gestartet, weil ein USB Gerät erkannt wird. Das Skript bestimmt die Klasse des Geräts und stellt fest, dass es als Drucker ansprechbar ist. Nach einigen anderen Operationen lädt es dann endlich das Modul usblp.
Wir können davon ausgehen, dass der Kernel die Prozesse in der Reihenfolge startet, in der er die Geräte erkennt. Aber diese Prozesse führen etliche andere Kommandos aus, und wir können nicht wissen, welcher Prozess zuerst zur Semaphore kommt. Den Teil hast Du mit dem Sleep auf jeden Fall in eine definierte Reihenfolge gebracht. Wenn die Vergabe der Minor Nummern im Kernel auch immer in der gleichen Reihenfolge bleibt, sollte es mit dem "Raten" im Skript funktionieren.
Da haben wir beide uns missverständlich ausgedrückt. Wir sollten immer dazu schreiben, WER die Minor-Number nun vergeben hat. Der Kernel (intern) oder das Script (explizit) durch mknod. Mein sleep funktioniert, wenn die Minor-Nummern vom Kernel immer in der Reihenfolge vergeben werden, in der auch die physikalischen USB-Ports sortiert sind. Sollten die Minor-Nummern allerdings eher in der Reihenfolge vergeben werden, wie die DEV-IDs vergeben wurden, hilft das Script nicht. Dann müsste die Startreihenfolge von den DEV-IDs abhängen und die kann ich nicht direkt heranziehen, um mit sleep zu verzögern. Da müsste man dann etwas tricksen.
... Umstecken der Drucker im laufenden Betrieb ist mit dieser Topologie eh strengstens verboten.
Es ist immer der Kernel, der die Minor Nummern vergibt, konkret das Modul usblp. Das Skript vergibt die Nummern weder explizit noch implizit, es mach implizit Annahmen darüber, in welcher Reihenfolge der Kernel die Nummern vergeben wird. Beim ersten erkannten Drucker also, bevor überhaupt das Modul usblp in den Kernel geladen wird. Diese Annahmen sind korrekt, wenn die Drucker nacheinander eingeschaltet werden, aber nicht zwangsläufig, wenn beide Drucker gleichzeitig verfügbar werden.
Und wie Du richtig schreibst, es ist immer getrickst, ob mit sleep oder ohne. Der richtige Ansatz wäre, die korrekten Kernel Ereignisse auszuwerten und nicht diese, die jetzt verwendet werden. Es würde aber einen größeren Eingriff an dem bedeuten, was AVM da vorgegeben hat.
 
Zuletzt bearbeitet:
Hallo ihr beiden. Ich verfolge interessiert eure langwierige Diskussion. Wärt ihr so nett das mal an einem konkreten Beispiel zu erklären? Ich habe einen Drucker an meiner 7390 angeschlossen und lade das usblp Modul.
Code:
usblp0: USB Bidirectional printer dev 3 if 1 alt 0 proto 2 vid 0x03F0 pid 0x5912
usblp1: USB Bidirectional printer dev 3 if 3 alt 0 proto 2 vid 0x03F0 pid 0x5912
usbcore: registered new interface driver usblp

T:  Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  3 Spd=480 MxCh= 0
D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=03f0 ProdID=5912 Rev= 1.00
S:  Manufacturer=HP
S:  Product=Officejet Pro 8600
S:  SerialNumber=CN2ACBXGG405KC
C:* #Ifs= 4 Cfg#= 1 Atr=c0 MxPwr=  2mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=cc Prot=00 Driver=(none)
E:  Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=83(I) Atr=03(Int.) MxPS=  64 Ivl=8ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=07(print) Sub=01 Prot=02 Driver=usblp
E:  Ad=08(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=89(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage
E:  Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 2 Cls=07(print) Sub=01 Prot=02 Driver=usblp
E:  Ad=0a(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=8b(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
Wo kann man jetzt sehen welche Zuordnung das usblp Modul für den Drucker vorgenommen hat? Und wäre es möglich das vorhandene Skript so zu patchen, dass es das Modul früher lädt und die Zuordnung übernimmt?

Gruß
Oliver
 
Das ist ein sehr gutes Beispiel.
Ich vermute mal, wenn Du schreibst "einen Drucker angeschlossen", dann heißt dass, dass es wirklich nur einer ist und nicht zwei.
Ich hatte weiter oben geschrieben, dass ein USB Gerät mehrere Funktionen haben kann. Dieses Gerät hat gleich vier.
Die erste, "I:...Cls=ff(vend.)", ist vermutlich zum Scannen.
Die dritte, "i:...Cls=08(stor.)", ist ein USB Massenspeicher, vermutlich ein SD-Slot.
Die zweite und vierte Funktion, "I:...Cls=07(print)", ist zum Drucken.

Dieser eine Drucker meldet sich also unter anderem als zwei Drucker. Deswegen werden oben auch usblp0 und usblp1 angezeigt, mit "if 1" und "if 3" (interface) am gleichen Gerät. Warum der Drucker gleich zwei Printer Interfaces hat, weiß wohl nur HP, oder es mag auch dokumentiert sein. Auf jeden Fall würde das Skript in der jetzigen Form, wenn Du zuerst diesen Drucker verbindest und dann einen anderen, die Ausgaben für den ersten Drucker auf das erste Interface dieses Druckers leiten und die Ausgaben für den zweiten Drucker auf das zweite Interface auch von diesem Drucker. Der zweite Drucker würde überhaupt nichts bekommen.

Die Zuordnung siehst Du in den ersten Zeilen vom Protokoll:
Code:
usblp0: USB Bidirectional printer dev 3 if 1 alt 0 proto 2 vid 0x03F0 pid 0x5912
usblp1: USB Bidirectional printer dev 3 if 3 alt 0 proto 2 vid 0x03F0 pid 0x5912
Es wurden also Minor Nummern 0 und 1 für die beiden Interfaces dieses einen Druckers vergeben, weil 0 die erste freie Nummer war.

Was man hier nicht sieht, ist, ob der Drucker direkt oder an einem USB Hub angeschlossen ist, und wenn ja, an welchem Port. Damit allein funktioniert also keine Zuordnung USB Port zu TCP Port. Außerdem will man in so einem Skript nicht im Protokoll lesen müssen.

Da es bei Dir eine 7390 ist, hätte ich gehofft, dass es da vernünftiger abläuft als auf den alten Boxen, aber ein kurzer Blick in /etc/hotplug/udev-printer-lp sieht mindestens so schlimm aus. Zumindest wird das Modul nicht mehr im Skript geladen, dafür wird aber an mehreren Stellen dreimal versucht, es zu entladen. Das Modul usplp ist ca. 10kB groß, wenn es noch etwas mehr Speicher im Kernel braucht, sollte das kein Problem sein, speziell bei den neueren Boxen.

Der Ansatz vom jetzigen Skript hat den Vorteil, dass keine Konfiguration notwendig ist. Es hat den Nachteil, dass es einige Einschränkungen hat (nur ein USB Hub, nur ein Drucker Interface pro Drucker, usw.), und dass es nicht immer den richtigen Drucker findet.
Ein guter Ansatz wäre, nicht auf die Erkennung einen USB-Geräts zu reagieren, sondern auf das Erkennen eines Druckers in usblp. Dann müsste man herausfinden, zu welchem USB Gerät dieser usblp gehört. Es stellt sich die Frage, ob man eine vernünftige Zuordnung ohne Konfiguration machen kann. Letztlich muss ja eine TCP Port Nummer herauskommen. Oder man legt fest, dass die Zuordnung von TCP Ports zu Druckern konfiguriert werden muss. Auf jeden Fall sollte es ein Verfahren sein, das zuverlässig funktioniert. Bei der Gelegenheit könnte man auch erwägen, das printserv Programm durch etwas einfacheres zu ersetzen. Wozu braucht man denn 4 Threads, um Daten auf einen Drucker auszugeben?
Der Kernel ist in der Lage, benötigte Module bei Bedarf selbst zu laden, dafür gab es früher "CONFIG_KMOD: Automatic kernel module loading", und es war bei AVM nicht aktiviert. Inzwischen habe ich keine vergleichbare Einstellung mehr gefunden, also gehe ich davon aus, dass neuere Kernel das grundsätzlich tun. Man kann also den ganzen Teil weglassen, wo in in /etc/hotplug/udev-printer-lp geprüft wird, ob es sich überhaupt um einen Drucker handelt. Wenn ein Drucker angeschlossen wird, lädt der Kernel automatisch das Modul usblp und das Gerät wird als Drucker erkannt. Dafür wird garantiert auch ein Event generiert, und auf den neueren Boxen mit udev kann man da auch sicher leichter etwas einbauen. Da müsste man nur noch den Gerätepfad herausfinden und entweder über eine Konfigurationsdatei oder eine Automatik eine Portnummer bestimmen.
 
Hi Ralf!

Erstmal ganz herzlichen Dank für deine sehr ausführliche Antwort! Du hast echt den Durchblick, das muss man sagen. Dagegen komme ich mir wie ein blutiger Anfänger vor. ;-) Aber du hast nun die letzten Wissenslücken bei mir geschlossen und ich denke, dass ich es jetzt so ziemlich verstanden habe, soweit das überhaupt möglich ist.

Die wichtigste Information war, dass erst usblp die Zuordnung der Nodes vornimmt, die dann quasi nur noch durch Erzeugen einer Gerätedatei unter /dev "manifestiert" wird. Das war die Schlüsselinformation, die mir erst jetzt richtig bewusst geworden ist. Da usblp aber erst spät im Script geladen wird, ist das vorherige Erzeugen einer Minor Number reines Stochern im Ungewissen.

So viel wie in den letzten Tagen habe ich schon ewig nicht mehr auf der Shell und mit dem vi gearbeitet. Wenn man damit fast 30 Jahre lang nichts mehr zu tun hatte, ist alles Wissen ziemlich vergraben, bis auf ganz rudimentäre Dinge. Erfreulich aber, dass sich in 30 Jahren da nur wenig verändert hat. Im Gegensatz zu Windows. Wenig Veränderung bei den grundlegenden Dingen ist auch die Basis für wirklich leistungsfähige Systeme.

Was für Ports meinst Du hier? TCP Ports, USB Hub Ports, sonstige Ports?
Ich meinte natürlich TCP Ports. Dem printserv wird ja nur die Gerätedatei und der TCP Port übergeben. Erst als ich den TCP Port getauscht hatte, kam die Druckausgabe richtig raus.

Du schreibst, es waren alle printserv Prozesse gekillt worden. Meinst Du damit, dass Du die printserv Prozesse gekillt hast und sonst nichts, oder dass Du das Skript mit remove für beide Drucker aufgerufen hast, was unter anderem die printserv Prozesse stoppt, aber auch noch einiges sonst tut? Das ist ein wichtiger Unterschied.
Meinst du? Das remove im Script löscht eigentlich nur die Device-Node unter /dev und killt alle Prozesse. Der Rest ist Kür (Status- und ID-Files aktualisieren). Ich habe manuell alle Prozesse gekillt, nicht aber die Gerätedatei unter /dev gelöscht.

Der Kernel legt normalerweise selbst keine Gerätedateien an. Er ruft statt dessen ein Skript auf, das dies tun soll. Dieses Skript startet letztlich /etc/hotplug/printer, was wiederum die Gerätedateien anlegt.
Ich finde nur die Reihenfolge seltsam bis bedenklich: Der Kernel erkennt ein neu angeschlossenes USB-Gerät. Woher weiß der Kernel, dass das ein Drucker ist? Sonst würde er doch nicht (indirekt) das Script /etc/hotplug/printer aufrufen in dem aber erst durch usblp explizit festgestellt wird, ob es sich um einen Drucker handelt? Diese Logik leuchtet mir momentan nicht ein. Das ist doch das Pferd von hinten aufgezäumt!? Oder habe ich was falsch verstanden?

Aber selbst angenommen, der Kernel würde selbst die Gerätedateien selbst anlegen. Dann gäbe es zunächst ein /dev/usb/lp0 und kurz danach ein /dev/usb/lp1. Abgesehen davon, dass davon noch kein printserv gestartet ist, weißt Du auch nicht ob lp0 jetzt der eine oder der andere Drucker ist.
Jepp. Aber der Kernel könnte, wenn er die Gerätedatei selbst anlegt (oder wenigstens die MINOR selbst festlegt), beim Aufruf des Scripts einfach MINOR als Parameter mit übergeben. So wie er derzeit ja auch die USB VID und PID beim Aufruf als Parameter übergibt. Und schon wäre das Problem gelöst.

Es zeigt auch, dass das Skript beim Remove keine Informationen zum Port bekommt. Vermutlich ruft es lsusb auf, aber lsusb gibt keine Ausgabe, weil das Gerät eben nicht mehr da ist. Daher setzt es die Port Nummer auf 0.
Das ist immer so! Das Gerät unter /proc/bus/usb/001/ existiert dann schon nicht mehr und daher gibt lsusb einen Error zurück, was in der weiteren Auswertung eine 0 ergibt. Ein Vorteil dabei ist, dass meine Script-Anpassung mit "sleep 0" beim remove nicht wartet.

Genau das ist seltsam, das System meldet ein Entfernen des Gerätes, und es wird nachher unter einer neuen Nummer wieder erkannt. Was für eine Box ist es denn? Die USB Implementierung von AVM ist auf manchen Boxen besser als auf anderen.
Das ist ein Speedport W920V von der Telekom. Den gabs praktisch für lau zum Entertain dazu. Er entspricht technisch weitgehend der Fritzbox 7570. Bei Freetz wird das Teil als "Alien Hardware" bezeichnet. Ich habe den Kernel nicht ausgewechselt. Sie läuft zwar auch mit einem original 7570 Kernel, aber sicherer ist es, den original Telekom Kernel zu behalten und nur den Rest drumerhum auszuwechseln. Der Telekom Kernel ist aber bis auf die Ansteuerung der Leuchtdioden, die etwas anders aufgebaut sind, wohl weitgehend identisch zum AVM-Kernel.

Und welcher war vorher unter TCP Port 9104 erreichbar?
Vorher war es der Laserdrucker. Der hängt ja immer an USB-Port 2. Und nach der Änderung (DEV:104 -> DEV:106) war es dann der BJC-3000, obwohl DEV:106 der Laser ist.

Was ist denn der Fehler, weswegen printserv beendet wird?
Das vermag ich nicht mehr zu sagen, Ich habe das sleep wieder rausgenommen und eben mehrfach versucht, den Fehler mit einer Ausgabe des Printservers auf /dev/tty (meine Telnet Session) zu reproduzieren, aber es hat immer fehlerfrei funktioniert. Das einzige, was fast jedesmal falsch war, war die Zuordnung der Drucker. Nochmal ein Zeichen dafür, dass mein sleep wirklich hilft.

Der Drucker mit der ID 104 wird nicht in dem Moment entfernt, wo mknod aufgerufen wird, sondern zwischen dort, wo die Debug Ausgabe für mknod erzeugt wird und der Stelle, wo die nächste Ausgabe kommt, also über den Aufruf von printserv.
Ja, du hast mal wieder völlig Recht. ;-) Die Ausgaben finden immer direkt in der Zeile vor der Ausführung des jeweiligen Befehls statt.

Es ist auf jeden Fall so, dass der Kernel die Minor Nummern vergibt, [...]
Genauer: Das Kernel-Modul usblp, wenn ich es richtig verstanden habe.

Statt dessen wird das Skript gestartet, weil ein USB Gerät erkannt wird. Das Skript bestimmt die Klasse des Geräts und stellt fest, dass es als Drucker ansprechbar ist.
Wo und wie findet dies denn in unserem Skript statt? Oder meinst du das erste Script, das direkt vom Kernel gestartet wird und dann unser printer-skript startet? Kann man das auch irgendwo finden?

Es ist immer der Kernel, der die Minor Nummern vergibt, konkret das Modul usblp. Das Skript vergibt die Nummern weder explizit noch implizit, es mach implizit Annahmen darüber, in welcher Reihenfolge der Kernel die Nummern vergeben wird.
Ja, ich habe mich etwas missverständlich ausgedrückt. Mit "expliziter" Vergabe durch das printer-Skript meinte ich das explizite Anlegen einer Gerätedatei unter einer bestimmten Node mit mknod.
 
Zuletzt bearbeitet:
Warum der Drucker gleich zwei Printer Interfaces hat, weiß wohl nur HP, oder es mag auch dokumentiert sein.
Ich vermute mal, das eine ist ein PCL-Interface und das andere ein PS-Interface. Jeder modernere HP-Drucker taucht ja auch unter Windows als zwei unterschiedliche Drucker auf, nämlich als ein PCL- und ein PS-Drucker. Ich habe auch noch einen HP Multifunktionsdrucker mit Scanner und SD-Kartenslot hier stehen. Den habe ich noch nie an die Fritzbox gehängt, weil es ein Netzwerkdrucker ist und er direkt im LAN hängt. Vermutlich dürfte das dann aber ähnlich aussehen.

Auf jeden Fall würde das Skript in der jetzigen Form, wenn Du zuerst diesen Drucker verbindest und dann einen anderen, die Ausgaben für den ersten Drucker auf das erste Interface dieses Druckers leiten und die Ausgaben für den zweiten Drucker auf das zweite Interface auch von diesem Drucker. Der zweite Drucker würde überhaupt nichts bekommen.
Warum? Müsste das zweite Gerät dann nicht als dritter Drucker unter usblp2 installiert werden? Es ist sowieso gewagt, wenn es zwei virtuelle Drucker mit der selben Device-ID gibt. Wird das printer-Script dann nur einmal aufgerufen oder wird es für die selbe Device-ID dann zweimal aufgerufen? Ich tippe auf ersteres. Wenn es nur einmal aufgerufen wird, wird auch nur eine Gerätedatei erzeugt. Und diese hat dann vermutlich die Node 0. Das heißt, es wird nur ein Drucker installiert und zwar der mit der Node-ID 0. Der zweite wird dann gar nicht ansprechbar sein. Wird das Script zweimal mit der selben Device-ID aufgerufen, so würde der erste Drucker unter Node 0 und der zweite unter Node 1 installiert. Da aber beide virtuellen Drucker bei TOPO vermutlich die selbe Zahl vorne haben werden, würden beide auf dem selben TCP-Port installiert. Dass verhindert das Script in "# Printserver port already in use?". Der zweite virtuelle Drucker an usblp1 würde also wohl nicht installiert werden. Langsam kriege ich fast Lust, mal meinen HP dranzustöpseln, um zu sehen was passiert. ;-)

@oliver: Mich würde mal interessieren, wie die Ausgabe von "lsusb -t -s" bei dir aussieht. Vor allem wenn noch ein weiteres Gerät mit dranhängt (falls du noch einen zweiten USB-Drucker hast).

Die Zuordnung siehst Du in den ersten Zeilen vom Protokoll:
Code:
usblp0: USB Bidirectional printer dev 3 if 1 alt 0 proto 2 vid 0x03F0 pid 0x5912
usblp1: USB Bidirectional printer dev 3 if 3 alt 0 proto 2 vid 0x03F0 pid 0x5912
Das ist ja aus dem kernel logfile. Damit könnte man dann eigentlich auf sehr einfache Weise die Nodes zuverlässig bestimmen (nachdem usblp gestartet wurde). Oder man überrredet usblp irgendwie dazu, einige informative Ausgaben irgendwo hinzuschreiben. Oder man passt das Modul etwas an. Wie ist es mit diesem Code hier?

Oder wie wäre es einfach mit
Code:
                # Device node
                modprobe $MODULE
                MINOR=$(dmesg | grep ": usblp[[:digit:]]: USB " | sed -n "s/^.*: usblp\([0-9]\).* printer dev $UNUM if .*$/\1/p")
                USB_DEVICE=$DEV_PREFIX-$UNUM.$MINOR
Das holt auf ganz einfache und schnelle Weise die von usblp an den Drucker mit der Device-ID $UNUM zugewiesene Node-ID aus dem Kernel-Logfile und erzeugt daraus die Gerätedatei. Funktioniert bei mir absolut zuverlässig. Ohne jedes sleep. Die "Ratestunde" unter "# Get next USB minor number..." kann dann völlig entfallen. Das ist im Grunde genau das, was Oliver vorgeschlagen hatte. Das löst auch das Problem mit mehreren virtuellen Druckern mit der selben Device-ID, weil es das erste Interface des ersten physikalischen Druckers mit Node 0 und den zweiten Drucker dann mit Node 2 installieren wird.
 
Zuletzt bearbeitet:
Meinst du? Das remove im Script löscht eigentlich nur die Device-Node unter /dev und killt alle Prozesse. Der Rest ist Kür (Status- und ID-Files aktualisieren). Ich habe manuell alle Prozesse gekillt, nicht aber die Gerätedatei unter /dev gelöscht.
Das remove im Script entfernt auch das Modul usblp beim letzten Drucker, was bedeutet, dass das Modul beim Erkennen des nächsten Druckers wieder neu geladen wird, was bedeutet, dass die Minor Nummern wieder frisch vergeben werden.
Wenn Du andererseits die Gerätedateien unter /dev nicht löscht, wird das Skript aus deren Existenz folgern, dass sie auch in Verwendung sind, und höhere Nummern vergeben. Und wie wir an anderer Stelle gesehen haben, hat das Skript beim remove keinen Zugriff mehr auf die Portnummer und wird daher nicht unbedingt die nicht mehr benötigte Gerätedatei entfernen, was Probleme beim Erkennen des nächsten Druckers geben kann.

Ich finde nur die Reihenfolge seltsam bis bedenklich: Der Kernel erkennt ein neu angeschlossenes USB-Gerät. Woher weiß der Kernel, dass das ein Drucker ist? Sonst würde er doch nicht (indirekt) das Script /etc/hotplug/printer aufrufen in dem aber erst durch usblp explizit festgestellt wird, ob es sich um einen Drucker handelt? Diese Logik leuchtet mir momentan nicht ein. Das ist doch das Pferd von hinten aufgezäumt!? Oder habe ich was falsch verstanden?
Das Ganze ist seltsam, aber von AVM vorgegeben. Es kommt etwas auf die Firmware an, aber bei meiner ist der Weg ungefähr so:
Der Kernel ruft /sbin/hotplug auf. Diese Skript ruft /etc/hotplug/$1.pandu auf. Das einzige Skript mit passendem Namen ist /etc/hotplug/usb.pandu, also wird Hotplug für alle Ereignisse außer usb ignoriert.
In ist /etc/hotplug/usb.pandu Werden Informationen über das USB Gerät abgefragt und daraus etwas gebastelt, das AVM CLASS bzw. DEVCLASS nennt. Daraus wird dann /etc/hotplug/$CLASS gebildet und aufgerufen. Werte für CLASS sind avmusbwlan, hub, storage, printer, printstor, aura. aura ist nicht eine Eigenschaft des Geräts, sondern bedeutet, dass der AVM USB Fernzugriff aktiv ist.
Aber der Kernel könnte, wenn er die Gerätedatei selbst anlegt (oder wenigstens die MINOR selbst festlegt), beim Aufruf des Scripts einfach MINOR als Parameter mit übergeben. So wie er derzeit ja auch die USB VID und PID beim Aufruf als Parameter übergibt. Und schon wäre das Problem gelöst.
Der Kernel übergibt alle nötigen Informationen. Der erste erkannte Drucker bekommt die Nummer 0 und kann über ein Gerät mit Minor Nummer 0 angesprochen werden. Man kann auch Gerätedateien /dev/usblp0 bis /dev/usblp15 anlegen, bevor überhaupt ein Drucker erkannt wird, das ist kein Problem und war vor Hotplug auch so üblich. Die Information, die man zusätzlich braucht, ist, um welchen Drucker es sich handelt.
Das ist immer so! Das Gerät unter /proc/bus/usb/001/ existiert dann schon nicht mehr und daher gibt lsusb einen Error zurück, was in der weiteren Auswertung eine 0 ergibt. Ein Vorteil dabei ist, dass meine Script-Anpassung mit "sleep 0" beim remove nicht wartet.
Bei remove bräuchtest Du überhaupt kein sleep. Ein weiterer Effekt, den ich nicht Vorteil nennen würde ist, dass das Skript versucht, die Gerätedatei $DEV_PREFIX-$UNUM* bei remove zu löschen. Da UNUM aber 0 ist und nicht die Nummer, undter der das Gerät angelegt wurde, funktioniert das nicht. Beim Erkennen des nächsten Druckers ist die Gerätedatei immer noch vorhanden, und das Skript vermutet, dass die dazugehörige Minor Nummer auch belegt ist. Ein weiterer Effekt ist, dass der dazugehörige printserv Prozess nicht gefunden wird und somit das kill nicht funktioniert, ebenso der Update von /var/log/printer_id. Kannst Du das mal überprüfen?
Das ist ein Speedport W920V von der Telekom. Er entspricht technisch weitgehend der Fritzbox 7570.
Die 7570 soll wieder ähnlich zur 7270 sein, deren USB recht gut ist.

Ich vermute mal, das eine ist ein PCL-Interface und das andere ein PS-Interface. Jeder modernere HP-Drucker taucht ja auch unter Windows als zwei unterschiedliche Drucker auf, nämlich als ein PCL- und ein PS-Drucker. Ich habe auch noch einen HP Multifunktionsdrucker mit Scanner und SD-Kartenslot hier stehen. Den habe ich noch nie an die Fritzbox gehängt, weil es ein Netzwerkdrucker ist und er direkt im LAN hängt. Vermutlich dürfte das dann aber ähnlich aussehen.
Ich habe auch einen Netzwerkdrucker, der PCL und PS kann, und der hat auch nur ein Interface. Ob PCL oder PS kommt, erkennt der Drucker an den Daten.

Warum? Müsste das zweite Gerät dann nicht als dritter Drucker unter usblp2 installiert werden?
Langsam kriege ich fast Lust, mal meinen HP dranzustöpseln, um zu sehen was passiert. ;-)
Genau das würde passieren, das zweite Geräte wäre als usblp2 ansprechbar. Das Skript würde aber versuchen, die Minor Nummer 1 anzusprechen, weil dies die nächste freie Nummer ist. Die Ausgabe würde also auf usblp1 landen, dem zweiten Interface am ersten Drucker. Es sei denn, das Skript wird für jedes Interface und nicht für jedes Gerät aufgerufen. Wenn Du schon die schönen Debug Ausgaben im Skript hast, dann stecke doch mal den Drucker an.

Das ist ja aus dem kernel logfile. Damit könnte man dann eigentlich auf sehr einfache Weise die Nodes zuverlässig bestimmen (nachdem usblp gestartet wurde). Oder man überrredet usblp irgendwie dazu, einige informative Ausgaben irgendwo hinzuschreiben. Oder man passt das Modul etwas an. Wie ist es mit diesem Code hier?
Ja, das ist aus dem Kernel Logfile. Zunächst einmal ist das Lesen aus dem Logfile für solche Zwecke sehr unschön. Konkret gibt es das Problem, dass bei AVM das Kernel Log normalerweise deaktiviert ist. Wenn man es doch aktiviert, gibt es andere Probleme mit der Box.
Oder wie wäre es einfach mit
Code:
                # Device node
                modprobe $MODULE
                MINOR=$(dmesg | grep ": usblp[[:digit:]]: USB " | sed -n "s/^.*: usblp\([0-9]\).* printer dev $UNUM if .*$/\1/p")
                USB_DEVICE=$DEV_PREFIX-$UNUM.$MINOR
Das holt auf ganz einfache und schnelle Weise die von usblp an den Drucker mit der Device-ID $UNUM zugewiesene Node-ID aus dem Kernel-Logfile und erzeugt daraus die Gerätedatei. Funktioniert bei mir absolut zuverlässig. Ohne jedes sleep. Die "Ratestunde" unter "# Get next USB minor number..." kann dann völlig entfallen. Das ist im Grunde genau das, was Oliver vorgeschlagen hatte. Das löst auch das Problem mit mehreren virtuellen Druckern mit der selben Device-ID, weil es das erste Interface des ersten physikalischen Druckers mit Node 0 und den zweiten Drucker dann mit Node 2 installieren wird.
Bei mir kommt mit den Logeinträgen von Oliver für MINOR 0 und 1, das gibt spätestens Probleme bei mknod. Und auch bei Druckern mit nur einem Interface kann es Probleme geben, wenn der Drucker getrennt und wieder verbunden wird, dann gibt es nämlich mehrere Einträge für den gleichen Drucker.
 
Zuletzt bearbeitet:
Das remove im Script entfernt auch das Modul usblp beim letzten Drucker, was bedeutet, dass das Modul beim Erkennen des nächsten Druckers wieder neu geladen wird, was bedeutet, dass die Minor Nummern wieder frisch vergeben werden.
Ja, aber mir ging es ja nicht darum, die USB-Ports neu zu erkennen und Nodes zuzuordnen. Mir ging es nur darum, den Printserver zu testen und zu schauen, wie er auf die Beendigung und den Neustart mit einem anderen, zugewiesenen Drucker bzw. Port reagiert. Das Script habe ich gar nicht benutzt, sondern nur das Killen und Neustarten des printserv Prozesses.

Das Ganze ist seltsam, aber von AVM vorgegeben. Es kommt etwas auf die Firmware an, aber bei meiner ist der Weg ungefähr so: [..]
Es klingt wirklich mächtig kompliziert und verworren, was da im Router beim Anstöpseln von USB-Geräten passiert. Ein Wunder, dass überhaupt was funktioniert. Mir war z.B. auch aufgefallen, dass der Router beim Abziehen und neu Anstöpseln meines USB Memory Sticks den NAS-Dienst nicht mehr startet. Das funktioniert nur, wenn der Router neu gestartet wird, während der Memory-Stick drinsteckt. Ansonsten gibt es in der Boxoberfläche die Meldung:

Code:
07.03.14	01:03:26	Der USB-Speicher 1121 enthält kein unterstütztes Dateisystem oder hat eine ungültige Partitionstabelle. (Das Gerät hat den folgenden Typ: 8564:1000)
07.03.14	01:03:26	Der USB-Speicher uStor01 (/dev/sda1) enthält kein unterstütztes Dateisystem oder hat eine ungültige Partitionstabelle. (Das Gerät hat den folgenden Typ: vfat)

Das Logfile sagt folgendes:

Code:
usb 1-1.2: new high speed USB device using musb_hdrc and address 121
usb 1-1.2: configuration #1 chosen from 1 choice
[25645163]maxrun: 1
SCSI subsystem initialized
Initializing USB Mass Storage driver...
scsi0 : SCSI emulation for USB Mass Storage devices
usbcore: registered new interface driver usb-storage
USB Mass Storage support registered.
usb-storage: device found at 121
usb-storage: waiting for device to settle before scanning
scsi 0:0:0:0: Direct-Access     JetFlash Transcend 8GB    1100 PQ: 0 ANSI: 4
SCSI device sda: 15814656 512-byte hdwr sectors (8097 MB)
sda: Write Protect is off
sda: Mode Sense: 43 00 00 00
sda: assuming drive cache: write through
SCSI device sda: 15814656 512-byte hdwr sectors (8097 MB)
sda: Write Protect is off
sda: Mode Sense: 43 00 00 00
sda: assuming drive cache: write through
 sda: sda1
sd 0:0:0:0: Attached scsi removable disk sda
usb-storage: device scan complete

Danach sieht eigentlich alles okay aus. Trotzdem wird das Gerät nicht unter /dev/sda1 gemountet. Kein Wunder bei dem Heckmeck, das der Router da veranstaltet. Ein Checkdisk auf anderen Rechnern ergibt keinerlei Fehler am FAT32 Dateisystem. Das alles festigt immer mehr meinen anfänglichen Eindruck, dass bei AVM zum Teil ziemlich überforderte (oder unterbezahlte?) Freizeit-Programmierer tätig sind.

Aber der Kernel könnte, wenn er die Gerätedatei selbst anlegt (oder wenigstens die MINOR selbst festlegt), beim Aufruf des Scripts einfach MINOR als Parameter mit übergeben. So wie er derzeit ja auch die USB VID und PID beim Aufruf als Parameter übergibt. Und schon wäre das Problem gelöst.
Der Kernel übergibt alle nötigen Informationen. Der erste erkannte Drucker bekommt die Nummer 0 und kann über ein Gerät mit Minor Nummer 0 angesprochen werden.
Alle nötigen Informationen? Eine nötige Information wäre auf jeden Fall - wie wir ja nun wissen - die Node-Number. Und genau diese wichtige Information übergibt der Kernel leider nicht! Bzw. das Script, das letztlich das printer-Script aufruft. Sonst hätten wir den Ärger ja nicht. Denn wir wissen eben nicht, welchen Drucker der Kernel als ersten erkannt und welchem er folglich die Nummer 0 zugeteilt hat.

Die Information, die man zusätzlich braucht, ist, um welchen Drucker es sich handelt.
Die Information bekommen wir ja übergeben! Als dritten und vierten Parameter übergibt der Kernel an das Printer-Script die zum Drucker zugehörige VID und PID, womit er eindeutig identifiziert ist. Es sei denn, man hat mehrere identische Drucker dran hängen, was aber wohl kaum vorkommt. Was fehlt, ist die Übergabe der Node-Number, sonst müssten wir ja nicht "raten".

Bei remove bräuchtest Du überhaupt kein sleep. Ein weiterer Effekt, den ich nicht Vorteil nennen würde ist, dass das Skript versucht, die Gerätedatei $DEV_PREFIX-$UNUM* bei remove zu löschen. Da UNUM aber 0 ist und nicht die Nummer, undter der das Gerät angelegt wurde, funktioniert das nicht. Beim Erkennen des nächsten Druckers ist die Gerätedatei immer noch vorhanden, und das Skript vermutet, dass die dazugehörige Minor Nummer auch belegt ist. Ein weiterer Effekt ist, dass der dazugehörige printserv Prozess nicht gefunden wird und somit das kill nicht funktioniert, ebenso der Update von /var/log/printer_id. Kannst Du das mal überprüfen?
"sleep 0" beim remove ist ja "kein sleep". ;-) Ich glaube, da hast du jetzt was durcheinander bekommen. UPRT ist auf 0, UNUM jedoch nicht. UNUM holt sich das Script auch beim remove aus dem zweiten Parameter ($2). Und daher wird auch die richtige Gerätedatei gelöscht. Das remove funktioniert schon korrekt.

Ich habe auch einen Netzwerkdrucker, der PCL und PS kann, und der hat auch nur ein Interface. Ob PCL oder PS kommt, erkennt der Drucker an den Daten. Wenn Du schon die schönen Debug Ausgaben im Skript hast, dann stecke doch mal den Drucker an.
Ich werde das mal mit meinem HP checken. Es ist ein "HP Color LaserJet CM1312nfi MFP". Ich werde das testen und dann berichten, ob das Script nur einmal oder zweimal für beide Interfaces aufgerufen wird (sofern mein Drucker auch zwei Interfaces hat).

Ja, das ist aus dem Kernel Logfile. Zunächst einmal ist das Lesen aus dem Logfile für solche Zwecke sehr unschön. Konkret gibt es das Problem, dass bei AVM das Kernel Log normalerweise deaktiviert ist. Wenn man es doch aktiviert, gibt es andere Probleme mit der Box.
syslogd ist deaktiviert, das ist es bei mir auch. Aber es gibt ja einen internen Ringpuffer für das kernel log, den man m.W. nicht abschalten kann und der über dmesg stets ausgelesen werden kann. Und in diesen schreibt usblp zuverlässige Debug-Informationen rein. Wenn man sich die Quelle usblp.c mal anschaut, findet man den Teil auch, wo die Minor-Number ins Logfile geschrieben wird. Solange usblp da nicht verändert wird, sollte diese Lösung mit grep und sed zuverlässig funktionieren. Jedenfalls zuverlässiger, als die jetzige Lösung!

Bei mir kommt mit den Logeinträgen von Oliver für MINOR 0 und 1, das gibt spätestens Probleme bei mknod. Und auch bei Druckern mit nur einem Interface kann es Probleme geben, wenn der Drucker getrennt und wieder verbunden wird, dann gibt es nämlich mehrere Einträge für den gleichen Drucker.
Das ist richtig, derzeit kommt da "0<space>1<lf>" raus. Weil das Gerät zweimal mit der gleichen Device-ID auftaucht und sich nur im Interface (1 bzw. 3) unterscheidet. Man müsste also auch noch die if-Nummer überprüfen oder nur das erste Zeichen des Ergebnisses benutzen. Probleme wird es weniger bei mknod geben, als vielmehr beim Aufruf des Printservers, der für beide Nodes auf dem selben TCP-Port horchen müsste. Da wird es das Problem geben, weil der Port schon belegt ist. Das Script wird den Printserver für Node 180,1 daher gar nicht starten. Ich denke nicht, dass es ohne ganz erheblichen Aufwand möglich wäre, beide Interfaces eines Druckers auf fortlaufenden TCP-Ports ansprechbar zu machen. Das würde eine ganz andere Logik erfordern. Aber das erste Interface verfügbar zu machen, wäre kein Problem. Ändere meinen Vorschlag um in:

Code:
                # Device node
                modprobe $MODULE
                UNUMD=$(($(echo $UNUM | sed 's/^0*//')))
                MINOR=$(dmesg | grep ": usblp[[:digit:]]: USB " | sed -n "s/^.*: usblp\([0-9]\).* printer dev $UNUMD if .*$/\1/p")
                MINOR=${MINOR:0:1}
                USB_DEVICE=$DEV_PREFIX-$UNUM.$MINOR

und schon wird es auch mit Olivers Drucker funktionieren (allerdings nur mit dem ersten von usblp erkannten und zugewiesenen Interface). Außerdem musste noch die Zeile "UNUMD=" eingefügt werden, weil UNUM führende Nullen hat und diese entfernt werden müssen, da die Device-ID in der Ausgabe von usblp keine Nullen vorne hat.

Wenn der Drucker getrennt und wieder verbunden wird, gibt es bei meiner Lösung kein Problem, da der Drucker jedes mal mit einer neuen, fortlaufenden Device-ID gestartet wird und diese in meinem Script über UNUM gegengeprüft wird. Probleme gäbe es nur dann, wenn alle 128 IDs einmal durch sind und es wieder von vorne los geht. Aber ich glaube kaum, dass irgendjemand es schaffen wird, während der Lebenszeit des Kernel-Ringpuffers 128 verschiedene Printer-Device-IDs zu erzeugen!

----------------

Ergänzung: Mein HP-Drucker hat auch nur ein Interface, allerdings hat es die ID if=1 und nicht if=0. Sonst ist er aber genauso wie die anderen Drucker:

Code:
drivers/usb/class/usblp.c: usblp2: USB Bidirectional printer dev 122 if 1 alt 0 proto 2 vid 0x03F0 pid 0x4F17

Daher kann ich leider nicht feststellen, ob das Printer-Script bei einem Drucker mit mehreren Interfaces einmal oder zweimal aufgerufen wird. Der PID nach zu urteilen, hat Oliver einen HP OfficeJet Pro 8600. Im folgenden Beitrag gehts um genau dieses Problem und darum, dass es mit dem Drucker Schwierigkeiten gibt, weil er doppelt auftaucht. In Antwort #5 ist die Beschreibung der Interfaces und dort wird auch gesagt, dass die zwei Interfaces das dort genannte Problem verursachen:

https://answers.launchpad.net/hplip/+question/218871:
I found now the source of the problem, I added the output of lsusb -v at the end of this message. Since 4 Interface Descriptors are listed, two of them are printers! The only difference I can see is that bEndpointAddress is 8/9 resp. 10/11 ... but no idea what that mean. I allready debuged the musb.c part and found that this is really the problem.

Ich gehe mal davon aus, dass das ein sehr exotisches Problem ist, das nur sehr selten vorkommt und wohl auch nur bei diesem Drucker. Deshalb glaube ich nicht, dass wir uns darum besonders kümmern müssen. Es reicht, wenn kein Fehler deshalb auftritt und das erste Interface (if 1) ansprechbar ist. Es würde mich allerdings interessieren, ob Olivers Drucker mit meiner Modifikation über die Fritzbox ansprechbar ist und ob auch ein zweiter Drucker, der auf einem höheren USB-Port hängt, ebenfalls ansprechbar wäre...
 
Zuletzt bearbeitet:
Ja, aber mir ging es ja nicht darum, die USB-Ports neu zu erkennen und Nodes zuzuordnen. Mir ging es nur darum, den Printserver zu testen und zu schauen, wie er auf die Beendigung und den Neustart mit einem anderen, zugewiesenen Drucker bzw. Port reagiert. Das Script habe ich gar nicht benutzt, sondern nur das Killen und Neustarten des printserv Prozesses.
Solange usblp nicht neu geladen wird, bleibt die Zuordnung der Nummern gleich.

Es klingt wirklich mächtig kompliziert und verworren, was da im Router beim Anstöpseln von USB-Geräten passiert. Mir war z.B. auch aufgefallen, dass der Router beim Abziehen und neu Anstöpseln meines USB Memory Sticks den NAS-Dienst nicht mehr startet.

Danach sieht eigentlich alles okay aus. Trotzdem wird das Gerät nicht unter /dev/sda1 gemountet. Kein Wunder bei dem Heckmeck, das der Router da veranstaltet. Ein Checkdisk auf anderen Rechnern ergibt keinerlei Fehler am FAT32 Dateisystem. Das alles festigt immer mehr meinen anfänglichen Eindruck, dass bei AVM zum Teil ziemlich überforderte (oder unterbezahlte?) Freizeit-Programmierer tätig sind.
Der Teil vom Log sieht gut aus. Um das zu testen bräuchte man den Verlauf vom Skript /etc/hotplug/storage. Meine Vermutung ist, dass es damit zu tun hat, dass beim Abnehmen des Sticks alle Module entladen werden und später wieder neu geladen werden müssen, und dass es dabei ein Timing Problem gibt.

Das Skript ist sicher nicht von Freizeit-Programmierern. Diese würden so etwas nämlich nicht verbreiten, sondern eine funktionierende und stabile Lösung suchen. Deswegen würden die Freizeit-Programmierer auch kein grep auf dmesg machen.

Alle nötigen Informationen? Eine nötige Information wäre auf jeden Fall - wie wir ja nun wissen - die Node-Number. Und genau diese wichtige Information übergibt der Kernel leider nicht! Bzw. das Script, das letztlich das printer-Script aufruft. Sonst hätten wir den Ärger ja nicht. Denn wir wissen eben nicht, welchen Drucker der Kernel als ersten erkannt und welchem er folglich die Nummer 0 zugeteilt hat.
Ja, alle nötigen Informationen. Das Problem ist, dass wir nicht wissen, wem der Kernel die Nummer 0 zuteilen wird, nicht hat. Natürlich übergibt der Kernel die Informationen nicht, bevor sie überhaupt vorhanden sind.
Die Information bekommen wir ja übergeben! Als dritten und vierten Parameter übergibt der Kernel an das Printer-Script die zum Drucker zugehörige VID und PID, womit er eindeutig identifiziert ist. Es sei denn, man hat mehrere identische Drucker dran hängen, was aber wohl kaum vorkommt. Was fehlt, ist die Übergabe der Node-Number, sonst müssten wir ja nicht "raten".
Der Kernel kann an dieser Stelle keine Node Nummer übergeben, weil sie da noch nicht vergeben wurde.

syslogd ist deaktiviert, das ist es bei mir auch. Aber es gibt ja einen internen Ringpuffer für das kernel log, den man m.W. nicht abschalten kann und der über dmesg stets ausgelesen werden kann.
Du solltest AVM niemals "unterschätzen". Bei mir ist die letzte Zeile in dmesg:
Code:
[ubik2_debug]redirect kernel-messages (/dev/debug)
Und das ist lange bevor ich einen Drucker angesteckt habe, danach kommt nichts mehr.
 
Solange usblp nicht neu geladen wird, bleibt die Zuordnung der Nummern gleich.
Das war in dem Fall auch okay. Ich wollte ja nur die Zuordnung zwischen Drucker und TCP-Port mal testhalber ändern.

Der Teil vom Log sieht gut aus. Um das zu testen bräuchte man den Verlauf vom Skript /etc/hotplug/storage. Meine Vermutung ist, dass es damit zu tun hat, dass beim Abnehmen des Sticks alle Module entladen werden und später wieder neu geladen werden müssen, und dass es dabei ein Timing Problem gibt.
Das mag sein, aber jetzt noch eine zweite Baustelle mit dem storage-script aufzureißen, habe ich keine Lust. Vielleicht später mal.

Ja, alle nötigen Informationen. Das Problem ist, dass wir nicht wissen, wem der Kernel die Nummer 0 zuteilen wird, nicht hat.
Weshalb es ja auch schön wäre, wenn usblp diese Information an brauchbarer und zuverlässiger Stelle mal hinterlegen würde, was es aber wohl nicht tut. Oder ist dir eine solche Stelle bekannt? Ich habe jetzt nur mäßig lust, deshalb die Quelle auseinanderzunehmen. Es geht doch schon in den Bereich der Absurdität, dass eine so wichtige Information, wie die Zuordnung einer Node zu einem USB-Device nicht irgendwo hinterlegt wird, sondern nur in ein Logfile geschrieben wird.

Du solltest AVM niemals "unterschätzen". Bei mir ist die letzte Zeile in dmesg: [..] Und das ist lange bevor ich einen Drucker angesteckt habe, danach kommt nichts mehr.
Hmm, ich war davon ausgegangen, dass bei allen Freetz-Images der Kernel-Ringpuffer immer vorhanden ist und da auch immer die Kernel Messages reingeschrieben werden. Das ist ja alles grausam hoch zehn! Ich denke langsam, dass du Recht mit der Vermutung hast, dass AVM die Quellen deshalb rechtswidrig unter Verschluss hält, weil sie Angst haben, sich durch eine Veröffentlichung vollends zu blamieren. Ich denke nur an die gruselige Geschichte mit dem Sicherheitsloch vor einigen Wochen. Dadurch war ich überhaupt erst wieder auf die Idee gekommen, ein neues Image zu bauen. Sonst wär ich jetzt sicher gar nicht hier. Und zuerst haben sie auch noch abgestritten, dass das Problem an der Firmware liegen würde, sondern es auf den Diebstahl von Kennwörtern geschoben. Erst als sie überführt wurden, gaben sie es zu. Dadurch wurde wertvolle Zeit verloren, weil viele User sich fälschlicherweise in Sicherheit wähnten. Sie haben damit auf übelste Weise gegen ihre Schadensminderungspflicht verstoßen, nur um öffentlich nicht schlecht dazustehen. Dass sie damit am Ende ihren Ruf erst so richtig ruiniert haben, darüber haben sie wohl am Anfang nicht nachgedacht. Der "zu-Guttenberg-Effekt".
 
Zuletzt bearbeitet:
Weshalb es ja auch schön wäre, wenn usblp diese Information an brauchbarer und zuverlässiger Stelle mal hinterlegen würde, was es aber wohl nicht tut.
Natürlich hinterlegt usblp Information an brauchbarer und zuverlässiger Stelle. Es tut das nur nicht, bevor es geladen wird.
Es geht doch schon in den Bereich der Absurdität, dass eine so wichtige Information, wie die Zuordnung einer Node zu einem USB-Device nicht irgendwo hinterlegt wird, sondern nur in ein Logfile geschrieben wird.
Deswegen würden die Freizeit-Programmierer von Linux das auch nicht nur ins Log schreiben, und die Freizeit-Programmierer von Freetz würden die Informationen nicht aus dem Log lesen.
Hmm, ich war davon ausgegangen, dass bei allen Freetz-Images der Kernel-Ringpuffer immer vorhanden ist und da auch immer die Kernel Messages reingeschrieben werden.

Der Kernel-Ringpuffer ist immer vorhanden, ob mit Freetz oder ohne. AVM hat nur etwas eingebaut, damit die Kernel Meldungen gar nicht erst dorthin kommen. Man kann das wieder aktivieren, aber es gibt dann zum Teil Probleme mit anderen Funktionen der Firmware. Ich weiß jetzt aber die Einzelheiten nicht und habe keine Lust nachzusehen.

Ich habe mal folgendes nach /etc/hotplug/usb.pandu kopiert
Code:
#! /bin/sh                                                                                                                                                                                                                       

CONSOLE=/dev/console

case "$MODALIAS" in
    usb:*ic07isc01ip01|usb:*ic07isc01ip02)
        MODULE=usblp
        case $ACTION in
            add)
                if [ ! -d /sys/bus/usb/drivers/usblp ]; then
                    modprobe $MODULE
                fi
                ;;
            remove)
                if (set -- /sys/class/usb/lp*; test ! -d $1); then
                    rmmod $MODULE
                fi
                ;;
        esac
        exit 0
        ;;
esac

if [ "$PHYSDEVDRIVER" = usblp ]; then
    BIN=/sbin/printserv
    # DEVNAME                                                                                                                                                                                                                    
    DEVNAME=/dev/usb/lp$MINOR
    # USBPORT                                                                                                                                                                                                                    
    USBPORT=${PHYSDEVPATH##*/}
    USBPORT=${USBPORT%:*}
    USBPORT=${USBPORT#*.}
    # TCPPORT                                                                                                                                                                                                                    
    TCPPORT=$((9100 + 2 * USBPORT))
    case $ACTION in
        add)
            mkdir -p ${DEVNAME%/*}
            rm -f $DEVNAME
            mknod -m 600 $DEVNAME c $MAJOR $MINOR
            if ! $BIN -d $DEVNAME -p $TCPPORT -c $CONSOLE; then
                eventadd 153
            fi
            eventadd 150 $TCPPORT
            ;;
        remove)
            PIDS=$(ps w | sed -n "s,^ *\([0-9]*\).*[[:blank:]]$BIN.*$DEVNAME.*$,\1,p")
            [ -n "$PIDS" ] && kill -KILL $PIDS
            rm -f $DEVNAME
            ;;
    esac
    exit 0
fi
Damit funktioniert zwar kein usbstorage oder aura mehr, aber damit wird bei mir zuverlässig der Drucker erkannt. Du kannst es auch einmal mit zwei Druckern ausprobieren. Das Skript entfernt sogar das usblp Modul, nachdem es nicht mehr benötigt wird, obwohl das meiner Meinung nach nicht so wichtig ist. Das Modul selbst in ca. 10kB groß, und braucht vermutlich noch einige kB zusätzlich. Aber wenn die Box läuft, solange der Drucker angeschlossen ist, sollte sie auch nachher noch mit geladenem Modul weiter laufen können.

Zu Skript selbst:
Der obere Teil lädt das Modul usblp, wenn es noch nicht vorhanden ist, und entfernt es, wenn der letzte Drucker entfernt wurde.
Der untere Teil legt die Gerätedatei an und startet den Server, bzw. stoppt den Server und entfernt die Gerätedatei. Der Kernel liefert alle Informationen, um den Gerätenamen, die Gerätenummern, den USB Port und daraus den TCP Port zu bestimmen. Kein Raten, kein Suchen mit externen Programmen wie lsusb, einfach nur die vorhandenen Informationen auswerten. Sogar die automatische Zuordnung von TCP Port zu USB Port ist vorhanden, vermutlich mit dem gleichen Problem, falls es mehr als einen Hub gibt. Außerdem würde es mit einem Drucker wie dem von Oliver dazu führen, dass printserv zweimal mit dem gleichen TCP Port gestartet wird, weil beide Interfaces am gleichen USB Port hängen. Letztlich wäre vermutlich der erste Aufruf erfolgreich und der zweite würde den TCP Port belegt vorfinden und sich beenden. Sofern das erste Interface zum Drucken geeignet ist, könnte man damit drucken. Kurz gesagt, die Einschränkungen sind die gleichen wie beim jetzigen Skript, aber die Unsicherheit mit der Druckerzuordnung fällt weg.

Eleganter, aber etwas mehr Arbeit wäre es, in einer Datei eine Zuordnung von USB Interfaces zu Ports zu hinterlegen, aber das ist wohl für die meisten Fälle nicht notwendig.
 
Natürlich hinterlegt usblp Information an brauchbarer und zuverlässiger Stelle. Es tut das nur nicht, bevor es geladen wird.
Das hat ja auch niemand verlangt. Man kann ja auch zuerst usblp laden und dann den Rest des printer-scripts ausführen, wie in meinem letzten Vorschlag. Ich verstehe aber nicht, warum du das komplette usb.pandu Skript austauschst, um das Problem zu lösen!? Wenn du weißt, an welcher "zuverlässigen" Stelle usblp die nötige Information hinterlegt, warum holst du sie nicht im printer-skript von dort?

Damit funktioniert zwar kein usbstorage oder aura mehr, aber damit wird bei mir zuverlässig der Drucker erkannt.
Auf USB-Storage zu verzichten, um die Drucker zuverlässig zu erkennen, ist definitiv ein zu hoher Preis! Kann man dein Skript nicht in das vorhandene usb.pandu integrieren, so dass es keine Verluste gibt?

Der Kernel liefert alle Informationen, um den Gerätenamen, die Gerätenummern, den USB Port und daraus den TCP Port zu bestimmen. Kein Raten, kein Suchen mit externen Programmen wie lsusb, einfach nur die vorhandenen Informationen auswerten.
Und wieso funktioniert das nur in usb.pandu und nicht später im printer-skript?
 
Das hat ja auch niemand verlangt. Man kann ja auch zuerst usblp laden und dann den Rest des printer-scripts ausführen, wie in meinem letzten Vorschlag. Ich verstehe aber nicht, warum du das komplette usb.pandu Skript austauschst, um das Problem zu lösen!? Wenn du weißt, an welcher "zuverlässigen" Stelle usblp die nötige Information hinterlegt, warum holst du sie nicht im printer-skript von dort?
Weil das Skript zu früh aufgerufen wird, bevor usblp geladen wird und die Informationen vorhanden sind. Da nützt es nichts zu wissen, wo die Informationen später irgendwann mal sein werden.
Auf USB-Storage zu verzichten, um die Drucker zuverlässig zu erkennen, ist definitiv ein zu hoher Preis! Kann man dein Skript nicht in das vorhandene usb.pandu integrieren, so dass es keine Verluste gibt?
Natürlich kann man das, aber das ist mehr Arbeit und dann ist der grundlegende Ablauf nicht mehr so einfach erkennbar. Ich habe auch das Modifizieren von /var/log/printer_id weggelassen, weil es nichts mit der Fragestellung richtige Minor Nummer zu tun hat.
Und wieso funktioniert das nur in usb.pandu und nicht später im printer-skript?
Weil usb.pandu das printer Skript nicht aufruft, wenn das Modul usblp einen Drucker erkennt.

Du kannst diese Zeilen am Anfang von usb.pandu einbauen:
Code:
if [ "$PHYSDEVDRIVER" = usblp ]; then
   exec /etc/hotplug/printer
fi
Dann sollte es auch funktionieren, wenn man das Skript von oben als /etc/hotplug/printer speichert, inkl. Aura und Storage.
 
Weil das Skript zu früh aufgerufen wird, bevor usblp geladen wird und die Informationen vorhanden sind. Da nützt es nichts zu wissen, wo die Informationen später irgendwann mal sein werden.
Aber usblp wird doch im printer-skript geladen!? Wenn man dies ganz am Anfang macht, hat man danach doch alle Zeit der Welt, um die erzeugten Informationen auszulesen und zu verarbeiten. Schließlich mache ich es in meinem letzten Vorschlag ja auch so, dass ich zuerst usblp lade und danach die von usblp ins Kernel-Logfile geschriebenen Informationen auswerte. Also ist es kein Problem, erst usblp zu starten und dann auf der Basis der von usblp erzeugten Informationen weiterzumachen.

Code:
if [ "$PHYSDEVDRIVER" = usblp ]; then
   exec /etc/hotplug/printer
fi
Dann sollte es auch funktionieren, wenn man das Skript von oben als /etc/hotplug/printer speichert, inkl. Aura und Storage.

Das gefällt mir schon besser. :) Wo kommen eigentlich ACTION, MODALIAS und PHYSDEVDRIVER her? Wer setzt die im Environment?
 
Zuletzt bearbeitet:
Natürlich kann man auch das Modul laden, dann warten, bis man meint, dass es alle Drucker erkannt haben sollte, und dann die Informationen auswerten. Man kann aber auch den Kernel die Erkennung durchführen lassen, und der Kernel ruft dann das Skript mit den passenden Werten auf. Nur weil AVM hier an den falschen Stellen angesetzt hat, muss man das nicht so beibehalten.

Die Werte im Environment übergibt der Kernel.

Wenn Du in der jetzigen Systematik bleiben willst, musst Du zusätzlich selbst herausfinden, welche Drucker neu dazu gekommen sind. Das lässt sich sicher auch feststellen, wenn man es darauf anlegt, ist aber weitaus mühsamer.
 
Natürlich kann man auch das Modul laden, dann warten, bis man meint, dass es alle Drucker erkannt haben sollte, und dann die Informationen auswerten.
Ich hatte zwischen dem Laden von usblp und dem Auslesen des Logfiles zuerst auch ein sleep von einer Sekunde gesetzt, dann aber festgestellt, dass dies überflüssig ist. Auch ohne sleep funktioniert es zuverlässig. Das heißt, dass das Skript offenbar so lange gestoppt wird, bis das Laden von usblp vollständig abgeschlossen ist (inklusive Druckererkennung).

Man kann aber auch den Kernel die Erkennung durchführen lassen, und der Kernel ruft dann das Skript mit den passenden Werten auf. Nur weil AVM hier an den falschen Stellen angesetzt hat, muss man das nicht so beibehalten.
Sicher. Übrigens hat die Telekom jetzt die kompletten Kernel-Sourcen des Speedports veröffentlicht. Nur weil du sagtest, dass AVM da so zurückhaltend sei. Diese Sourcen sind nahezu vollständig identisch mit den AVM-Sourcen für die Fritzbox 7570. Falls es jemanden interessiert: http://hilfe.telekom.de/dlp/eki/downloads/Speedport/Speedport%20W%20920V/GPL-Speedport_W_920V.tar.gz
 
Zuletzt bearbeitet:
Es gibt übrigens auch noch andere Dinge, die mich erheblich zweifeln lassen, ob diese ganze Druckergeschichte überhaupt richtig funktionsfähig ist.

Folgende Geschichte habe ich in der letzten Woche nun schon dreimal(!) gehabt:
Ich druckte zuerst auf dem BJC-3000 an TCP-Port 9106 und dann wollte ich auf Port 9104 auf den USB-Parallel-Adapter drucken. Der erste Auftrag lief prima, der zweite blieb im Spooler hängen. Dann druckte ich nochmal auf Port 9106 und auch dieser Auftrag blieb dann hängen. Im Logfile war folgendes:

Code:
drivers/usb/class/usblp.c: usblp0: error -150 writing to printer
drivers/usb/class/usblp.c: usblp1: error -150 writing to printer
drivers/usb/class/usblp.c: usblp0: error -150 writing to printer
drivers/usb/class/usblp.c: usblp1: error -150 writing to printer
drivers/usb/class/usblp.c: usblp0: error -150 writing to printer
drivers/usb/class/usblp.c: usblp1: error -150 writing to printer
[u.s.w.]

Error -150 ist eine Statusmeldung von usb_submit_urb aus urb.c und heißt nur, dass der Druckauftrag in Arbeit ist:

Code:
[B]usblp.c:[/B]
	err = usb_submit_urb(usblp->writeurb, GFP_KERNEL);
	[..]
	if (!usblp->wcomplete)
		err("usblp%d: error %d writing to printer",
			usblp->minor, usblp->writeurb->status);
	[..]

[B]urb.c:[/B]
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
	[..]
	urb->status = -EINPROGRESS;
	[..]
}

[B]errno.h:[/B]
#define	EINPROGRESS	150	/* Operation now in progress */

Ich habe dann die Printserver-Prozesse für Port 9104 beendet und neu gestartet - erfolglos. Auch nachdem ich den Drucker mit "printer remove" entfernt und mit "add" neu hinzugefügt hatte, funktionierte er nicht. Erst nachdem ich den Drucker vom USB-Port abgestöpselt und neu eingesteckt hatte, ging es wieder. Auch der ausstehende Auftrag auf Port 9106 wurde dann sofort nachträglich gedruckt. Das ist schon äußerst seltsam, zumal das usblp Modul durch diese Maßnahmen nicht entfernt oder neu geladen wurde, denn der Drucker in Port USB3 (9106) war ja nie abgestöpselt.

Ich hatte schon die Vermutung, dass vielleicht der USB-Parallel-Adapter abgestürzt gewesen sein könnte. Deshalb habe ich ihn mal direkt in den Rechner gesteckt, der dauerhaft läuft. Aber da funktioniert er jetzt schon seit fast 3 Tagen ohne Unterbrechung störungsfrei. An der Fritzbox lief er keine 2 Tage einwandfrei. Das deutet darauf hin, dass es nicht am Adapter liegt, sondern irgendwas mit der Druckergeschichte an der Fritzbox faul ist. Ich bin langsam grundsätzlich am zweifeln, dass dieses System für mehrere Drucker dauerhaft geeignet und zuverlässig ist.
 
Zuletzt bearbeitet:
Es gibt dafür mehrere Möglichkeiten. Eine ist, dass printserv nicht für mehrere Drucker geeignet ist und da irgend etwas blockiert. Die andere ist, dass es irgendwo im Kernel ein Problem gibt.
Du kannst versuchen, einen Druckjob vorab zu erstellen, oder bei PCL Druckern auch nur etwas Text gefolgt vom einem Seitenvorschub.
Wenn der Adapter dann wieder hängt, kannst Du versuchen, printserv zu stoppen und dann die Datei direkt an den Drucker zu senden, ohne den Umweg über printserv.
Code:
echo -en 'Test\f' > /dev/usb_prntsvr-XY
cat Testdatei  > /dev/usb_prntsvr-XY
Dann weißt Du, ob das Problem beim Printserv liegt, oder eher Kernel/Hardware.
 
Wenn der Adapter dann wieder hängt, kannst Du versuchen, printserv zu stoppen und dann die Datei direkt an den Drucker zu senden, ohne den Umweg über printserv.
Code:
echo -en 'Test\f' > /dev/usb_prntsvr-XY
cat Testdatei  > /dev/usb_prntsvr-XY
Habe ich gemacht. Das cat bleibt dann hängen und usblp beginnt wieder, den error -150 auszugeben, bis ich das cat mit Strg-C beende. Es liegt also NICHT am printserver! Interessant ist aber, dass ich auf beide Drucker nichts mehr ausgeben kann, auch nicht auf den BJC-3000, der eigentlich gar nicht von der Blockade betroffen war. In beiden Fällen hängt das cat. Stöpsele ich den BJC-3000 aus und wieder an, kann ich auf diesem wieder Drucken. Aber nur so lange, bis ich etwas an den blockierten Drucker sende. Dann hängen wieder beide. Aufheben lässt sich das Proiblem nur, indem ich den blockierten Drucker abstöpsele und wieder einstöpsele. Auch ein remove und add über das printer-skript ist wirkungslos. Erst wenn der Kernel ein neues Device unter /proc/bus/usb/001/ anlegt und man dieses manuell oder über das printer-script added (also Gerätedatei unter /dev anlegen), funktioniert das Drucken wieder.

Aber es gibt auch noch andere, völlig bekloppte Sachen. Z.B. bewirkte das Ab- und Anstöpseln des Druckers mit einmal gar nichts mehr: Das printer-script wurde überhaupt nicht mehr aufgerufen. Und das manuelle killen der vier printserv Prozesse funktionierte nur noch bei drei von vieren. Den vierten Prozess konnte ich so oft zu killen versuchen, wie ich wollte: Wirkungslos, er blieb einfach im Speicher! Und "rmmod usblp" wurde nur quittiert mit "rmmod: can't unload 'usblp': Resource temporarily unavailable". Das ist doch alles ein riesiger Murks mit diesem Drucker-Gedöns!

Ich habe mich jetzt auch nochmal mit dem Storage-Problem auseinandergesetzt (Memory-Stick wird zwar erkannt, aber nicht gemountet). Ich bin so weit gekommen: Das Skript /etc/hotplug/storage führt folgenden Befehl aus:
Code:
/etc/hotplug/run_mount /proc/bus/usb/001/085 sda
Das Skript run_mount gibt dann folgendes aus:
Code:
mount: mounting /dev/sda1 on /var/media/ftp/uStor01 failed: No such device
Das Verzeichnis /var/media/ftp ist folglich leer. Aber warum mountet das Skript ein Device /dev/sda1, das gar nicht da ist? Bzw. warum ist es nicht da?

Im Logfile steht doch nach dem Anstöpseln:

Code:
SCSI device sda: 15814656 512-byte hdwr sectors (8097 MB)
sda: Write Protect is off
sda: Mode Sense: 43 00 00 00
sda: assuming drive cache: write through
 sda: sda1
sd 0:0:0:0: Attached scsi removable disk sda

So weit erstmal...
 
Zuletzt bearbeitet:
Na, Ralf? Du hast vermutlich genauso die Lust an der Sache verloren, wie ich mittlerweile. Wie soll man auch mit einem Betriebssystem arbeiten, in dem sich nichtmal mehr Prozesse killen lassen... :motz:

Ich kauf mir jetzt einen Printserver. Der kostet 18 Euro und gut ist. Nase voll von Fritzbox! :p
 
Zuletzt bearbeitet:

Zurzeit aktive Besucher

Neueste Beiträge

Statistik des Forums

Themen
244,872
Beiträge
2,219,909
Mitglieder
371,594
Neuestes Mitglied
AA-Idealbau
Holen Sie sich 3CX - völlig kostenlos!
Verbinden Sie Ihr Team und Ihre Kunden Telefonie Livechat Videokonferenzen

Gehostet oder selbst-verwaltet. Für bis zu 10 Nutzer dauerhaft kostenlos. Keine Kreditkartendetails erforderlich. Ohne Risiko testen.

3CX
Für diese E-Mail-Adresse besteht bereits ein 3CX-Konto. Sie werden zum Kundenportal weitergeleitet, wo Sie sich anmelden oder Ihr Passwort zurücksetzen können, falls Sie dieses vergessen haben.