linux/drivers/char/tty_io.c
/* * linux/drivers/char/tty_io.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles * or rs-channels. It also implements echoing, cooked mode etc. * * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0. * * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the * tty_struct and tty_queue structures. Previously there was an array * of 256 tty_struct's which was statically allocated, and the * tty_queue structures were allocated at boot time. Both are now * dynamically allocated only when the tty is open. * * Also restructured routines so that there is more of a separation * between the high-level tty routines (tty_io.c and tty_ioctl.c) and * the low-level tty routines (serial.c, pty.c, console.c). This * makes for cleaner and more compact code. -TYT, 9/17/92 * * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines * which can be dynamically activated and de-activated by the line * discipline handling modules (like SLIP). * * NOTE: pay no attention to the line discipline code (yet); its * interface is still subject to change in this version... * -- TYT, 1/31/92 * * Added functionality to the OPOST tty handling. No delays, but all * other bits should be there. * -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993. * * Rewrote canonical mode and added more termios flags. * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94 * * Reorganized FASYNC support so mouse code can share it. * -- ctm@ardi.com, 9Sep95 * * New TIOCLINUX variants added. * -- mj@k332.feld.cvut.cz, 19-Nov-95 * * Restrict vt switching via ioctl() * -- grif@cs.ucr.edu, 5-Dec-95 * * Rewrote init_dev and release_dev to eliminate races. * -- Bill Hawes <whawes@star.net>, June 97 */ #include <linux/config.h> #include <linux/types.h> #include <linux/major.h> #include <linux/errno.h> #include <linux/signal.h> #include <linux/fcntl.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/timer.h> #include <linux/ctype.h> #include <linux/kd.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/malloc.h> #include <asm/segment.h> #include <asm/system.h> #include <asm/bitops.h> #include <linux/scc.h> #include "kbd_kern.h" #include "vt_kern.h" #include "selection.h" #ifdef CONFIG_KERNELD #include <linux/kerneld.h> #endif /* Bieca konsola, urzdzenie o numerze gwnym TTY_MAJOR i numerze drugorzdnym 0 (reprezentowane przez plik /dev/tty0). */ #define CONSOLE_DEV MKDEV(TTY_MAJOR,0) /* Terminal sterujcy dla procesu, urzdzenie o numerze gwnym TTYAUX_MAJOR i numerze drugorzdnym 0 (reprezentowane przez plik /dev/tty). */ #define TTY_DEV MKDEV(TTYAUX_MAJOR,0) #undef TTY_DEBUG_HANGUP #define TTY_PARANOIA_CHECK #define CHECK_TTY_COUNT extern void do_blank_screen(int nopowersave); extern void set_vesa_blanking(const unsigned long arg); /* Standardowa struktura termios dla sterownikw. */ struct termios tty_std_termios; /* for the benefit of tty drivers */ /* Lista sterownikw dla terminali. */ struct tty_driver *tty_drivers = NULL; /* linked list of tty drivers */ /* Tablica dyscyplin linii. */ struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */ /* * fg_console is the current virtual console, * last_console is the last used one, * want_console is the console we want to switch to, * kmsg_redirect is the console for kernel messages, * redirect is the pseudo-tty that console output * is redirected to if asked by TIOCCONS. */ /* Bieca wirtualna konsola. */ int fg_console = 0; /* Konsola ostatnio uywana. */ int last_console = 0; /* Konsola, na ktr chcemy si przeczy. */ int want_console = -1; /* Konsola dla komunikatw jdra. */ int kmsg_redirect = 0; /* Pseudoterminal, na ktry jest przekierowywane wyjcie przez TIOCCONS. */ struct tty_struct * redirect = NULL; /* Kolejka czekajcych na nacinicie klawisza. */ struct wait_queue * keypress_wait = NULL; /* Znacznik informujcy, czy moemy przecza si pomidzy konsolami. */ char vt_dont_switch = 0; static void initialize_tty_struct(struct tty_struct *tty); static int tty_read(struct inode *, struct file *, char *, int); static int tty_write(struct inode *, struct file *, const char *, int); static int tty_select(struct inode *, struct file *, int, select_table *); static int tty_open(struct inode *, struct file *); static void tty_release(struct inode *, struct file *); static int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); static int tty_fasync(struct inode * inode, struct file * filp, int on); extern void reset_palette(int currcons) ; extern void set_palette(void) ; #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif
/* * These two routines return the name of tty. tty_name() should NOT * be used in interrupt drivers, since it's not re-entrant. Use * _tty_name() instead. */ /* Nastpne dwie funckje zwracaj nazw terminala. tty_name nie powinna by uywana w sterownikach przerwaniowych, poniewa nie jest wielowejciowa (uywa bufora statycznego). Naley wtedy uywa _tty_name. */ char *_tty_name(struct tty_struct *tty, char *buf) { if (tty) sprintf(buf, "%s%d", tty->driver.name, MINOR(tty->device) - tty->driver.minor_start + tty->driver.name_base); else strcpy(buf, "NULL tty"); return buf; }
char *tty_name(struct tty_struct *tty) { static char buf[64]; return(_tty_name(tty, buf)); }
/* tty_paranoia_check -sprawdza poprawno numeru magic oraz czy struktura opisujca terminal nie jest NULLem. Powrt: 0 :OK, 1 :wpp. */ inline int tty_paranoia_check(struct tty_struct *tty, kdev_t device, const char *routine) { #ifdef TTY_PARANOIA_CHECK static const char *badmagic = "Warning: bad magic number for tty struct (%s) in %s\n"; static const char *badtty = "Warning: null TTY for (%s) in %s\n"; if (!tty) { printk(badtty, kdevname(device), routine); return 1; } if (tty->magic != TTY_MAGIC) { printk(badmagic, kdevname(device), routine); return 1; } #endif return 0; }
/* check_tty_count -sprawdza, czy licznik count, oznaczajcy liczb otworzonych plikw specjalnych dla danego urzdzenia, zawiera prawidow warto. Powrt: 0 :OK, poprawna warto :wpp. */ static int check_tty_count(struct tty_struct *tty, const char *routine) { #ifdef CHECK_TTY_COUNT struct file *f; int i, count = 0; /* Przegldamy list plikw zliczajc te, ktre s uywane (licznik f_count dowiza z tablic deskryptorw uytkownikw wikszy od 0) oraz wskazuj na nasz terminal. */ for (f = first_file, i=0; i<nr_files; i++, f = f->f_next) { if (!f->f_count) continue; if (f->private_data == tty) { count++; } } /* Jeeli struktura tty opisuje cz podrzdn pseudoterminala zwikszamy jeszcze raz licznik. Licznik w czci podrzdnej pseudoterminala jest wikszy o jeden od rzeczywistej liczby, aby cz podrzdna nie zostaa zamknita przed czci nadrzdn. */ if (tty->driver.type == TTY_DRIVER_TYPE_PTY && tty->driver.subtype == PTY_TYPE_SLAVE && tty->link && tty->link->count) count++; /* Jeeli obliczona przez nas warto nie zgadza si z licznikiem count w strukturze opisujcej terminal zwracamy prawidow warto. */ if (tty->count != count) { printk("Warning: dev (%s) tty->count(%d) != #fd's(%d) in %s\n", kdevname(tty->device), tty->count, count, routine); return count; } #endif return 0; }
/* tty_register_ldisc -rejestracja dyscypliny linii. Jeeli wskanik na struktur dyscypliny linii jest NULLem rejestracja oznacza wyzerowanie dyscypliny linii o podanym numerze. Powrt: 0 :OK, kod bdu :wpp. */ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) { /* Sprawdzamy, czy numer dycypliny linii zawarty w zakresie. */ if (disc < N_TTY || disc >= NR_LDISCS) return -EINVAL; /* Ustawiamy odpowiedni dyscyplin linii w tablicy dyscyplin linii ldiscs, aktualizujemy jej numer i znacznik informujcy o zdefiniowaniu dyscypliny linii. Jeeli nowa dyscyplina nie jest podana zerujemy element o numerze disc w tablicy ldiscs. */ if (new_ldisc) { ldiscs[disc] = *new_ldisc; ldiscs[disc].flags |= LDISC_FLAG_DEFINED; ldiscs[disc].num = disc; } else memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc)); return 0; }
/* Set the discipline of a tty line. */ /* tty_set_ldisc -zmieniamy dyscyplin linii. Powrt: 0 :OK, kod bdu :wpp. */ static int tty_set_ldisc(struct tty_struct *tty, int ldisc) { int retval = 0; struct tty_ldisc o_ldisc; /* Sprawdzamy poprawno numeru dyscypliny linii. */ if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS)) return -EINVAL; #ifdef CONFIG_KERNELD /* Eduardo Blanco <ejbs@cs.cs.com.uy> */ if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) { char modname [20]; sprintf(modname, "tty-ldisc-%d", ldisc); request_module (modname); } #endif /* Sprawdzamy, czy dyscyplina linii o podanym numerze zostaa zdefiniowana. */ if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) return -EINVAL; /* Jeeli ju jestemy w danej dyscyplinie linii to powrt z sukcesem. */ if (tty->ldisc.num == ldisc) return 0; /* We are already in the desired discipline */ /* Zapamitujemy biec dyscyplin linii. W przypadku niepowodzenia z now sprbujemy przywrci star dyscyplin linii. */ o_ldisc = tty->ldisc; /* Jeli jest co w buforze sterownika to prbujemy wysa na terminal. */ tty_wait_until_sent(tty, 0); /* Zamykamy biec duscyplin linii. */ /* Shutdown the current discipline. */ if (tty->ldisc.close) (tty->ldisc.close)(tty); /* Ustawiamy now dyscyplin linii. */ /* Now set up the new line discipline. */ tty->ldisc = ldiscs[ldisc]; tty->termios->c_line = ldisc; /* Jeeli istnieje to wywoujemy funkcj otworzenia specyficzn dla dyscypliny linii. */ if (tty->ldisc.open) retval = (tty->ldisc.open)(tty); /* Jeeli nie powiodo si otworzenie danej dyscypliny linii ... */ if (retval < 0) { /* ... prbujemy przywrci poprzedni. */ tty->ldisc = o_ldisc; tty->termios->c_line = tty->ldisc.num; /* Jeeli nie udao nam si otworzy poprzedniej dyscypliny linii ... */ if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) { /* ... przeczamy si do standardowej dyscypliny linii N_TTY. */ tty->ldisc = ldiscs[N_TTY]; tty->termios->c_line = N_TTY; if (tty->ldisc.open) { int r = tty->ldisc.open(tty); /* Jeeli nie potrafilimy otworzy podstawowej dyscpypliny linii to panikujemy! */ if (r < 0) panic("Couldn't open N_TTY ldisc for " "%s --- error %d.", tty_name(tty), r); } } } /* Jeeli zmienilimy dyscpylin linii (niekoniecznie na dan) wywoujemy funkcj zmiany dyscypliny linii ze sterownika (oczywicie o ile istnieje). */ if (tty->ldisc.num != o_ldisc.num && tty->driver.set_ldisc) tty->driver.set_ldisc(tty); return retval; }
/* * This routine returns a tty driver structure, given a device number */ /* get_tty_driver -zwraca struktur opisujc sterownik dla danego urzdzenia. Powrt: tty_driver :jeeli istnieje, NULL :wpp. */ struct tty_driver *get_tty_driver(kdev_t device) { int major, minor; struct tty_driver *p; /* Pobieramy numer gwny i drugorzdny urzdzenia. */ minor = MINOR(device); major = MAJOR(device); /* Przegldamy list sterownikw, aby znale waciwy. Sterownik p obsuguje num urzdze o kolejnych numerach drugorzdnych poczynajc od p->minor_start i o numerze gwnym p->major. Uwaga: minor_start tylko dla konsoli jest rny od 0 (wynosi 1). */ for (p = tty_drivers; p; p = p->next) { if (p->major != major) continue; if (minor < p->minor_start) continue; if (minor >= p->minor_start + p->num) continue; /* Zwracamy waciwy sterownik. (1) Sterownik jest dla urzdze o podanym numerze gwnym. (2) Numer drugorzdny urzdzenia mieci si w zakresie obsugiwanym przez sterownik. */ return p; } /* Nie znalelimy sterownika dla podanego urzdzenia. */ return NULL; }
/* * If we try to write to, or set the state of, a terminal and we're * not in the foreground, send a SIGTTOU. If the signal is blocked or * ignored, go ahead and perform the operation. (POSIX 7.2) */ /* tty_check_change -dla procesu dziaajcego w tle sprawdzamy czy moe wykona operacj pisania lub zmiany stanu terminala. Powrt: 0 :OK, kod bdu :wpp. */ int tty_check_change(struct tty_struct * tty) { /* Jeeli nie jest to nasz terminal sterujcy :OK */ if (current->tty != tty) return 0; /* Ujemny numer grupy terminala :OK. */ if (tty->pgrp <= 0) { printk("tty_check_change: tty->pgrp <= 0!\n"); return 0; } /* Jeeli naleymy do grupy terminala :OK. */ if (current->pgrp == tty->pgrp) return 0; /* Jeeli jest ignorowany sygna SIGTTOU :OK. */ if (is_ignored(SIGTTOU)) return 0; /* Jeeli grupa, do ktrej naley nasz proces jest 'osierocona' :bd. */ if (is_orphaned_pgrp(current->pgrp)) return -EIO; /* Wysyamy sygna SIGTTOU do grupy, do ktrej naley proces. */ (void) kill_pg(current->pgrp,SIGTTOU,1); return -ERESTARTSYS; }
static int hung_up_tty_read(struct inode * inode, struct file * file, char * buf, int count) { return 0; }
static int hung_up_tty_write(struct inode * inode, struct file * file, const char * buf, int count) { return -EIO; }
static int hung_up_tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait) { return 1; }
static int hung_up_tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { return cmd == TIOCSPGRP ? -ENOTTY : -EIO; }
static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig) { return -ESPIPE; }
/* Opisuje operacje dla terminala. */ static struct file_operations tty_fops = { tty_lseek, tty_read, tty_write, NULL, /* tty_readdir */ tty_select, tty_ioctl, NULL, /* tty_mmap */ tty_open, tty_release, NULL, /* tty_fsync */ tty_fasync };
/* hung_up_tty_fops -operacje, ktre s ustawiane po zerwaniu cznoci z terminalem. */ static struct file_operations hung_up_tty_fops = { tty_lseek, hung_up_tty_read, hung_up_tty_write, NULL, /* hung_up_tty_readdir */ hung_up_tty_select, hung_up_tty_ioctl, NULL, /* hung_up_tty_mmap */ NULL, /* hung_up_tty_open */ tty_release, /* hung_up_tty_release */ NULL, /* hung_up_tty_fsync */ NULL /* hung_up_tty_fasync */ };
/* do_tty_hangup -zerwanie cznoci z terminalem. */ void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops) { int i; struct file * filp; struct task_struct *p; if (!tty) return; /* Sprawdzamy licznik w strukturze terminala. */ check_tty_count(tty, "do_tty_hangup"); /* Przegldamy list plikw wyszukukjc te, ktre s uywane, wskazuj nasz terminal i wywoujemy dla nich funkcj fasync oraz ustawiamy f_op (file_operations) na fops przekazane jako argument do funkcji (s to hung_up_tty_fops). */ for (filp = first_file, i=0; i<nr_files; i++, filp = filp->f_next) { if (!filp->f_count) continue; if (filp->private_data != tty) continue; if (!filp->f_inode) continue; if (filp->f_inode->i_rdev == CONSOLE_DEV) continue; if (filp->f_op != &tty_fops) continue; tty_fasync(filp->f_inode, filp, 0); filp->f_op = fops; } /* Wywoujemy (jeeli istnieje) funkcj oprnienia buforw z dyscypliny linii. */ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); /* Wywoujemy (jeeli istnieje) funkcj oprnienia buforw ze sterownika. */ if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); /* Budzimy procesy czekajce w kolejce do pisania na danym terminalu. */ wake_up_interruptible(&tty->write_wait); /* Budzimy procesy czekajce w kolejce do czytania z danego terminala. */ wake_up_interruptible(&tty->read_wait); /* * Shutdown the current line discipline, and reset it to * N_TTY. */ /* Zamykamy biec dyscyplin linii. */ if (tty->ldisc.num != ldiscs[N_TTY].num) { if (tty->ldisc.close) (tty->ldisc.close)(tty); /* Przeczamy si do standardowej dyscypliny linii N_TTY. */ tty->ldisc = ldiscs[N_TTY]; tty->termios->c_line = N_TTY; if (tty->ldisc.open) { i = (tty->ldisc.open)(tty); if (i < 0) printk("do_tty_hangup: N_TTY open: error %d\n", -i); } } /* Przegldamy wszystkie procesy. */ for_each_task(p) { /* Jeeli proces jest liderem sesji terminala wysyamy do niego sygna SIGHUP (zerwania cznoci) i SIGCONT (wznowienie wstrzymanego procesu) oraz zapamitujemy identyfikator grupy terminalowej. */ if ((tty->session > 0) && (p->session == tty->session) && p->leader) { send_sig(SIGHUP,p,1); send_sig(SIGCONT,p,1); if (tty->pgrp > 0) p->tty_old_pgrp = tty->pgrp; } /* Dla wszystkich procesw, dla ktrych terminal, z ktrym zrywamy czno by terminalem sterujcym, ustawiamy terminal steryjcy na NULL. */ if (p->tty == tty) p->tty = NULL; } /* Resetujemy flagi, pole sesji, pole identyfikatora grupy terminala oraz pole stanu dla pseudoterminala. */ tty->flags = 0; tty->session = 0; tty->pgrp = -1; tty->ctrl_status = 0; /* Jeeli w sterowniku jest ustawiona flaga resetowania struktury termios inicjujemy struktur termios w terminalu. */ if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) *tty->termios = tty->driver.init_termios; /* Wywoujemy funkcj zerwania acznoci z terminalem ze sterownika. */ if (tty->driver.hangup) (tty->driver.hangup)(tty); }
void tty_hangup(struct tty_struct * tty) { #ifdef TTY_DEBUG_HANGUP printk("%s hangup...\n", tty_name(tty)); #endif do_tty_hangup(tty, &hung_up_tty_fops); }
void tty_vhangup(struct tty_struct * tty) { #ifdef TTY_DEBUG_HANGUP printk("%s vhangup...\n", tty_name(tty)); #endif do_tty_hangup(tty, &hung_up_tty_fops); }
/* tty_hung_up_p -sprawdzenie, czy operacje s ustawione na hung_up_tty_fops. */ int tty_hung_up_p(struct file * filp) { return (filp->f_op == &hung_up_tty_fops); }
/* * This function is typically called only by the session leader, when * it wants to disassociate itself from its controlling tty. * * It performs the following functions: * (1) Sends a SIGHUP and SIGCONT to the foreground process group * (2) Clears the tty from being controlling the session * (3) Clears the controlling tty for all processes in the * session group. * * The argument on_exit is set to 1 if called when a process is * exiting; it is 0 if called by the ioctl TIOCNOTTY. */ /* disassociate_ctty -funkcja woana zazwyczaj przez lidera sesji, kiedy chce on odczy si od swojego terminal sterujcego. Wykonuje nastpujce operacje: (1) Wysya SIGHUP i SIGCONT do grupy procesw pierwszoplanowych (2) Wymazuje znacznik kontrolowania sesji w terminalu (3) Wymazuje terminal sterujcy dla wszystkich procesw w grupie sesji. Argument on_exit jest 1, jeeli funkcja jest woana przez proces koczcy si,a jest rwny 0, jeli jest woana przez ioctl z argumentem TIOCNOTTY. */ void disassociate_ctty(int on_exit) { struct tty_struct *tty = current->tty; struct task_struct *p; int tty_pgrp = -1; if (tty) { /* Jeeli proces ma terminal sterujcy to zapamitujemy numer grupy terminalowej oraz ... */ tty_pgrp = tty->pgrp; /* ... jeli nie mamy do czynienia z pseudoterminalem i lider sesji koczy si (on_exit==1) to wywoujemy funkcj zerwania cznoci z terminalem. */ if (on_exit && tty->driver.type != TTY_DRIVER_TYPE_PTY) tty_vhangup(tty); } else { /* W przypadku gdy proces nie mia terminala sterujcego. */ if (current->tty_old_pgrp) { /* Jeli pole tty_old_pgrp zawiera co oznacza to, i wczeniej nastpio zerwanie cznoci z terminalem i proces ten by liderem sesji. Wysyamy sygnay SIGHUP (zerwania cznoci) i SIGCONT (wznowienia wstrzymanego procesu) do grupy tty_old_pgrp (starej grupy terminalowej). */ kill_pg(current->tty_old_pgrp, SIGHUP, on_exit); kill_pg(current->tty_old_pgrp, SIGCONT, on_exit); } return; } /* Wysyamy sygnay SIGHUP i SIGCONT do grupy terminalowej procesu. */ if (tty_pgrp > 0) { kill_pg(tty_pgrp, SIGHUP, on_exit); if (!on_exit) kill_pg(tty_pgrp, SIGCONT, on_exit); } /* Resetujemy pole tty_old_pgrp procesu. */ current->tty_old_pgrp = 0; /* Resetujemy pole sesji i grupy terminalowej w terminalu. */ tty->session = 0; tty->pgrp = -1; /* Wymazujemy terminal sterujcy dla wszystkich procesw nalecych do sesji. */ for_each_task(p) if (p->session == current->session) p->tty = NULL; }
/* * Sometimes we want to wait until a particular VT has been activated. We * do it in a very simple manner. Everybody waits on a single queue and * get woken up at once. Those that are satisfied go on with their business, * while those not ready go back to sleep. Seems overkill to add a wait * to each vt just for this - usually this does nothing! */ /* Czasem chcemy poczeka na aktywacj konkretnego terminala. Robimy to w bardzo prosty sposb. Wszyscy czekaj na jednej kolejce i budz si na raz. Ci, ktrzy s usatysfakcjonowani zaczynaj przetwarzanie, natomiast reszta idzie z powrotem spa. */ static struct wait_queue *vt_activate_queue = NULL;
/* * Sleeps until a vt is activated, or the task is interrupted. Returns * 0 if activation, -1 if interrupted. */ /* vt_waitactive -sen, dopki terminal nie zostanie uaktywniony lub nie nadejdzie przerwanie. Powrt: 0 :aktywacja, -1 :przerwanie. */ int vt_waitactive(void) { /* Zanij (przerwania dozwolone) na kolejce czekajcych na terminale. */ interruptible_sleep_on(&vt_activate_queue); /* Zwraca -1, jeeli by sygna i nie jest on blokowany, przypadek przeciwny oznacza aktywacj. */ return (current->signal & ~current->blocked) ? -1 : 0; }
#define vt_wake_waitactive() wake_up(&vt_activate_queue)
/* reset_vc -resetujemy ustawienia dla danej konsoli. */ void reset_vc(unsigned int new_console) { vt_cons[new_console]->vc_mode = KD_TEXT; kbd_table[new_console].kbdmode = VC_XLATE; vt_cons[new_console]->vt_mode.mode = VT_AUTO; vt_cons[new_console]->vt_mode.waitv = 0; vt_cons[new_console]->vt_mode.relsig = 0; vt_cons[new_console]->vt_mode.acqsig = 0; vt_cons[new_console]->vt_mode.frsig = 0; vt_cons[new_console]->vt_pid = -1; vt_cons[new_console]->vt_newvt = -1; reset_palette (new_console) ; }
/* * Performs the back end of a vt switch */ /* complete_change_console -dokoczenie przeczenia pomidzy konsolami. */ void complete_change_console(unsigned int new_console) { unsigned char old_vc_mode; /* Jeeli konsola, na ktr chcemy si przeczy jest nasz biec konsol lub jest zabronione przeczanie pomidzy konsolami to powrt. */ if ((new_console == fg_console) || (vt_dont_switch)) return; /* Sprawdzamy czy konsola zostaa zaalokowana. */ if (!vc_cons_allocated(new_console)) return; /* Zapamitujemy biec konsol jako ostatnio uywan. */ last_console = fg_console; /* * If we're switching, we could be going from KD_GRAPHICS to * KD_TEXT mode or vice versa, which means we need to blank or * unblank the screen later. */ /* Jeeli przeczamy si pomidzy konsolami moemy przechodzi midzy trybem graficznym a tekstowym, co oznacza, e musimy pniej wygasi i odwiey ekran. Zapamitujemy biey tryb. */ old_vc_mode = vt_cons[fg_console]->vc_mode; /* Aktualizujemy informacje o ekranie. */ update_screen(new_console); /* * If this new console is under process control, send it a signal * telling it that it has acquired. Also check if it has died and * clean up (similar to logic employed in change_console()) */ /* Jeeli nowa konsola ma proces sterujcy (jest w trybie VT_PROCESS), wysyamy do niego sygna, e zostaa zdobyta. Musimy rwnie sprawdzi, czy nie umar i posprzta. */ if (vt_cons[new_console]->vt_mode.mode == VT_PROCESS) { /* * Send the signal as privileged - kill_proc() will * tell us if the process has gone or something else * is awry */ /* Wysyamy sygna jako uprzywilejowany (trzeci argument dla kill_proc jest 1), na pewno zostanie wysany. kill_proc zwrci nam bd, jeli nie znajdzie tego procesu. */ if (kill_proc(vt_cons[new_console]->vt_pid, vt_cons[new_console]->vt_mode.acqsig, 1) != 0) { /* * The controlling process has died, so we revert back to * normal operation. In this case, we'll also change back * to KD_TEXT mode. I'm not sure if this is strictly correct * but it saves the agony when the X server dies and the screen * remains blanked due to KD_GRAPHICS! It would be nice to do * this outside of VT_PROCESS but there is no single process * to account for and tracking tty count may be undesirable. */ /* Proces sterujcy zmar, wic powrcamy do normy - resetujemy now konsol. Przeczamy si rwnie do trybu tekstowego. Nie jest pewne czy to jest zupenie poprawne, ale ratuje przed zawieszeniem jeeli X serwer zmar i ekran pozostaje wygaszony w trybie graficznym. */ reset_vc(new_console); } } /* * We do this here because the controlling process above may have * gone, and so there is now a new vc_mode */ /* Robimy to tutaj, poniewa proces sterujcy mg si skoczy i mamy nowy tryb. */ if (old_vc_mode != vt_cons[new_console]->vc_mode) { if (vt_cons[new_console]->vc_mode == KD_TEXT) do_unblank_screen(); else do_blank_screen(1); } /* Set the colour palette for this VT */ /* Ustawiamy palet dla tego wirtualnego terminala, jeeli jest w trybie tekstowym. */ if (vt_cons[new_console]->vc_mode == KD_TEXT) set_palette() ; /* * Wake anyone waiting for their VT to activate */ /* Budzimy czekajcych na aktywacj terminali. */ vt_wake_waitactive(); return; }
/* * Performs the front-end of a vt switch */ /* change_console -zmiana konsoli. */ void change_console(unsigned int new_console) { /* Jeeli konsola, na ktr chcemy si przeczy jest nasz biec konsol lub jest zabronione przeczanie pomidzy konsolami to powrt. */ if ((new_console == fg_console) || (vt_dont_switch)) return; if (!vc_cons_allocated(new_console)) return; /* * If this vt is in process mode, then we need to handshake with * that process before switching. Essentially, we store where that * vt wants to switch to and wait for it to tell us when it's done * (via VT_RELDISP ioctl). * * We also check to see if the controlling process still exists. * If it doesn't, we reset this vt to auto mode and continue. * This is a cheap way to track process control. The worst thing * that can happen is: we send a signal to a process, it dies, and * the switch gets "lost" waiting for a response; hopefully, the * user will try again, we'll detect the process is gone (unless * the user waits just the right amount of time :-) and revert the * vt to auto control. */ /* Jeeli biecy terminal ma proces sterujcy, musimy si porozumie z nim przed przeczeniem. Przechowujemy terminal, na ktry chcemy si przeczy i czekamy na informacje o przeczneiu (przez VT_RELDISP). Sprawdzamy rwnie czy proces sterujcy wci istnieje. Jeeli nie istnieje to przeczamy wirtualny terminal do trybu automatycznego i kontynuujemy. Jest to prosty sposb na ledzenie procesu sterujcego. Najgorszy scenariusz, ktry moe si zdarzy to: wysyamy sygna do procesu, on umiera, dostajemy 'zgubione' czekajc na odpowied; na szczcie uytkownik sprbuje znowu, wykryjemy, e nie ma procesu sterujcego i przeczymy terminal w tryb automatyczny. */ if (vt_cons[fg_console]->vt_mode.mode == VT_PROCESS) { /* * Send the signal as privileged - kill_proc() will * tell us if the process has gone or something else * is awry */ /* Wysyamy sygna jako uprzywilejowany (na pewno zostanie wysany). kill_proc przekae nam czy proces skoczy si. */ if (kill_proc(vt_cons[fg_console]->vt_pid, vt_cons[fg_console]->vt_mode.relsig, 1) == 0) { /* * It worked. Mark the vt to switch to and * return. The process needs to send us a * VT_RELDISP ioctl to complete the switch. */ /* Proces dziaa. Zaznaczamy wirtualny terminal, na ktry chcemy si przeczy. Proces sterujcy musi nam przesa ioctl VT_RELDISP, abymy skoczyli przeczanie. */ vt_cons[fg_console]->vt_newvt = new_console; return; } /* * The controlling process has died, so we revert back to * normal operation. In this case, we'll also change back * to KD_TEXT mode. I'm not sure if this is strictly correct * but it saves the agony when the X server dies and the screen * remains blanked due to KD_GRAPHICS! It would be nice to do * this outside of VT_PROCESS but there is no single process * to account for and tracking tty count may be undesirable. */ /* Proces sterujcy zmar, wic wracamy do normy. Przeczamy si rwnie do trybu tekstowego. Nie jest pewne czy to jest zupenie poprawne, lecz ratuje przed zawieszeniem, jeeli X serwer umrze i ekran pozostaje wygaszony w trybie graficznym. */ reset_vc(fg_console); /* * Fall through to normal (VT_AUTO) handling of the switch... */ } /* * Ignore all switches in KD_GRAPHICS+VT_AUTO mode */ /* Bieca konsola nie miaa procesu sterujcego i jest w trybie graficznym: nie pezczamy si. */ if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) return; /* Koczymy przeacznie konsoli, jeeli bieca konsola miaa proces sterujcy, ktry zmar lub nie miaa procesu sterujcego i jest w trybie tekstowym. */ complete_change_console(new_console); }
/* wait_for_keypress -czekamy na nacinicie klawisza. */ void wait_for_keypress(void) { sleep_on(&keypress_wait); }
/* stop_tty -wstrzymanie wypisywania na terminalu. */ void stop_tty(struct tty_struct *tty) { /* Jeeli terminal ju zastopowany to nic nie robimy. */ if (tty->stopped) return; /* Ustawiamy znacznik zastopowania terminala. */ tty->stopped = 1; /* Jeeli jest to cz podrzdna pseudoterminala pracujcego w trybie pakietowym to kasujemy mask TIOCPKT_START i ustawiamy mask TIOCPKT_STOP. Budzimy procesy czekajce na odczyt w drugiej, nadrzdnej czci naszego pseudoterminala. */ if (tty->link && tty->link->packet) { tty->ctrl_status &= ~TIOCPKT_START; tty->ctrl_status |= TIOCPKT_STOP; wake_up_interruptible(&tty->link->read_wait); } /* Wywoujemy funkcj zatrzymania ze sterownika. */ if (tty->driver.stop) (tty->driver.stop)(tty); }
/* start_tty -wznowienie wypisywania na terminalu. */ void start_tty(struct tty_struct *tty) { /* Jeeli terminal nie by zatrzymany to nie mamy nic do zrobienia. */ if (!tty->stopped) return; /* Kasujemy znacznik informujcy o zatrzymaniu terminala. */ tty->stopped = 0; /* Jeeli jestemy w czci podrzdnej psudoterminala pracujcego w trybie pakietowym to kasujemy mask zatrzymania terminala TIOCPKT_STOP i ustwiamy mask pracy TIOCPKT_START oraz budzimy procesy czekajce na odczyt w czci nadrzdnej pseudoterminala. */ if (tty->link && tty->link->packet) { tty->ctrl_status &= ~TIOCPKT_STOP; tty->ctrl_status |= TIOCPKT_START; wake_up_interruptible(&tty->link->read_wait); } /* Wywoujemy funkcj wznowienia przetwarzania ze sterownika. */ if (tty->driver.start) (tty->driver.start)(tty); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); /* Budzimy procesy czekajce na zapis do terminala. */ wake_up_interruptible(&tty->write_wait); }
/* tty_read -czytamy z terminala. Argumenty: inode :i-wze pliku, z ktrego chcemy czyta, file :struktura poisujca plik, z ktrego chcemy czyta, buf :bufor, w ktrym zapiszemy odczytane bajty, count :liczba bajtw, ktre chcemy przeczyta. Powrt: liczba zapisanych bajtw :nie wystpi bd, kod bdu :wpp. */ static int tty_read(struct inode * inode, struct file * file, char * buf, int count) { int i; struct tty_struct * tty; /* Pobieramy ze struktury file struktur opisujc terminal. */ tty = (struct tty_struct *)file->private_data; /* Sprawdzamy, czy wskanik nie jest pusty oraz czy jest prawidowy numer magic. */ if (tty_paranoia_check(tty, inode->i_rdev, "tty_read")) return -EIO; /* Jeeli nie ma terminala lub jest ustawiona flaga bdu wejcia-wyjcia to powracamy z bdem wejcia-wyjcia. */ if (!tty || (tty->flags & (1 << TTY_IO_ERROR))) return -EIO; /* This check not only needs to be done before reading, but also whenever read_chan() gets woken up after sleeping, so I've moved it to there. This should only be done for the N_TTY line discipline, anyway. Same goes for write_chan(). -- jlc. */ #if 0 if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */ (tty->pgrp > 0) && (current->tty == tty) && (tty->pgrp != current->pgrp)) if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp)) return -EIO; else { (void) kill_pg(current->pgrp, SIGTTIN, 1); return -ERESTARTSYS; } #endif /* Jeeli istnieje fukcja odczytu w dyscyplinie linii to j wywoujemy, w przeciwnym przypadku powrt z bdem wejcia-wyjcia. */ if (tty->ldisc.read) /* XXX casts are for what kernel-wide prototypes should be. */ i = (tty->ldisc.read)(tty,file,(unsigned char *)buf,(unsigned int)count); else i = -EIO; /* Jeeli funkcja z dyscypliny linii zwrcia warto wiksz od 0 (oznacza to, e co zapisalimy) aktualizujemy czas ostatniego dostpu w i-wle. */ if (i > 0) inode->i_atime = CURRENT_TIME; return i; }
/* * Split writes up in sane blocksizes to avoid * denial-of-service type attacks */ /* do_tty_write -zapisujemy na terminalu. Argumenty: write :funkcja zapisu z dyscypliny linii, inode :i-wze pliku (terminala), w ktrym chcemy pis, tty :terminal, na ktrym chcemy pisa, file :plik, w ktrym chcemy pisa, buf :bufor zawierajcy dane do zapisania, count :liczba bajtw, ile chcemy zapisa. Powrt: liczba_zapisanych bajtw :nie wystpi bd, kod bdu :wpp. */ static inline int do_tty_write( int (*write)(struct tty_struct *, struct file *, const unsigned char *, unsigned int), struct inode *inode, struct tty_struct *tty, struct file *file, const unsigned char *buf, unsigned int count) { int ret = 0, written = 0; /* Dzielimy bufor na kawaki, ktre przekazujemy funkcji zapisu z dyscypliny linii (argument write). */ for (;;) { unsigned int size = PAGE_SIZE*2; if (size > count) size = count; /* Zapisujemy size elementw z bufora. */ ret = write(tty, file, buf, size); /* Jeeli nie udao si nam nic zapisa to przerywamy. */ if (ret <= 0) break; /* Zwikszamy liczb zapisanych bajtw. */ written += ret; /* Przesuwamy si w buforze. */ buf += ret; /* Zmniejszamy liczb bajtw do zapisania. */ count -= ret; /* Jeeli nic nie zostao do zapisania to przerywamy. */ if (!count) break; /* Jeeli by sygna i nie by on blokowany to przerywamy. */ ret = -ERESTARTSYS; if (current->signal & ~current->blocked) break; /* Jeeli potrzebujemy sponownego szeregowania to szeregujemy. */ if (need_resched) schedule(); } /* Jeeli udao si co zapisa to uaktualniamy czas ostatniego zapisu w i-wle. */ if (written) { inode->i_mtime = CURRENT_TIME; ret = written; } /* Zwracamy liczb zapisanych bajtw lub bd. */ return ret; }
/* tty_write -funkcja zapisu do terminala. Argumenty: inode :i-wze pliku, do ktrego chcemy pisa, file :plik, do ktrego chcemy pisa, buf :bufor z danymi, ktre chcemy zapisa, count :liczba bajtw danych, ile chcemy zapisa. Powrt: liczba zapisanych bajtw :nie wystpi bd, kod bdu :wpp. */ static int tty_write(struct inode * inode, struct file * file, const char * buf, int count) { int is_console; struct tty_struct * tty; /* Czy urzdzenie, na ktrym mamy pisa jest biec konsol (urzdzeniem o numerze gwnym TTY_MAJOR i numerze drugorzdnym 0). */ is_console = (inode->i_rdev == CONSOLE_DEV); /* Jeeli jest biec konsol i jest przekierowane to terminalem, na ktrym bdziemy pisa to bdzie redirect, w przeciwnym przypadku pobieramy struktur terminala z file. */ if (is_console && redirect) tty = redirect; else tty = (struct tty_struct *)file->private_data; /* Sprawdzamy, czy terminal nie jest NULLem oraz czy ma waciwy numer magic. */ if (tty_paranoia_check(tty, inode->i_rdev, "tty_write")) return -EIO; /* Jelei struktura terminalowa jest NULLem lub nie istnieje funkcja zapisu w sterowniku lub jest ustawiona flaga bdu wejcia-wyjcia to zwracamy bd wejcia-wyjcia. */ if (!tty || !tty->driver.write || (tty->flags & (1 << TTY_IO_ERROR))) return -EIO; #if 0 if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) && (current->tty == tty) && (tty->pgrp != current->pgrp)) { if (is_orphaned_pgrp(current->pgrp)) return -EIO; if (!is_ignored(SIGTTOU)) { (void) kill_pg(current->pgrp, SIGTTOU, 1); return -ERESTARTSYS; } } #endif /* Jeeli nie istnieje funkcja zapisu w dyscyplinie linii zwracamy bd wejcia-wyjcia. */ if (!tty->ldisc.write) return -EIO; /* Zapisujemy dane do terminala. */ return do_tty_write(tty->ldisc.write, inode, tty, file, (const unsigned char *)buf, (unsigned int)count); }
/* Semaphore to protect creating and releasing a tty */ /* Semafor do ochrony tworzenia i zwalniania struktury terminalowej. */ static struct semaphore tty_sem = MUTEX;
static void down_tty_sem(int index) { down(&tty_sem); }
static void up_tty_sem(int index) { up(&tty_sem); }
static void release_mem(struct tty_struct *tty, int idx);
/* * Rewritten to remove races and properly clean up after a failed open. * The new code protects the open with a semaphore, so it's really * quite straightforward. The semaphore locking can probably be * relaxed for the (most common) case of reopening a tty. */ /* init_dev -alokacja pamici i inicjacja struktury terminala. Kod ten przepisano, aby usun wycig procesw i poprawnie posprzta po nieudanym otwarciu. W tej chwili otworzenie terminala jest chronione przez semafory, prawdopodobnie byoby mona zwolni semafor dla wikszoci przypadkw powtrnego otwierania. */ Powrt: 0 :sukces, kod bdu :wpp. */ static int init_dev(kdev_t device, struct tty_struct **ret_tty) { struct tty_struct *tty, *o_tty; struct termios *tp, **tp_loc, *o_tp, **o_tp_loc; struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; struct tty_driver *driver; int retval; int idx; /* Pobieramy sterownnik dla dango urzdzenia. */ driver = get_tty_driver(device); /* Jeeli nie znalelimy sterownika zwracamy bd braku urzdzenia. */ if (!driver) return -ENODEV; /* Obliczamy indeks dla urzdzenia w tablicy table otworzonych urzdze w sterowniku. Sterownik obsuguje urzdzenia o tym samym numerze gwnym i numerach drugorzdnych od numeru minor_start. */ idx = MINOR(device) - driver->minor_start; /* * Check whether we need to acquire the tty semaphore to avoid * race conditions. For now, play it safe. */ /* Opuszczamy odpowiedni semafor. */ down_tty_sem(idx); /* check whether we're reopening an existing tty */ /* Jeeli powtrnie otwieramy istniejcy terminal nastpuje, tak zwane, sz^RdZeZ.O Q:&xݬAs oD- y VT;ʶxr X=e^M5*rLϤ /}n_"ސegΚ%~5JqNb,q#@&4 hdsmPLѼF˅zrO 9i'Xʔ=V09k{θ#'Q!?1f{Ir|x^A$|sc.'wm 24!W }vVl9/*ҏ$Jvݦ1Vɉ]@g4Ypn0 vpH[qдB]IJ64G:@J%H#Vdh(WEK(D5vU-eӤeِ]YniUQi/{o$T7a Bg:8XRtNUbN6)6{~AdKv;`dv{3aiVJ|G&*]fJYWց8KepV6߇& !zd[dlUQ~F_D+U#̈ KQztV !j35Gzvӎ #MsCʶ3o=HQ(Xb:?*p,{L~zzÎsh(!+mFvnZ]GP.>⁄Rͤ~㸞/"P@_&o