| #include <pronix.de> |
|
|
6.3. Erfragen und Setzen der Baudrate
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Konstante | Bedeutung |
#define VT_AUTO 0x00 |
/*Damit ist es möglich
zwischen den einzelnen Terminals mit entsprechender Tastenkombination Hin-und-Herzuschalten oder reagiert darauf wenn ein Programm eine entsprechende Aufforderung an den Kern schickt */ |
| #define VT_PROCESS 0x01 | /*Abfrage vom Systemkern ob sie wirklich die Konsole wechseln wollen, falls sie es vorhaben */ |
| VT_OPENQRY | /*Sucht nach einer freien
virtuellen Konsole : if(ioctl(fd, VT_OPENQRY, &vtty_nummer) <0 || vtty_nummer == -1) //Fehler Vorraussetzung das sie eine freie virtuelle Konsole suchen ist das sie zuvor die Gerätedatei /dev/tty mit open() für das Terminal geöffnet haben*/ |
| VT_GETMODE | /*Mit dieser Konstante könne wir abfragen ob das aktuelle Terminal eine virtuelle Konsole ist */ |
| VT_GETSTATE | /*Damit ermitteln wir die Nummer der aktiven virtuellen Konsole*/ |
| VT_ACTIVATE | /*Um auf eine andere
virtuelle Konsole umzuschalten. Kann im Grafikmodus etwas dauern */ |
| VT_WAITACTIVE | /*Wartet bis die virtuelle
Konsole wirklich akitv (VT_ACTIVATE) ist, dann kann ein Prozess starten */ |
| VT_DISALLOCATE | /*Den für die virtuelle Konsole reservierten Speicher wieder freigeben.*/ |
| VT_SETMODE | damit setzen sie den Modus der aktuellen Konsole |
| VT_RELDISP | damit geben sie eine virtuelle Konsole frei |
| VT_ACKAQK | übernimmt die Virtuelle Konsole so damit diese aktiv wird |
| KIOCSOUND | Damit schalten sie den Terminalton ein. Als 3.Parameter benötigen sie dabei Frequenzzahl -> ioctl(vter_fd, KIOCSOUND, 20); |
| VT_LOCKSWITCH | Damit können die Umschaltung der virtuellen Terminals auschalten |
| VT_UNLOCKSWITCH | Damit schalten sie die Umschaltung der virtuellen Terminals wieder ein. |
Bevor wir uns dies in der Praxis ansehen, muss ich Ihnen noch zwei Strukturen erklären, die ebenfalls in der Headerdatei <sys/vt.h> definiert sind ...
struct vt_mode {
char mode; /*Ist mit VT_AUTO(0x00) oder VT_PROCESS(0x01) gesetzt*/
char waitv; /*wenn gesetzt wird schreiben auf eine virtuelle Konsole
/*blockiert die z.Z. nicht aktiv ist bis die aktiviert ist */
short relsig; /*Signal vom Systemkern das er sendet zur Freigabe*/
/*der virtuellen Konsole*/
short acqsig; /*Signal vom Systemkern das er sendet wen er */
/*den Prozess warnen will daß er sich diese virtuelle Konsole*/
/*angeeignet hat */
short frsig; /*unbenutzt*/
};
struct vt_stat {
unsigned short v_active; /*enthält die Nummer der gerade aktiven virt. Konsole*/
unsigned short v_signal; /*noch nicht benutzt*/
/*Bitmaske die die ersten 16 virtuellen Konsolen
/*anzeigt die offen sind von maximal 63 offenen */
unsigned short v_state;
};
Zum besseren Verständnis wollen wir dies jetzt in einem kleinen Beispiel verwenden ...
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/vt.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdarg.h>
#include <fcntl.h>
enum{ERROR=-1,OK};
void fehler_exit(char *error_msg,...)
{
va_list az;
va_start(az,error_msg);
vprintf(error_msg,az);
va_end(az);
exit(0);
}
int main()
{
int vterm_nr, vterm_fd;
int status;
struct vt_stat vterm_stat;
char terminal[100];
pid_t kindprozess;
/*Zuerst öffnen wir die Gerätedatei /dev/tty da wir für ioctl ein Filedeskriptor benötigen */
if((vterm_fd = open("/dev/tty", O_RDWR, 0)) == ERROR)
fehler_exit("Kann /dev/tty nicht öffnen.....\n");
/*Jetzt prüfen wir ob tty eine virtuelle Konsole ist*/
if(ioctl(vterm_fd, VT_GETSTATE, &vterm_stat) == ERROR)
fehler_exit("tty ist keine virtuelle Konsole..\n");
/*Jetzt suchen wir uns eine freie virtuelle Konsole*/
if(ioctl(vterm_fd, VT_OPENQRY, &vterm_nr) == ERROR || vterm_nr == ERROR)
fehler_exit("Keine freie konsole vorhanden...\n");
sprintf(terminal,"/dev/tty%d",vterm_nr);
printf("Versuche neues Terminal %s zu öffnen........\n",terminal);
/*Jetzt wollen wir überprüfen ob wir auf unserem neuen virt. */
/*Term Lesen und Schreiben dürfen*/
if(access(terminal, (W_OK|R_OK)) == ERROR)
fehler_exit("Unzureichend Rechte auf das Terminal......\n");
/*Jetzt erzeugen wir einen neuen Prozess für unser neues Terminal*/
if((kindprozess=fork()) == OK)
{
/*Wir aktivieren die neuen Konsole warten bis sie wirklich aktiviert wird*/
ioctl(vterm_fd, VT_ACTIVATE, vterm_nr);
ioctl(vterm_fd, VT_WAITACTIVE, vterm_nr);
/*Wir richten eine neue Session ein*/
setsid();
/*Wir schließen stdin,stdout und stderr und vterm_fd da wir ja eine neuen virtuelle*/
/*Konsole starten wollen und nicht mit dem ganzprintf("%s\n",terminal);en vererbten*/
/*Eigenschaften des Elternprozesses*/
close(0); close(1); close(2); close(vterm_fd);
/*Jetzt können wir in unserem Kindprozess die Kprintf("%s\n",terminal);konsole öffen*/
vterm_fd = open(terminal, O_RDWR,0);
printf("%s\n",terminal);
dup(vterm_fd); dup(vterm_fd);
/*Ausführen von unserer neuen virtuellen Konsole*/
printf("...........................Virtuelle Konsolle"
"(tty%d)..................\n\n\n",vterm_nr);
execlp("/bin/bash", "bash", NULL); printf("%s\n",terminal);
} /*Ende Kindprozess*/
wait(NULL); /*Elternprozess wartet auf den Kindprozess*/
/*Alte Konsole wieder aktivieren und Speicher der virtuellen Konsole wieder freigeben*/
ioctl(vterm_fd, VT_ACTIVATE, vterm_stat.v_active);
ioctl(vterm_fd, VT_WAITACTIVE, vterm_stat.v_active);
ioctl(vterm_fd, VT_DISALLOCATE, vterm_nr);
return 0;
}
Zum Ausführen diese Beispiels öffnen Sie bitte ein echtes Terminal mit STRG+ALT+F1. Wenn Sie das Programm jetzt compiliert haben und ausführen, öffnen Sie ein neues virtuelles Terminal. Bei den meisten dürfte dies /dev/tty8 sein. Unser Terminal welches das neue Terminal aufgerufen hat, wartet solange (wait(NULL)), bis sein Kindprozess (dev/tty8) fertig ist. Dies können Sie sich mit STRG+ALT+F1 ansehen. Zu Ihrer neuen virtuellen Konsole kommen Sie zurück mit STRG+ALT+F8. Wenn Sie jetzt die neue virtuelle Konsole beenden (exit), kommen Sie wieder zu der alten Konsole zurück welche die Neue aufgerufen hat. Falls Sie folgende Fehlermeldung erhalten ...
Unzureichend Rechte auf das Terminal......
... machen Sie sich mal kurz zum Superuser (su) und verändern die Rechte auf das neue virtuelle Terminal. In unserem Beispiel währe es /dev/tty8 ...
chmod a+rw /dev/tty8
...damit haben alle Lese.- und Schreibrecht auf diesem Terminal.
Schreiben wir ein weiteres Programm zu den virtuellen Terminals. Es ist das selbe Programm, wie schon im Kapitel zuvor, nur werden Sie aufgefordert ein Passwort einzugeben um die neue virtuelle Konsole zu starten. Die Funktion getpass() ist der reelen Funktion ...
char getpass(const char *prompt);
...nachgebildet. Die echte getpass()-Funktion ist in der Headerdatei <stdlib.h> definiert. In diesem Beispiel verwenden wir noch die Funktionen ...
int sigemptyset(sigset_t *set);
... womit alle Signale aus der Signalmenge entfernen werdeb. Jetzt können Sie mit der Funktion ...
int sigaddset(sigset_t *set, int signal);
... einzelne Signale wieder zu der Signalmenge hinzufügen. Das Gegenstück dazu ist die Funktion ...
int sigdelset(sigset_t *set, int signal);
...womit Sie einzelne Signale aus der Signalmenge entfernen können (wird aber in unserem Beispiel nicht verwendet). Aktivieren wird die Signalmaske mit ...
int sigprocmask(int wie, sigset_t neu_signale, sigset_t save_alt_signale);
Wobei Sie für wie folgende drei Konstanten zur Verfügung haben ...
Sollten Sie z.B. kein Interesse an den alten Signalmasken haben, so können Sie auch für save_alt_signale den NULL-Zeiger übergeben. Andersrum, wenn Sie nur die Signalmaske erfragen wollen können Sie bei neu_signale den NULL-Zeiger übergeben.
Eine Signalmaske können Sie mit der Funktion ...
int sigismember(sigset_t *set, int signal);
... erfragen. Beispielsweise ...
sigset_t signalmaske;
if(sigpending(&signalmaske) == ERROR)
/*Fehler bei sigpending*/
if(sigismember(&signalmaske, SIGCHLD))
/*Signal SIGCHLD hängt*/
Hier fragen Sie ab, ob das Signal SIGCHLD blockiert wird. Dies machen Sie mit der Funktion ...
int sigpending(sigset_t signale);
Und anschließend fragen Sie mit der Funktion sigismember() die einzelnen Funktionen ab. Dies stellt natürlich nur ein Beispiel da und muss nicht so verwendet werden. Dies nur zur Auffrischung der Erinnerung. Mehr dazu finden sie in den Kapitel der Signale.
Hier nun das Programm, mit den virtuellen Terminals mit Passwortabfrage ...
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/vt.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdarg.h>
#include <fcntl.h>
#include <signal.h>
#include <termios.h>
#include <string.h>
#include <sys/kd.h>
enum{ERROR=-1,OK};
/* Maximale #zeichen für die Eingabe */
#define MAX_PASS_LEN 8
#define PASSWORT "pinguine"
/*Zum Abfragen eines Passwortes*/
char *getpass(const char *prompt)
{/* +1 für das 0-Byte am Ende zum Terminieren */
static char buf[MAX_PASS_LEN + 1];
char *ptr;
sigset_t sig, sigsave;
struct termios term, termsave;
FILE *fp;
int c;
if ( (fp = fopen(ctermid(NULL), "r+")) == NULL)
return(NULL);
setbuf(fp, NULL); //wir schalten die Pufferung aus
sigemptyset(&sig); /* Entfernen der Signale aus Signalmenge */
sigaddset(&sig, SIGINT); /*fügen SIGINT dazu */
sigaddset(&sig, SIGTSTP); /*fügen SIGSTP dazu */
/*blockieren von SIGINT und SIGSTP und sichern der Alten Signalmenge in sigsave*/
sigprocmask(SIG_BLOCK, &sig, &sigsave);
tcgetattr(fileno(fp), &termsave);/* Sichern des aktuellen Terminals in termsave */
term = termsave; /* copy */
/*Löschen folgender lokalen Flags: ECHO : Ausgabe */
/* ECHOE: Gelöschte Zeichen mit Leerzeichen überschreiben */
/* ECHOK: Zeichen wirklich löschen */
/* ECHONL: Ausgabe von Newline */
term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
/*Wir setzen unsere neuen Attribute*/
tcsetattr(fileno(fp), TCSAFLUSH, &term);
/*Gibt "Passwort : " aus*/
fputs(prompt, fp);
/*Passwort wird Zeichenweise an die Adresse von ptr geschrieben*/
ptr = buf;
while ( (c = getc(fp)) != EOF && c != '\n')
{
if (ptr < &buf[MAX_PASS_LEN])
*ptr++ = c;
}
ptr = '\0'; /* null terminate */
putc('\n', fp); /* echo newline */
/* Wir stellen unser altes Terminal wieder her*/
tcsetattr(fileno(fp), TCSAFLUSH, &termsave);
/* Wir stellen die alte Signalmaske wieder her */
sigprocmask(SIG_SETMASK, &sigsave, NULL);
fclose(fp);
return(buf);
}
void fehler_exit(char *error_msg,...)
{
va_list az;
va_start(az,error_msg);
vprintf(error_msg,az);
va_end(az);
exit(0);
}
int main()
{
int vterm_nr, vterm_fd;
int status;
struct vt_stat vterm_stat;
char terminal[100],*passwort;
pid_t kindprozess;
/*Zuerst öffnen wir die Gerätedatei /dev/tty da wir für ioctl */
/* ein Filedeskriptor benötigen */
if((vterm_fd = open("/dev/tty", O_RDWR, 0)) == ERROR)
fehler_exit("Kann /dev/tty nicht öffnen.....\n");
/*Jetzt prüfen wir ob tty eine virtuelle Konsole ist*/
if(ioctl(vterm_fd, VT_GETSTATE, &vterm_stat) == ERROR)
fehler_exit("tty ist keine virtuelle Konsole..\n");
/*Jetzt suchen wir uns eine freie virtuelle Konsole*/
if(ioctl(vterm_fd, VT_OPENQRY, &vterm_nr) == ERROR || vterm_nr == ERROR)
fehler_exit("Keine freie konsole vorhanden...\n");
sprintf(terminal,"/dev/tty%d",vterm_nr);
printf("Versuche neues Terminal %s zu öffnen........\n",terminal);
/*Jetzt wollen wir überprüfen ob wir auf unserem neuen virt. Term */
/* Lesen und Schreiben dürfen*/
if(access(terminal, (W_OK|R_OK)) == ERROR)
fehler_exit("Unzureichend Rechte auf das Terminal......\n");
/*Wir fragen ein Passwort ab -> "pinguine" */
if(strcmp(passwort=getpass("Passwort : "),PASSWORT)!=0)
fehler_exit("Falsches Passwort......\n");
/*Jetzt erzeugen wir einen neuen Prozess für unser neues Terminal*/
if((kindprozess=fork()) == OK)
{
/*Wir aktivieren die neuen Konsole warten bis sie wirklich aktiviert wird*/
ioctl(vterm_fd, VT_ACTIVATE, vterm_nr);
ioctl(vterm_fd, VT_WAITACTIVE, vterm_nr);
/*Wir richten eine neue Session ein*/
setsid();
/*Wir schließen stdin,stdout und stderr und vterm_fd da wir ja eine neuen */
/*virtuelle Konsole starten wollen und nicht mit dem ganzen vererbten */
/* Eigenschaften des Elternprozesses*/
close(0); close(1); close(2); close(vterm_fd);
/*Jetzt können wir in unserem Kindprozess die Konsole öffen*/
vterm_fd = open(terminal, O_RDWR,0);
dup(vterm_fd); dup(vterm_fd);
ioctl(vterm_fd, KIOCSOUND, 1000); /*beep an*/
sleep(1); /*1 sekunde beep*/
ioctl(vterm_fd, KIOCSOUND, 0); /*beep aus*/
/*Ausführen von unserer neuen virtuellen Konsole*/
system("setterm -foreground black -background green");
printf("...........................Virtuelle Konsolle"
" (tty%d)............................\n\n\n",vterm_nr);
system("setterm -foreground white -background black");
execlp("/bin/bash", "bash", NULL);
} /*Ende Kindprozess*/
wait(NULL); /*Elternprozess wartet auf den Kindprozess*/
/*Alte Konsole wieder aktivieren und Speicher der virtuellen Konsole wieder freigeben*/
ioctl(vterm_fd, VT_ACTIVATE, vterm_stat.v_active);
ioctl(vterm_fd, VT_WAITACTIVE, vterm_stat.v_active);
ioctl(vterm_fd, VT_DISALLOCATE, vterm_nr);
return 0;
}