Forum: PC-Programmierung In C feststellen, dass Serielle Schnittstelle bereits genutzt wird


von Rene P. (icebair)


Lesenswert?

Hi zusammen,
ich bin gerade dabei erste Schritte mit C für die serielle Schnittstelle 
unter Linux zu machen.

Nun habe ich festgestellt, dass man mein Programm mehrfach starten kann 
und die einzelnen Prozesse dann Fragmente der seriellen Daten erhalten.

Hier mein bisheriger code:
1
int main (int argc, char *argv[])
2
{
3
  char c;
4
  int fd;
5
  
6
  fd=open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
7
  if (fd == -1) {
8
    printf("Error opening port!\n");
9
  } else {
10
    printf("Opened port!\n");
11
    getchar();
12
    close(fd);
13
  }
14
  return 0;
15
}

Wie kann ich dedizierten Zugriff auf eine Serielle Schnittstelle 
realisieren? Gibt es einen Weg generell weitere Zugriffe zu sperren oder 
verlässlich abzufragen ob die Schnittstelle schon benutzt wird?

Gruß
  René

von Kabel (Gast)


Lesenswert?

Habe es nicht getestet, aber lsof zeigt dir die geöffneten Dateien an, 
da müsste /dev/tty... auch dabei sein, oder?

von Kabel (Gast)


Lesenswert?

Korrektur: wenn root die Datei öffnet, taucht sie bei einem 'normalen' 
User in lsof nicht auf.

von Rene P. (icebair)


Lesenswert?

Interessanter Ansatz.
Funktioniert sogar :-)

Ich werde mal schauen ob ich in C direct auf "datei geöffnet" testen 
kann.

Gruß

von Mikel_X (Gast)


Lesenswert?

...wie wär'S mit einem Flag, das bei Beginn einer Übertragung gesetzt 
wird und "belegt" meldet, bis es es nach beenden der Übertragung vom 
aufrufenden Task wieder rückgesetzt wird?

von Norbert (Gast)


Lesenswert?

Hier nun die richtige Antwort:
1
#include <stdio.h>
2
#include <fcntl.h>
3
#include <sys/ioctl.h>
4
#include <sys/file.h>
5
6
int main (int argc, char *argv[])
7
{
8
  char c;
9
  int fd;
10
11
  fd=open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
12
  if (fd == -1) {
13
    printf("Error opening port!\n");
14
  } else {
15
    printf("Opened port!\n");
16
    if (-1 == ioctl(fd, TIOCEXCL))
17
      printf("...exclusive!\n");
18
    getchar();
19
    close(fd);
20
  }
21
  return 0;
22
}

von Rene P. (icebair)


Lesenswert?

Mikel_X schrieb:
> ...wie wär'S mit einem Flag, das bei Beginn einer Übertragung gesetzt
> wird und "belegt" meldet, bis es es nach beenden der Übertragung vom
> aufrufenden Task wieder rückgesetzt wird?

Mehrere Programme verwenden die Schnittstelle. Daher muss ich 
allgemeingültig prüfen können.

Mit lsof kann ich nun sogar testen ob mehrere prozesse die Schnittstelle 
geöffnet haben und ggf. einen Prozess beenden. Da meine Anweundg 
unkritisch ist, ist das für mich die perfekte Quick&Dirty lösung ;)

von Norbert (Gast)


Lesenswert?

1
if (-1 == ioctl(fd, TIOCEXCL))
soll natürlich
1
if (-1 != ioctl(fd, TIOCEXCL))
heissen.

von Rene P. (icebair)


Lesenswert?

@Norbert: Sieht fast schon genau nach dem aus, was ich suche.
Mir fällt nur auf, dass dann erst der Port geöffnet wird und dann die 
Prüfung stattfindet. (Damit könnte ich ja eine vorhandene kommunikation 
stören, oder?).

von Norbert (Gast)


Lesenswert?

Rene P. schrieb:
> @Norbert: Sieht fast schon genau nach dem aus, was ich suche.
> Mir fällt nur auf, dass dann erst der Port geöffnet wird und dann die
> Prüfung stattfindet. (Damit könnte ich ja eine vorhandene kommunikation
> stören, oder?).

