Blame src/vlock/vt.c

Packit ec106e
Packit ec106e
/*
Packit ec106e
Packit ec106e
  VT code and signal handling for vlock, the VT locking program for linux.
Packit ec106e
Packit ec106e
  Copyright (C) 1994-1998  Michael K. Johnson <johnsonm@redhat.com>
Packit ec106e
  Copyright (C) 2002, 2004, 2005  Dmitry V. Levin <ldv@altlinux.org>
Packit ec106e
Packit ec106e
  This program is free software; you can redistribute it and/or modify
Packit ec106e
  it under the terms of the GNU General Public License as published by
Packit ec106e
  the Free Software Foundation; either version 2 of the License, or
Packit ec106e
  (at your option) any later version.
Packit ec106e
Packit ec106e
  This program is distributed in the hope that it will be useful,
Packit ec106e
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ec106e
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Packit ec106e
  GNU General Public License for more details.
Packit ec106e
Packit ec106e
  You should have received a copy of the GNU General Public License
Packit ec106e
  along with this program; if not, write to the Free Software
Packit ec106e
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Packit ec106e
*/
Packit ec106e
#include "config.h"
Packit ec106e
Packit ec106e
#include <stdio.h>
Packit ec106e
#include <errno.h>
Packit ec106e
#include <string.h>
Packit ec106e
#include <stdlib.h>
Packit ec106e
#include <unistd.h>
Packit ec106e
#include <fcntl.h>
Packit ec106e
#include <signal.h>
Packit ec106e
#include <sys/vt.h>
Packit ec106e
#include <sys/ioctl.h>
Packit ec106e
#include <sys/wait.h>
Packit ec106e
Packit ec106e
#include "vlock.h"
Packit ec106e
#include "nls.h"
Packit ec106e
#include "kbd_error.h"
Packit ec106e
Packit ec106e
/* Saved VT mode. */
Packit ec106e
struct vt_mode ovtm;
Packit ec106e
Packit ec106e
/* VT descriptor. */
Packit ec106e
static int vfd = -1;
Packit ec106e
Packit ec106e
/* Copy of the VT mode when the program was started. */
Packit ec106e
int is_vt;
Packit ec106e
Packit ec106e
/*
Packit ec106e
 * This is called by a signal whenever a user tries to change
Packit ec106e
 * the VC (with a ALT-Fn key or via VT_ACTIVATE).
Packit ec106e
 */
