1
0
Fork 0
bash/debian/clear_console.c
Daniel Baumann fc8a52c443
Adding debian version 5.2.37-2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-21 06:49:22 +02:00

291 lines
5.5 KiB
C

/*
Copyright (C) 2006-2019 Canonical Ltd.
clear_console and it's man page are free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2, or (at your
option) any later version.
*/
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#if defined(__linux)
#include <linux/kd.h>
#include <linux/vt.h>
#elif defined(__FreeBSD_kernel__)
#include <sys/consio.h>
#include <sys/kbio.h>
#endif
#include <curses.h>
#include <term.h>
#define VERSION "0.1"
char* progname;
int quiet = 0;
void usage()
{
fprintf(stderr, "Usage: %s [option]\n", progname);
fprintf(stderr, "valid options are:\n");
fprintf(stderr, "\t-q --quiet don't print error messages\n");
fprintf(stderr, "\t-h --help display this help text and exit\n");
fprintf(stderr, "\t-V --version display version information and exit\n");
}
const struct option opts[] =
{
/* operations */
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{"quiet", no_argument, 0, 'q'},
{0, 0, 0, 0}
};
static int putch(int c)
{
return putchar(c);
}
/* taken from console-utils, lib/misc-console-utils.c */
int is_a_console(int fd)
{
#if defined(__linux__)
char arg;
#elif defined(__FreeBSD_kernel__)
int arg;
#endif
arg = 0;
return (ioctl(fd, KDGKBTYPE, &arg) == 0
&& ((arg == KB_OTHER) || (arg == KB_101) || (arg == KB_84)));
}
static int open_a_console(char *fnam)
{
int fd;
/* try read-only */
fd = open(fnam, O_RDWR);
/* if failed, try read-only */
if (fd < 0 && errno == EACCES)
fd = open(fnam, O_RDONLY);
/* if failed, try write-only */
if (fd < 0 && errno == EACCES)
fd = open(fnam, O_WRONLY);
/* if failed, fail */
if (fd < 0)
return -1;
/* if not a console, fail */
if (! is_a_console(fd))
{
close(fd);
return -1;
}
/* success */
return fd;
}
/*
* Get an fd for use with kbd/console ioctls.
* We try several things because opening /dev/console will fail
* if someone else used X (which does a chown on /dev/console).
*
* if tty_name is non-NULL, try this one instead.
*/
int get_console_fd(char* tty_name)
{
int fd;
if (tty_name)
{
if (-1 == (fd = open_a_console(tty_name)))
return -1;
else
return fd;
}
fd = open_a_console("/dev/tty");
if (fd >= 0)
return fd;
fd = open_a_console("/dev/tty0");
if (fd >= 0)
return fd;
fd = open_a_console("/dev/console");
if (fd >= 0)
return fd;
for (fd = 0; fd < 3; fd++)
if (is_a_console(fd))
return fd;
#if 0
fprintf(stderr,
_("Couldnt get a file descriptor referring to the console\n"));
#endif
return -1; /* total failure */
}
int is_pseudo_tty(int fd)
{
char *tty = ttyname(fd);
if (!tty)
{
if (!quiet)
perror("ttyname");
return 0;
}
if (strlen(tty) >= 9 && !strncmp(tty, "/dev/pts/", 9))
return 1;
if (strlen(tty) >= 8 && !strncmp(tty, "/dev/tty", 8)
&& tty[8] >= 'a' && tty[8] <= 'z')
return 1;
return 0;
}
int clear_console(int fd)
{
int num, tmp_num;
#if defined(__linux__)
struct vt_stat vtstat;
#endif
/* Linux console secure erase (since 2.6.39), this is sufficient there;
other terminals silently ignore this code. If they don't and write junk
instead, well, we're clearing the screen anyway.
*/
write(1, "\e[3J", 4);
/* clear screen */
setupterm((char *) 0, 1, (int *) 0);
if (tputs(clear_screen, lines > 0 ? lines : 1, putch) == ERR)
{
exit(1);
}
if (is_pseudo_tty(STDIN_FILENO))
return 0;
if (!strcmp(getenv("TERM"), "screen"))
return 0;
/* get current vt */
#if defined(__linux__)
if (ioctl(fd, VT_GETSTATE, &vtstat) < 0)
#elif defined(__FreeBSD_kernel__)
if (ioctl(fd, VT_ACTIVATE, &num) < 0)
#endif
{
if (!quiet)
fprintf(stderr, "%s: cannot get VTstate\n", progname);
exit(1);
}
#if defined(__linux__)
num = vtstat.v_active;
#endif
tmp_num = (num == 6 ? 5 : 6);
/* switch vt to clear the scrollback buffer */
if (ioctl(fd, VT_ACTIVATE, tmp_num))
{
if (!quiet)
perror("chvt: VT_ACTIVATE");
exit(1);
}
if (ioctl(fd, VT_WAITACTIVE, tmp_num))
{
if (!quiet)
perror("VT_WAITACTIVE");
exit(1);
}
/* switch back */
if (ioctl(fd, VT_ACTIVATE, num))
{
if (!quiet)
perror("chvt: VT_ACTIVATE");
exit(1);
}
if (ioctl(fd, VT_WAITACTIVE, num))
{
if (!quiet)
perror("VT_WAITACTIVE");
exit(1);
}
return 0;
}
int main (int argc, char* argv[])
{
int fd;
int result; /* option handling */
int an_option;
if ((progname = strrchr(argv[0], '/')) == NULL)
progname = argv[0];
else
progname++;
while (1)
{
result = getopt_long(argc, argv, "Vhq", opts, &an_option);
if (result == EOF)
break;
switch (result)
{
case 'V':
fprintf(stdout, "%s: Version %s\n", progname, VERSION);
exit (0);
case 'h':
usage();
exit (0);
case 'q':
quiet = 1;
}
}
if (optind < argc)
{
if (!quiet)
fprintf(stderr, "%s: no non-option arguments are valid", progname);
exit(1);
}
if ((fd = get_console_fd(NULL)) == -1)
{
if (!quiet)
fprintf(stderr, "%s: terminal is not a console\n", progname);
exit(1);
}
clear_console(fd);
return 0;
}