Nö, nur öffnen ist rein passiv und stört gar nichts.
Kannst du wunderbar testen, indem du mit einer Applikation eine 
andauernde Datenübertragung machst und die Daten mit zB. md5sum oder 
sha1sum überprüfst. Während diese Übertragung läuft, startest du ein 
zweites Programm, das eine Million mal die Schnittstelle öffnet, ein 
paar 100 µs wartet und wieder schließt.

von Rene P. (icebair)


Lesenswert?

Norbert schrieb:
> Nö, nur öffnen ist rein passiv und stört gar nichts.
> Kannst du wunderbar testen, indem du mit einer Applikation eine
> andauernde Datenübertragung machst und die Daten mit zB. md5sum oder
> sha1sum überprüfst. Während diese Übertragung läuft, startest du ein
> zweites Programm, das eine Million mal die Schnittstelle öffnet, ein
> paar 100 µs wartet und wieder schließt.

Super! Danke für die Erklärung.

Dann habe ich ja genau was ich brauche und wünsche allen hier ein frohes 
Osterfest :-)

von A.H. (Gast)


Lesenswert?

Es steht zwar nicht sooo in der Manpage zu open(2), aber vielleicht 
funktioniert auch ein zusätzliches O_EXCL Flag bei open(2). Schon mal 
probiert?

von Andreas B. (andreas_b77)


Lesenswert?

Traditionell (d.h. andere Programme machen es auch so) werden 
Lock-Dateien verwendet. Das Programm, das etwa auf /dev/ttyS0 zugreifen 
will, erzeugt eine Datei /var/lock/LCK..ttyS0 und schreibt seine PID 
rein.

Wenn das Erzeugen fehlschlägt (weil die Datei existiert und die 
entsprechenden Flags bei open gesetzt wurden), ist das Device gesperrt. 
Man sollte in dem Fall die Lock-Datei noch auslesen und prüfen, ob die 
angegebene PID überheupt noch existiert und gegebenenfalls die veraltete 
Lock-Datei löschen und es neu versuchen. Selber sollte man natürlich 
auch die Lock-Datei zuverlässig am Programmende löschen (etwa via 
atexit() Handler).

von Rolf M. (rmagnus)


Lesenswert?

Andreas B. schrieb:
> Traditionell (d.h. andere Programme machen es auch so) werden
> Lock-Dateien verwendet. Das Programm, das etwa auf /dev/ttyS0 zugreifen
> will, erzeugt eine Datei /var/lock/LCK..ttyS0 und schreibt seine PID
> rein.

Das funktioniert allerdings nur für das eigene Programm, denn es gibt 
kein Standard-Lockfile für ttyS0, das von allen Programmen, die drauf 
zugreifen genutzt wird.

von Andreas B. (andreas_b77)


Lesenswert?

Das Standard-Lockfile für ttyS0 ist /var/lock/LCK..ttyS0 unter Linux und 
dem Filesystem Hierarchy Standard. Früher und unter anderen Unixen ist 
unter Umständen das Verzeichnis anders (etwa /usr/spool/locks), das 
Prinzip ist das gleiche.

Dazu der FHS:

Many programs follow a convention to create a lock file in /var/lock to 
indicate that they are using a particular device or file. This directory 
holds those lock files (for some devices) and hopefully other programs 
will notice the lock file and won't attempt to use the device or file.

Lock files should be stored within the /var/lock directory structure. 
Lock files for devices and other resources shared by multiple 
applications, such as the serial device lock files that were originally 
found in either /usr/spool/locks or /usr/spool/uucp, must now be stored 
in /var/lock. The naming convention which must be used is LCK.. followed 
by the base name of the device file. For example, to lock /dev/ttyS0 the 
file LCK..ttyS0 would be created. The format used for the contents of 
such lock files must be the HDB UUCP lock file format. The HDB format is 
to store the process identifier (PID) as a ten byte ASCII decimal 
number, with a trailing newline. For example, if process 1230 holds a 
lock file, it would contain the eleven characters: space, space, space, 
space, space, space, one, two, three, zero, and newline.

von Rene P. (icebair)


Lesenswert?

Andreas B. schrieb:
> ...and hopefully other programs
> will notice the lock file and won't attempt to use the device or file.