Packit ec106e
static void
Packit ec106e
release_vt(__attribute__((unused)) int signo)
Packit ec106e
{
Packit ec106e
	/*
Packit ec106e
	 * Kernel is not allowed to switch.
Packit ec106e
	 * Return code is silently ignored.
Packit ec106e
	 */
Packit ec106e
	ioctl(vfd, VT_RELDISP, 0);
Packit ec106e
}
Packit ec106e
Packit ec106e
/* This is called whenever a user switches to that VC. */
Packit ec106e
static void
Packit ec106e
acquire_vt(__attribute__((unused)) int signo)
Packit ec106e
{
Packit ec106e
	/*
Packit ec106e
	 * This call is not currently required under Linux,
Packit ec106e
	 * but it won't hurt, either.
Packit ec106e
	 * Return code is silently ignored.
Packit ec106e
	 */
Packit ec106e
	ioctl(vfd, VT_RELDISP, VT_ACKACQ);
Packit ec106e
}
Packit ec106e
Packit ec106e
/* Set the signal masks and handlers. */
Packit ec106e
static void
Packit ec106e
mask_signals(void)
Packit ec106e
{
Packit ec106e
Packit ec106e
	static sigset_t sig;
Packit ec106e
	static struct sigaction sa;
Packit ec106e
Packit ec106e
	memset(&sa, 0, sizeof sa);
Packit ec106e
	sigemptyset(&(sa.sa_mask));
Packit ec106e
	sa.sa_flags = SA_RESTART;
Packit ec106e
Packit ec106e
	if (o_lock_all) {
Packit ec106e
		/* handle SIGUSR{1,2}... */
Packit ec106e
		sa.sa_handler = release_vt;
Packit ec106e
		sigaction(SIGUSR1, &sa, 0);
Packit ec106e
		sa.sa_handler = acquire_vt;
Packit ec106e
		sigaction(SIGUSR2, &sa, 0);
Packit ec106e
Packit ec106e
		/* ... and ensure they are unblocked. */
Packit ec106e
		sigemptyset(&sig);
Packit ec106e
		sigaddset(&sig, SIGUSR1);
Packit ec106e
		sigaddset(&sig, SIGUSR2);
Packit ec106e
		sigprocmask(SIG_UNBLOCK, &sig, 0);
Packit ec106e
	}
Packit ec106e
Packit ec106e
	/* Ignore all the rest. */
Packit ec106e
	sa.sa_handler = SIG_IGN;
Packit ec106e
	if (!o_lock_all) {
Packit ec106e
		sigaction(SIGUSR1, &sa, 0);
Packit ec106e
		sigaction(SIGUSR2, &sa, 0);
Packit ec106e
	}
Packit ec106e
	sigaction(SIGHUP, &sa, 0);
Packit ec106e
	sigaction(SIGINT, &sa, 0);
Packit ec106e
	sigaction(SIGQUIT, &sa, 0);
Packit ec106e
	sigaction(SIGPIPE, &sa, 0);
Packit ec106e
	sigaction(SIGALRM, &sa, 0);
Packit ec106e
	sigaction(SIGTERM, &sa, 0);
Packit ec106e
	sigaction(SIGTSTP, &sa, 0);
Packit ec106e
	sigaction(SIGTTIN, &sa, 0);
Packit ec106e
	sigaction(SIGTTOU, &sa, 0);
Packit ec106e
	sigaction(SIGURG, &sa, 0);
Packit ec106e
	sigaction(SIGVTALRM, &sa, 0);
Packit ec106e
	sigaction(SIGIO, &sa, 0);
Packit ec106e
	sigaction(SIGPWR, &sa, 0);
Packit ec106e
Packit ec106e
	/*
Packit ec106e
	 * Also block SIGCHLD.
Packit ec106e
	 * Not really needed; just make sleep(3) more easy.
Packit ec106e
	 */
Packit ec106e
	sigemptyset(&sig);
Packit ec106e
	sigaddset(&sig, SIGCHLD);
Packit ec106e
	sigprocmask(SIG_BLOCK, &sig, 0);
Packit ec106e
}
Packit ec106e
Packit ec106e
int init_vt(const char *tty)
Packit ec106e
{
Packit ec106e
	const char dev_tty[] = "/dev/tty";
Packit ec106e
Packit ec106e
	vfd = open(dev_tty, O_RDWR);
Packit ec106e
	if (vfd < 0) {
Packit ec106e
		kbd_warning(errno, "could not open %s", dev_tty);
Packit ec106e
		return 0;
Packit ec106e
	}
Packit ec106e
Packit ec106e
	/*
Packit ec106e
	 * First we will set process control of VC switching.
Packit ec106e
	 * - If this fails, then we know that we aren't on a VC,
Packit ec106e
	 *   and will print a warning message.
Packit ec106e
	 * - If it doesn't fail, it gets the current VT status.
Packit ec106e
	 */
Packit ec106e
	if (ioctl(vfd, VT_GETMODE, &ovtm) < 0) {
Packit ec106e
		is_vt = 0;
Packit ec106e
		fprintf(stderr, _("This tty (%s) is not a virtual console.\n"),
Packit ec106e
		        tty);
Packit ec106e
		if (o_lock_all) {
Packit ec106e
			o_lock_all = 0;
Packit ec106e
			close(vfd);
Packit ec106e
			vfd = -1;
Packit ec106e
			fprintf(stderr,
Packit ec106e
			        _("The entire console display cannot be locked.\n"));
Packit ec106e
			return 0;
Packit ec106e
		}
Packit ec106e
		fprintf(stderr, "\n\n");
Packit ec106e
		fflush(stderr);
Packit ec106e
	} else {
Packit ec106e
		is_vt = 1;
Packit ec106e
	}
Packit ec106e
Packit ec106e
	/* If we aren't going to lock console, we don't need VT descriptor. */
Packit ec106e
	if (!o_lock_all) {
Packit ec106e
		close(vfd);
Packit ec106e
		vfd = -1;
Packit ec106e
	}
Packit ec106e
Packit ec106e
	mask_signals();
Packit ec106e
Packit ec106e
	if (o_lock_all) {
Packit ec106e
		struct vt_mode vtm = ovtm;
Packit ec106e
Packit ec106e
		vtm.mode   = VT_PROCESS; /* Process controls switching. */
Packit ec106e
		vtm.relsig = SIGUSR1;    /* Signal to raise on release request, handled by release_vt(). */
Packit ec106e
		vtm.acqsig = SIGUSR2;    /* Signal to raise on acquisition, handled by acquire_vt(). */
Packit ec106e
Packit ec106e
		/* Set mode of active vt. */
Packit ec106e
		if (ioctl(vfd, VT_SETMODE, &vtm) < 0) {
Packit ec106e
			kbd_warning(errno, "ioctl VT_SETMODE");
Packit ec106e
			return 0;
Packit ec106e
		}
Packit ec106e
	}
Packit ec106e
Packit ec106e
	if (is_vt)
Packit ec106e
		init_screen();
Packit ec106e
Packit ec106e
	return 1;
Packit ec106e
}
Packit ec106e
Packit ec106e
void restore_vt(void)
Packit ec106e
{
Packit ec106e
	if (is_vt) {
Packit ec106e
		restore_screen();
Packit ec106e
Packit ec106e
		if (o_lock_all) {
Packit ec106e
			/*
Packit ec106e
			 * Reset mode of active vt.
Packit ec106e
			 * Don't check return code - it won't help anyway.
Packit ec106e
			 */
Packit ec106e
			ioctl(vfd, VT_SETMODE, &ovtm);
Packit ec106e
		}
Packit ec106e
	}
Packit ec106e
}