/* 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 #include #include #include #include #include #include #include #if defined(__linux) #include #include #elif defined(__FreeBSD_kernel__) #include #include #endif #include #include #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; }