Da würde ich doch sagen: Ich lege ein Lockfile an und schaue trotzdem 
mal nach, ob die Schnittstelle nicht schon geöffnet ist ;-)

von Rolf M. (rmagnus)


Lesenswert?

Andreas B. schrieb:
> and hopefully other programs will notice the lock

Das sagt ja schon genug darüber aus, wie zuverlässig das ist.

von Reinhard Kern (Gast)


Lesenswert?

Hallo,

wenn ich die Diskussion hier lese, verstehe ich nicht, wieso Linux 
Windows so unendlich überlegen sein soll - unter Windows kann Programm B 
eine COM-Schnittstelle einfach nicht öffnen, wenn diese schon von 
Programm A benutzt wird, Basta. Ich weiss, der Glaube machts, da 
schluckt man jede Kröte.

Gruss Reinhard

von Norbert (Gast)


Lesenswert?

Reinhard Kern schrieb:
> Hallo,
>
> wenn ich die Diskussion hier lese, verstehe ich nicht, wieso Linux
> Windows so unendlich überlegen sein soll - unter Windows kann Programm B
> eine COM-Schnittstelle einfach nicht öffnen, wenn diese schon von
> Programm A benutzt wird, Basta. Ich weiss, der Glaube machts, da
> schluckt man jede Kröte.
>
> Gruss Reinhard

Du wirst im Laufe der Diskussion hier festgestellt haben, das es unter 
Linux sehr einfach ist, ein Device exklusiv zu öffnen *WENN MAN SELBST 
ES MÖCHTE* und nicht wenn das OS es befiehlt.

Alles was man tun muß, ist einen Betriebssystembefehl abzusetzen.

Ich habe als Programmierer die volle Kontrolle, wo also ist das Problem 
(wenn man mal Polemik außen vor lässt)?

von Andreas B. (andreas_b77)


Lesenswert?

Rolf Magnus schrieb:
> Andreas B. schrieb:
>> and hopefully other programs will notice the lock
>
> Das sagt ja schon genug darüber aus, wie zuverlässig das ist.

Welche Programme, die auf die seriellen Schnittstellen zugreifen, 
verletzen denn konkret dieses Protokoll?

von Andreas B. (andreas_b77)


Lesenswert?

Norbert schrieb:
> printf("Opened port!\n");
>     if (-1 == ioctl(fd, TIOCEXCL))
>       printf("...exclusive!\n");

Achtung, das hat nicht exakt das gewünschte Ergebnis. Das verhindert, 
dass das Device in Zukunft von Prozessen, die nicht als root laufen, 
geöffnet werden kann. Damit merkt man nicht, ob das Device bereits von 
anderen Prozessen geöffnet wurde und benutzt wird.

von Norbert (Gast)


Lesenswert?

Andreas B. schrieb:

> Achtung, das hat nicht exakt das gewünschte Ergebnis. Das verhindert,
> dass das Device in Zukunft von Prozessen, die nicht als root laufen,
> geöffnet werden kann. Damit merkt man nicht, ob das Device bereits von
> anderen Prozessen geöffnet wurde und benutzt wird.

Interessanter Einwand. Hatte ich bis jetzt noch nicht festgestellt, da 
meine daemons immer ihre Rechte auf Minimal 'droppen' sobald sie 
gestartet werden.
Sollte man aber im Hinterkopf behalten, wenn man irgendetwas komplett 
mit root Rechten laufen lässt.

von Reinhard Kern (Gast)


Lesenswert?

Norbert schrieb:
> Ich habe als Programmierer die volle Kontrolle, wo also ist das Problem
> (wenn man mal Polemik außen vor lässt)?

Darüber, ob das Device schon benutzt wird, hast du ja, wie sich aus der 
Diskussion ergibt, mit deiner Methode überhaupt keine Kontrolle - nur 
darüber, ob sich in Zukunft noch ein Dritter einklinken kann.

Wie schon gesagt, der Glaube muss es richten. Es war mir schon klar dass 
sich auf meinen Post gleich die ultraorthodoxen Eiferer zu Wort melden, 
aber für mich zählen halt nur logisch korrekte Aussagen, tut mir leid. 
Linux hat natürlich auch seine guten Seiten, da muss man Schwächen nicht 
mit Täuschungsmanövern schönreden.

