Sehr Umfangreiche Webseite zum Programmieren in C Perl CGI, Skripting, Linux, Systemprogrammierung Terminal Konsole Terminal Ein/Ausgabe ioctlC C++ C/C++ ANSI C Linux Linuxsystemprogrammierung Linuxsystemprogrammieren Terminal Konsole Terminal Ein/Ausgabe ioctl 6. Terminal E/A

6.3. Erfragen und Setzen der Baudrate           zurück Ein Kapitel tiefer zum Inhaltsverzeichnis

Kommen wir nun zu den Funktionen, mit denen es möglich ist, Baudraten von Terminals zu Erfragen oder zu Setzen. Damit könnten Sie zum Beispiel testen, wie die Geschwindigkeit zwischen zwei Terminals im Netzwerk ist. Folgende Funktionen stehen uns zum Erfragen der Geschwindigkeit zur Verfügung ...

speed_t cfgetispeed(const struct termios *tty_zeiger);
speed_t cfgetospeed(const struct termios *tty_zeiger);

Beide Funktionen sind in der Headerdatei <termios.h> definiert und geben die momentan gesetzte Baudrate zurück. Wobei cfgetispeed() die Baudraten-Eingabe und cfgetospeed() die Baudraten-Ausgabe zurückgibt. Folgende Konstanten sind dafür auf alle Fälle definiert:

B0,B50,B75,B110,B134,B150,B200,B300,B600,B1200,B1800,B2400,B4800,B9600,B19200,B38400

Wobei B0 für die Beendigung der Verbindung steht. Weiterhin können (unter Linux auf alle Fälle) vorhanden sein:

B57600,B115200,B230400,B460800

Angewendet wird diese Funktion folgendermaßen ...

baudrate = funktion_erfrage_baudrate(cfgetispeed(&terminal));
  ........
  .......
unsigned long funktion_erfrage_baudrate(speed baudkonstante)
 {
    if(baudkonstante == B0)              return(0);
    else if(baudkonstante == B50)        return(50);
    else if(baudkonstante == B75)        return(75);
    .........
    .........
    .........
    else if(baudkonstante == B460800)    return(460800);
    else   return ERROR;
}

Anstatt jede einzelne Baudkonstante schriftlich abzufragen, können Sie sich das ganze etwas einfacher machen. Mit einer for-Schleife und zwei Arrays. Hier das Beispiel, womit Sie die Baudrate eines Gerätes erfragen, dass Sie in der Kommandozeile mit z.B. baud /dev/tty eingeben. Damit fragen Sie die Baudrate des Kontrollterminals ab. Hier nun das Programm dazu ...

#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>

enum{ERROR=-1,SUCCESS};
typedef unsigned long Ulong;
typedef struct termios TTY;


speed_t baud_konstante[] = {   B0,B50,B75,B110,B134,B150,B200,B300,B600,B1200,
                               B1800,B2400,B4800,B9600,B19200,B38400,B57600,
                               B115200,B230400,B460800
                           };

Ulong baud_werte[] = {   0,50,75,110,134,150,200,300,600,1200,
                         1800,2400,4800,9600,19200,38400,57600,
                         115200,230400,460800
                     };

Ulong baudrate_wert(speed_t baud)
{
 int i;

 for(i=0; i<=19; i++)
   {
       if(baud == baud_konstante[i])
           return(baud_werte[i]);
   }
 return ERROR;
}


int main(int argc, char **argv)
{
 int fd;
 speed_t baud_input,  baud_output;
 TTY terminal;

 if(argc != 2)
   {
     printf("Bitte einen Gerätepfad mitangeben!!!\n");
     exit(0);
   }

 if((fd =open(argv[1], O_RDWR | O_NONBLOCK)) == ERROR)
   {
     printf("Konnte Gerätedatei %s nicht öffnen!!\n",argv[1]);
     exit(1);
   }

 if(isatty(fd) == 0)
   {
      printf("%s ist keine tty.......\n",argv[1]);
      exit(2);
   }

 if(tcgetattr(fd, &terminal) == ERROR)
   {
      printf("Fehler bei tcgetattr......\n");
      exit(3);
   }

 if(( baud_input = baudrate_wert(cfgetispeed(&terminal))) == ERROR)
   {
      printf("Fehler bei baud_input........\n");
      exit(4);
   }

 if(( baud_output = baudrate_wert(cfgetospeed(&terminal))) == ERROR)
   {
      printf("Fehler bei baud_output........\n");
      exit(5);
   }

 printf("Eingabe-Baudrate : %lu\n",baud_input);
 printf("Ausgabe_Baudrate : %lu\n",baud_output);

 return 0;
}

Neu in diesem Programm dürfte nur die Funktion ...

int isatty(int fd);

...sein. Damit können Sie Abfragen, ob ein Filedeskriptor auf das Terminal eingestellt ist. Was noch wichtig an den Funktionen cfget...() und cfset()... ist, dass Sie, wenn Sie mit cfgetispeed() z.B. etwas Abfragen wollen, müssen Sie zuerst mit der Funktion tcgetattr() die Struktur termios für das Betreffende Gerät erfragen. Das selbe gilt auch wenn Sie die beiden Funktionen ...

int cfsetispeed(struct termios *termzeiger, speed_t baudrate);
int cfsetospeed(struct termios *termzeiger, speed_t baudrate);

...einsetzen wollen. Auch hier müssen Sie diese Aufrufe mit dem tcsetattr-Aufruf aktivieren. Hier nun unser Beispiel, erweitert mit dem setzen der Baudrate auf 115200 Baud. Ob aber durch den Aufruf ...

setbaud /dev/modem oder setbaud /dev/ttyS0

...das Modem dann auch tatsächlich mit dieser Geschwindigkeit läuft, lässt sich stark bezweifeln. Hierzu nun der Code ...

