/* go_away: * Performs a switch away. */ static void go_away(void) { _switch_out(); _unix_bg_man->disable_interrupts(); if ((switch_mode == SWITCH_PAUSE) || (switch_mode == SWITCH_AMNESIA)) _al_suspend_old_timer_emulation(); /* Disable input devices while we're away */ /* __al_linux_suspend_standard_drivers(); */ _save_switch_state(switch_mode); if (gfx_driver && gfx_driver->save_video_state) gfx_driver->save_video_state(); ioctl (__al_linux_console_fd, VT_RELDISP, 1); console_active = 0; __al_linux_switching_blocked--; if ((switch_mode == SWITCH_PAUSE) || (switch_mode == SWITCH_AMNESIA)) { __al_linux_wait_for_display(); _al_resume_old_timer_emulation(); } _unix_bg_man->enable_interrupts(); }
/* __al_linux_console_graphics: * Puts the Linux console into graphics mode. */ int __al_linux_console_graphics (void) { if (__al_linux_use_console()) return 1; if (graphics_mode) return 0; /* shouldn't happen */ __al_linux_display_switch_lock(TRUE, TRUE); ioctl(__al_linux_console_fd, KDSETMODE, KD_GRAPHICS); __al_linux_wait_for_display(); graphics_mode = 1; return 0; }
/* __al_linux_display_switch_lock: * System driver routine for locking the display around crucial bits of * code, for example when changing video modes. */ void __al_linux_display_switch_lock(int lock, int foreground) { if (__al_linux_console_fd == -1) { return; } if (foreground) { __al_linux_wait_for_display(); } if (lock) { __al_linux_switching_blocked++; } else { __al_linux_switching_blocked--; poll_console_switch(); } }
/* init_console: * Initialises this subsystem. */ static int init_console(void) { char tmp[256]; /* Find our tty's VT number */ __al_linux_vt = get_tty(STDIN_FILENO); if (__al_linux_vt < 0) { uszprintf (allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Error finding our VT: %s"), ustrerror(errno)); return 1; } if (__al_linux_vt != 0) { /* Open our current console */ if ((__al_linux_console_fd = open("/dev/tty", O_RDWR)) < 0) { uszprintf (allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unable to open %s: %s"), uconvert_ascii("/dev/tty", tmp), ustrerror(errno)); return 1; } } else { int tty, console_fd, fd, child; unsigned short mask; char tty_name[16]; struct vt_stat vts; /* Now we need to find a VT we can use. It must be readable and * writable by us, if we're not setuid root. VT_OPENQRY itself * isn't too useful because it'll only ever come up with one * suggestion, with no guarrantee that we actually have access * to it. * * At some stage I think this is a candidate for config * file overriding, but for now we'll stat the first N consoles * to see which ones we can write to (hopefully at least one!), * so that we can use that one to do ioctls. We used to use * /dev/console for that purpose but it looks like it's not * always writable by enough people. * * Having found and opened a writable device, we query the state * of the first sixteen (fifteen really) consoles, and try * opening each unused one in turn. */ if ((console_fd = open ("/dev/console", O_WRONLY)) < 0) { int n; uszprintf (allegro_error, ALLEGRO_ERROR_SIZE, uconvert_ascii("%s /dev/console: %s", tmp), get_config_text("Unable to open"), ustrerror (errno)); /* Try some ttys instead... */ for (n = 1; n <= 24; n++) { snprintf (tty_name, sizeof(tty_name), "/dev/tty%d", n); tty_name[sizeof(tty_name)-1] = 0; if ((console_fd = open (tty_name, O_WRONLY)) >= 0) break; } if (n > 24) return 1; /* leave the error message about /dev/console */ } /* Get the state of the console -- in particular, the free VT field */ if (ioctl (console_fd, VT_GETSTATE, &vts)) { uszprintf (allegro_error, ALLEGRO_ERROR_SIZE, uconvert_ascii("VT_GETSTATE: %s", tmp), ustrerror (errno)); close (console_fd); return 1; } __al_linux_prev_vt = vts.v_active; /* We attempt to set our euid to 0; if we were run with euid 0 to * start with, we'll be able to do this now. Otherwise, we'll just * ignore the error returned since it might not be a problem if the * ttys we look at are owned by the user running the program. */ seteuid(0); /* tty0 is not really a console, so start counting at 2. */ fd = -1; for (tty = 1, mask = 2; mask; tty++, mask <<= 1) { if (!(vts.v_state & mask)) { snprintf (tty_name, sizeof(tty_name), "/dev/tty%d", tty); tty_name[sizeof(tty_name)-1] = 0; if ((fd = open (tty_name, O_RDWR)) != -1) { close (fd); break; } } } seteuid (getuid()); if (!mask) { ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, get_config_text ("Unable to find a usable VT")); close (console_fd); return 1; } /* OK, now fork into the background, detach from the current console, * and attach to the new one. */ child = fork(); if (child < 0) { /* fork failed */ uszprintf (allegro_error, ALLEGRO_ERROR_SIZE, uconvert_ascii ("fork: %s", tmp), ustrerror (errno)); close (console_fd); return 1; } if (child) { /* We're the parent -- write a note to the user saying where the * app went, then quit */ fprintf (stderr, "Allegro application is running on VT %d\n", tty); exit (0); } /* We're the child. Detach from our controlling terminal, and start * a new session. */ close (console_fd); ioctl (0, TIOCNOTTY, 0); setsid(); /* Open the new one again. It becomes our ctty, because we started a * new session above. */ seteuid(0); fd = open (tty_name, O_RDWR); seteuid(getuid()); if (fd == -1) { ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, get_config_text ("Unable to reopen new console")); return 1; } /* Try to switch to it -- should succeed, since it's our ctty */ ioctl (fd, VT_ACTIVATE, tty); __al_linux_vt = tty; __al_linux_console_fd = fd; /* Check we can reliably wait until we have the display */ if (__al_linux_wait_for_display()) { close (fd); ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, get_config_text ("VT_WAITACTIVE failure")); return 1; } /* dup2 it to stdin, stdout and stderr if necessary */ if (isatty(0)) dup2 (fd, 0); if (isatty(1)) dup2 (fd, 1); if (isatty(2)) dup2 (fd, 2); } /* Get termio settings and make a working copy */ tcgetattr(__al_linux_console_fd, &__al_linux_startup_termio); __al_linux_work_termio = __al_linux_startup_termio; return 0; }