Gruss Reinhard

von Dr. Sommer (Gast)


Lesenswert?

Nun, an sich macht es ja mehr Sinn, komplett zu verhindern, dass "in 
Zukunft" ein 2. Programm auf den selben Port zugreift, anstatt zu 
hoffen, dass ein solches Programm so nett ist, zu prüfen, ob bereits ein 
Zugriff erfolgt. Das macht man eben mit dem TIOCEXCL Flag. Unter Windows 
ist dieses Flag quasi immer gesetzt, unter Linux hat man eben die Wahl - 
Linux kann also das gleiche wie Windows, und noch mehr - wo ist da die 
Schwäche? Was hat Windows deiner Meinung nach für einen Vorteil?

von Vn N. (wefwef_s)


Lesenswert?

Reinhard Kern schrieb:
> Darüber, ob das Device schon benutzt wird, hast du ja, wie sich aus der
> Diskussion ergibt, mit deiner Methode überhaupt keine Kontrolle - nur
> darüber, ob sich in Zukunft noch ein Dritter einklinken kann.

Mit Lockfiles ja, aber dass es allgemein keine Kontrolle gäbe, ist 
schlicht falsch (schließlich wurde ja weiter oben die Lösung gepostet). 
Und nun fantasier weiter herum.

von Norbert (Gast)


Lesenswert?

Aus den Diskussionsbeiträgen kann man sehr schön erkennen,
das es Windows Benutzern* - und das ist jetzt nicht abfällig gemeint -
ein nahezu unbekanntes Konzept ist, das Programme immer nur mit den
Rechten laufen die unbedingt für die Funktion nötig sind.
Hält man sich an dieses Konzept erkennt man das normale Programme 
praktisch (im Sinne von nahezu) niemals root-Rechte brauchen. Von 
System- und Wartungswerkzeugen einmal abgesehen, da hängen die 
notwendigen Rechte damit zusammen auf was und wie diese Werkzeuge 
zugreifen.

Wenn man daemons schreibt, kann es in Einzelfällen notwendig sein, 
diesen für bestimmt Aufgaben root-Rechte zu erteilen. Das kann man sogar 
nach einem fork() per Prozess festlegen und allen anderen Beteiligten 
Prozessen die unbenötigten Rechte entziehen (eigentlich geben sie selbst 
ihre Rechte ab)

Eine serielle Schnittstelle zum Beispiel braucht keine root-Rechte 
PUNKT.

Es liegt logisch gefolgert am Programmierer ob er seine Aufgabe gut oder 
schlecht macht / machen will.


*) Wie oft haben wir schon lesen müssen, das selbst triviale Aufgaben 
mittels sudo oder direkt als root durchgeführt werden. Dieses Prinzip 
ist gerade bei Windows Umsteigern sehr beliebt.
*) Wie oft haben wir schon lesen müssen, das Benutzerrechte solange 
erweitert werden bis etwas funktioniert.
*) Wie oft haben wir schon lesen müssen, das Resourcerestriktionen 
solange heruntergesetzt werden bis etwas funktioniert.

Ein schönes Beispiel sind Windows SMB Freigaben:
Kannst du auf die Datei zugreifen? Nein!
Prutsch,werkel,... und jetzt, geht's jetzt? Nein!
OK...bastel,bastel... teste nochmal. Cool jetzt gehts!
OK, dann lassen wir die volle Freigabe auf alles einfach drin. Ist ja 
kein Sicherheitproblem, man muß ja schließlich noch den Pfad kennen.