#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>

enum{ERROR=-1,SUCCESS};
typedef unsigned long Ulong;
typedef struct termios TTY;


speed_t baud_konstante[] = {   B0,B50,B75,B110,B134,B150,B200,B300,B600,B1200,
                               B1800,B2400,B4800,B9600,B19200,B38400,B57600,
                               B115200,B230400,B460800
                            };

Ulong baud_werte[] = {   0,50,75,110,134,150,200,300,600,1200,
                         1800,2400,4800,9600,19200,38400,57600,
                         115200,230400,460800
                      };

void fehler_exit(char *error_msg,...)
{
  va_list az;
  va_start(az,error_msg);
  vprintf(error_msg,az);
  va_end(az);
  exit(0);
}


Ulong baudrate_wert(speed_t baud)
{
  int i;

  for(i=0; i<=19; i++)
    {
       if(baud == baud_konstante[i])
            return(baud_werte[i]);
    }
  return ERROR;
}


int main(int argc, char **argv)
{
  int fd;
  speed_t baud_input, baud_output;
  TTY terminal;

  if(argc != 2)
       fehler_exit("Bitte einen Gerätepfad mitangeben!!!\n");

  if((fd =open(argv[1], O_RDWR | O_NONBLOCK)) == ERROR)
       fehler_exit("Konnte Gerätedatei %s nicht öffnen!!\n",argv[1]);

  if(isatty(fd) == 0)
       fehler_exit("%s ist keine tty.......\n",argv[1]);

  if(tcgetattr(fd, &terminal) == ERROR)
       fehler_exit("Fehler bei tcgetattr......\n");

  if(( baud_input = baudrate_wert(cfgetispeed(&terminal))) == ERROR)
       fehler_exit("Fehler bei baud_input........\n");

  if(( baud_output = baudrate_wert(cfgetospeed(&terminal))) == ERROR)
       fehler_exit("Fehler bei baud_output........\n");

  printf("Eingabe-Baudrate : %lu\n",baud_input);
  printf("Ausgabe_Baudrate : %lu\n",baud_output);


  if((cfsetispeed(&terminal,B115200)) == ERROR)
       fehler_exit("Fehler beim setzen von Eingabe-Baudrate........\n");

  if((cfsetospeed(&terminal,B115200)) == ERROR)
       fehler_exit("Fehler beim setzen von Ausgabe-Baudrate........\n");

  if(tcsetattr(fd,TCSAFLUSH, &terminal) == ERROR)
       fehler_exit("Fehler bei tcsetattr......\n");

  if(tcgetattr(fd, &terminal) == ERROR)
       fehler_exit("Fehler bei tcgetattr......\n");

  if(( baud_input = baudrate_wert(cfgetispeed(&terminal))) == ERROR)
       fehler_exit("Fehler bei baud_input........\n");

  if(( baud_output = baudrate_wert(cfgetospeed(&terminal))) == ERROR)
       fehler_exit("Fehler bei baud_output........\n");

  printf("Eingabe-Baudrate-neu : %lu\n",baud_input);
  printf("Ausgabe_Baudrate-neu : %lu\n",baud_output);

  return 0;
}

Weitere Funktionen, die in der Headerdatei <termios.h> definiert sind, wären ...

int tcdrain(int fd);
int tcflush(int fd, int puffer);
int tcsendbreak(int fd, int dauer);
int tcflow(int fd, int aktion);

Die Funktionen sind in Ihrer Anwendung recht simpel. Lesen sie daher bitte selbst die man-Pages dazu, sofern Sie diese benötigen (man termios).

6.4. Programmieren von virtuelle Konsolen (ioctl)           zurück Ein Kapitel tiefer Ein Kapitel höher zum Inhaltsverzeichnis

Wir wollen in diesem Kapitel, was immer noch zu Terminal I/O zählt, eine virtuelle Konsole unter Linux erzeugen.

Für Anfänger und Umsteiger von Windows auf Linux will ich noch schnell erklären, was eine virtuelle Konsole überhaupt ist. Ein virtuelle Konsole ist eigentlich nichts anderes, als mehrere Terminalsitzungen an einem Bildschirm zu betreiben. Wenn Sie Beispielsweise unter Linux (nicht unter dem X-Window) die Taste von ALT+F1 bis ALT+F6 und unter X-Window die Tastenkombination STRG+ALT+F1 bis STRG+ALT+F6 drücken, können Sie zwischen einzelnen virtuellen Konsolen hin-und-herschalten. Zum X-Window kommen Sie übrigens mit der Tastenkombination ALT+F7 bzw. STRG+ALT+F7 zurück. Der Clou daran ist, dass jede einzelne virtuelle Konsole davon, Ihre eigene Einstellungen haben darf unabhängig von den anderen Konsolen. Soviel in kürze dazu.

Wenn man eine virtuelle Konsole programmieren will, benötigt man auf alle Fälle die Funktion ...

int ioctl(int fd, int operation,...);

Diese ist in der Headerdatei <sys/ioctl.h> definiert. Bei Fehler liefert diese Funktion den Wert -1 ansonsten 0. Die Angaben für die operation der Funktion, stehen in den Headerdateien <sys/vt.h> und <sys/kd.h>. Am besten binden Sie gleich von Anfang an beide Headerdateien mit in das Programm ein. Hierzu nun ein paar Konstanten der Headerdatei <sys/vt.h>, die Sie für die Programmierung von virtuelle Konsolen mit der Funktion ioctl() benötigen ...

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.

6.5. Virtuelle Konsolen und das neue Signalkonzept           zurück Ein Kapitel tiefer zum Inhaltsverzeichnis

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;
}

Weiter mit 7.1. Dateisperren (record locking)