von Reinhard Kern (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Was hat Windows deiner Meinung nach für einen Vorteil?

Dass es die ganze Diskussion überhaupt nicht gäbe, ein COMPort steht 
einem Programm zur Verfügung, ein weiteres kann das Device nicht öffnen 
bevor das erste es nicht geschlossen hat. Und das ohne dass der 
Programmierer etwas tun muss, er bekommt beim Open einfach die Antwort 
geht nicht, wird schon verwendet. Da Devices wie Comports normalerweise 
für mehrfache Benutzung vollkommen ungeeignet sind, ist das auch die 
einzig korrekte Behandlung durch das Betriebssystem - allerdings, nach 
dem Verlauf der Diskussion, für Linuxer vollkommen unverständlich. Hier 
scheint man es für natürlich zu halten, dass die Sendedaten zweier 
Programme bunt gemischt auf TxD erscheinen. Naja, wenn ihr das so toll 
findet, da kann man halt nichts machen.

Wir hatten schon genug Ärger mit den ach so tollen Unix-Methoden wie 
Lockfiles, bei denen selbst Software der 100 KEuro-Klasse nicht sauber 
funktioniert, weil jedes Programm nur seine eigenen Lockfiles sieht. 
Aber jeder Unix-Anhänger schwört darauf als ultimative Sharing-Regelung. 
Ist aber wirklich jedes Wort zuviel, Argumente werden in diesem Umfeld 
garnicht zur Kenntnis genommen und erst recht nicht beantwortet, weil 
jemand von ausserhalb ja nur zu dumm sein kann um Unix zu kennen - eine 
Standardantwort, die ich seit 30 Jahren immer wieder höre, ganz egal um 
was es geht.

Danke für die Belehrungen, Reinhard

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Reinhard Kern schrieb:
> Dass es die ganze Diskussion überhaupt nicht gäbe, ein COMPort steht
> einem Programm zur Verfügung, ein weiteres kann das Device nicht öffnen
> bevor das erste es nicht geschlossen hat.

Das ist zwar in vielen Fällen sinnvoll, aber eben nur in vielen. Ein 
Beispiel, wo es das nicht ist, ist die Nutzung der seriellen 
Schnittstelle, um daran ein Terminal oder Modem zu betreiben.
In einer unixoiden Umgebung können sich mehrere Prozesse mit dieser 
Schnittstelle verbinden und horchen, was da an Daten reinkommt.

Primär verantwortlich ist der Prozess, der das ganze mit einer 
logon-Sitzung und letzlich irgendeiner Kommandozeilen-Shell verbindet, 
aber sekundär kann auch ein Z-Modem-Protokoll-Interpreter und ein 
Fax-Modem-Interpreter gleichzeitig dranhängen, so daß, wenn in der 
Terminalsitzung jemand Daten per Z-Modem überträgt, die gleich im 
richtigen Loch landen können, oder bei Einwahlsitzungen ein an ein 
angeschlossenes Modem gesandtes Fax nicht in einer Shell landet, sondern 
korrekt empfangen wird.

Gut, das sind alles Konzepte aus der kommunikativen Altsteinzeit ... 
aber auch in "neuzeitlicheren" Anwendungen kann es ganz praktisch sein, 
den Datenstrom, der über eine serielle Schnittstelle geht, mehrfach 
abgreifen zu können. Man stelle sich ein Gerät vor, das mit einem 
unbekannten Protokoll von einer proprietären Software angesteuert wird 
... durch einen "Mithörer" kann man schon mal Ansätze des 
Reverse-Engineering betreiben.

Fragwürdig erscheint mir das Konzept, daß die Verriegelung der 
Schnittstelle nur per informeller Absprache (lockfile und hoffen, daß 
sich alle dran halten) und nicht per open übergebenen Flags erfolgt. 
Das Windows-Pendant, CreateFile bietet die Möglichkeit, mit "share 
flags" anzugeben, ob und wie andere Prozesse die göffneten Handles 
ebenfalls öffnen dürfen.

von Arc N. (arc)


Lesenswert?

Dr. Sommer schrieb:
> Nun, an sich macht es ja mehr Sinn, komplett zu verhindern, dass "in
> Zukunft" ein 2. Programm auf den selben Port zugreift, anstatt zu
> hoffen, dass ein solches Programm so nett ist, zu prüfen, ob bereits ein
> Zugriff erfolgt. Das macht man eben mit dem TIOCEXCL Flag. Unter Windows
> ist dieses Flag quasi immer gesetzt,

Nein.
> unter Linux hat man eben die Wahl -
> Linux kann also das gleiche wie Windows, und noch *mehr*> - wo ist da die
> Schwäche? Was hat Windows deiner Meinung nach für einen Vorteil?

Win32 CreateFile
dwShareMode gibt an ob der Aufrufer exklusiven Zugriff haben will oder 
ob andere Programme lesen und/oder schreiben dürfen. Ganz einfach
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.