vidcontrol.c revision 146736
1/*- 2 * Copyright (c) 1994-1996 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Portions of this software are based in part on the work of 6 * Sascha Wildner <saw@online.de> contributed to The DragonFly Project 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer, 13 * in this position and unchanged. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * $DragonFly: src/usr.sbin/vidcontrol/vidcontrol.c,v 1.10 2005/03/02 06:08:29 joerg Exp $ 32 */ 33 34#ifndef lint 35static const char rcsid[] = 36 "$FreeBSD: head/usr.sbin/vidcontrol/vidcontrol.c 146736 2005-05-29 08:43:44Z delphij $"; 37#endif /* not lint */ 38 39#include <ctype.h> 40#include <err.h> 41#include <limits.h> 42#include <stdio.h> 43#include <stdlib.h> 44#include <string.h> 45#include <unistd.h> 46#include <sys/fbio.h> 47#include <sys/consio.h> 48#include <sys/errno.h> 49#include <sys/types.h> 50#include <sys/stat.h> 51#include "path.h" 52#include "decode.h" 53 54 55#define DATASIZE(x) ((x).w * (x).h * 256 / 8) 56 57/* Screen dump modes */ 58#define DUMP_FMT_RAW 1 59#define DUMP_FMT_TXT 2 60/* Screen dump options */ 61#define DUMP_FBF 0 62#define DUMP_ALL 1 63/* Screen dump file format revision */ 64#define DUMP_FMT_REV 1 65 66char legal_colors[16][16] = { 67 "black", "blue", "green", "cyan", 68 "red", "magenta", "brown", "white", 69 "grey", "lightblue", "lightgreen", "lightcyan", 70 "lightred", "lightmagenta", "yellow", "lightwhite" 71}; 72 73struct { 74 int active_vty; 75 vid_info_t console_info; 76 unsigned char screen_map[256]; 77 int video_mode_number; 78 struct video_info video_mode_info; 79} cur_info; 80 81int hex = 0; 82int number; 83int vesa_cols; 84int vesa_rows; 85int font_height; 86int colors_changed; 87int video_mode_changed; 88int normal_fore_color, normal_back_color; 89int revers_fore_color, revers_back_color; 90char letter; 91struct vid_info info; 92struct video_info new_mode_info; 93 94 95/* 96 * Initialize revert data. 97 * 98 * NOTE: the following parameters are not yet saved/restored: 99 * 100 * screen saver timeout 101 * cursor type 102 * mouse character and mouse show/hide state 103 * vty switching on/off state 104 * history buffer size 105 * history contents 106 * font maps 107 */ 108 109static void 110init(void) 111{ 112 if (ioctl(0, VT_GETACTIVE, &cur_info.active_vty) == -1) 113 errc(1, errno, "getting active vty"); 114 115 cur_info.console_info.size = sizeof(cur_info.console_info); 116 117 if (ioctl(0, CONS_GETINFO, &cur_info.console_info) == -1) 118 errc(1, errno, "getting console information"); 119 120 if (ioctl(0, GIO_SCRNMAP, &cur_info.screen_map) == -1) 121 errc(1, errno, "getting screen map"); 122 123 if (ioctl(0, CONS_GET, &cur_info.video_mode_number) == -1) 124 errc(1, errno, "getting video mode number"); 125 126 cur_info.video_mode_info.vi_mode = cur_info.video_mode_number; 127 128 if (ioctl(0, CONS_MODEINFO, &cur_info.video_mode_info) == -1) 129 errc(1, errno, "getting video mode parameters"); 130 131 normal_fore_color = cur_info.console_info.mv_norm.fore; 132 normal_back_color = cur_info.console_info.mv_norm.back; 133 revers_fore_color = cur_info.console_info.mv_rev.fore; 134 revers_back_color = cur_info.console_info.mv_rev.back; 135} 136 137 138/* 139 * If something goes wrong along the way we call revert() to go back to the 140 * console state we came from (which is assumed to be working). 141 * 142 * NOTE: please also read the comments of init(). 143 */ 144 145static void 146revert(void) 147{ 148 int size[3]; 149 150 ioctl(0, VT_ACTIVATE, (caddr_t) (long) cur_info.active_vty); 151 152 fprintf(stderr, "\033[=%dA", cur_info.console_info.mv_ovscan); 153 fprintf(stderr, "\033[=%dF", cur_info.console_info.mv_norm.fore); 154 fprintf(stderr, "\033[=%dG", cur_info.console_info.mv_norm.back); 155 fprintf(stderr, "\033[=%dH", cur_info.console_info.mv_rev.fore); 156 fprintf(stderr, "\033[=%dI", cur_info.console_info.mv_rev.back); 157 158 ioctl(0, PIO_SCRNMAP, &cur_info.screen_map); 159 160 if (cur_info.video_mode_number >= M_VESA_BASE) 161 ioctl(0, _IO('V', cur_info.video_mode_number - M_VESA_BASE), 162 NULL); 163 else 164 ioctl(0, _IO('S', cur_info.video_mode_number), NULL); 165 166 if (cur_info.video_mode_info.vi_flags & V_INFO_GRAPHICS) { 167 size[0] = cur_info.video_mode_info.vi_width / 8; 168 size[1] = cur_info.video_mode_info.vi_height / 169 cur_info.console_info.font_size; 170 size[2] = cur_info.console_info.font_size; 171 172 ioctl(0, KDRASTER, size); 173 } 174} 175 176 177/* 178 * Print a short usage string describing all options, then exit. 179 */ 180 181static void 182usage(void) 183{ 184 fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", 185"usage: vidcontrol [-CdHLPpx] [-b color] [-c appearance] [-f [size] file]", 186" [-g geometry] [-h size] [-i adapter | mode] [-l screen_map]", 187" [-M char] [-m on | off] [-r foreground background]", 188" [-S on | off] [-s number] [-t N | off] [mode]", 189" [foreground [background]] [show]"); 190 exit(1); 191} 192 193 194/* 195 * Retrieve the next argument from the command line (for options that require 196 * more than one argument). 197 */ 198 199static char * 200nextarg(int ac, char **av, int *indp, int oc, int strict) 201{ 202 if (*indp < ac) 203 return(av[(*indp)++]); 204 205 if (strict != 0) { 206 revert(); 207 errx(1, "option requires two arguments -- %c", oc); 208 } 209 210 return(NULL); 211} 212 213 214/* 215 * Guess which file to open. Try to open each combination of a specified set 216 * of file name components. 217 */ 218 219static FILE * 220openguess(const char *a[], const char *b[], const char *c[], const char *d[], char **name) 221{ 222 FILE *f; 223 int i, j, k, l; 224 225 for (i = 0; a[i] != NULL; i++) { 226 for (j = 0; b[j] != NULL; j++) { 227 for (k = 0; c[k] != NULL; k++) { 228 for (l = 0; d[l] != NULL; l++) { 229 asprintf(name, "%s%s%s%s", 230 a[i], b[j], c[k], d[l]); 231 232 f = fopen(*name, "r"); 233 234 if (f != NULL) 235 return (f); 236 237 free(*name); 238 } 239 } 240 } 241 } 242 return (NULL); 243} 244 245 246/* 247 * Load a screenmap from a file and set it. 248 */ 249 250static void 251load_scrnmap(const char *filename) 252{ 253 FILE *fd; 254 int size; 255 char *name; 256 scrmap_t scrnmap; 257 const char *a[] = {"", SCRNMAP_PATH, NULL}; 258 const char *b[] = {filename, NULL}; 259 const char *c[] = {"", ".scm", NULL}; 260 const char *d[] = {"", NULL}; 261 262 fd = openguess(a, b, c, d, &name); 263 264 if (fd == NULL) { 265 revert(); 266 errx(1, "screenmap file not found"); 267 } 268 269 size = sizeof(scrnmap); 270 271 if (decode(fd, (char *)&scrnmap, size) != size) { 272 rewind(fd); 273 274 if (fread(&scrnmap, 1, size, fd) != (size_t)size) { 275 warnx("bad screenmap file"); 276 fclose(fd); 277 revert(); 278 errx(1, "bad screenmap file"); 279 } 280 } 281 282 if (ioctl(0, PIO_SCRNMAP, &scrnmap) == -1) { 283 revert(); 284 errc(1, errno, "loading screenmap"); 285 } 286 287 fclose(fd); 288} 289 290 291/* 292 * Set the default screenmap. 293 */ 294 295static void 296load_default_scrnmap(void) 297{ 298 scrmap_t scrnmap; 299 int i; 300 301 for (i=0; i<256; i++) 302 *((char*)&scrnmap + i) = i; 303 304 if (ioctl(0, PIO_SCRNMAP, &scrnmap) == -1) { 305 revert(); 306 errc(1, errno, "loading default screenmap"); 307 } 308} 309 310 311/* 312 * Print the current screenmap to stdout. 313 */ 314 315static void 316print_scrnmap(void) 317{ 318 unsigned char map[256]; 319 size_t i; 320 321 if (ioctl(0, GIO_SCRNMAP, &map) == -1) { 322 revert(); 323 errc(1, errno, "getting screenmap"); 324 } 325 for (i=0; i<sizeof(map); i++) { 326 if (i != 0 && i % 16 == 0) 327 fprintf(stdout, "\n"); 328 329 if (hex != 0) 330 fprintf(stdout, " %02x", map[i]); 331 else 332 fprintf(stdout, " %03d", map[i]); 333 } 334 fprintf(stdout, "\n"); 335 336} 337 338 339/* 340 * Determine a file's size. 341 */ 342 343static int 344fsize(FILE *file) 345{ 346 struct stat sb; 347 348 if (fstat(fileno(file), &sb) == 0) 349 return sb.st_size; 350 else 351 return -1; 352} 353 354 355/* 356 * Load a font from file and set it. 357 */ 358 359static void 360load_font(const char *type, const char *filename) 361{ 362 FILE *fd; 363 int h, i, size, w; 364 unsigned long io = 0; /* silence stupid gcc(1) in the Wall mode */ 365 char *name, *fontmap, size_sufx[6]; 366 const char *a[] = {"", FONT_PATH, NULL}; 367 const char *b[] = {filename, NULL}; 368 const char *c[] = {"", size_sufx, NULL}; 369 const char *d[] = {"", ".fnt", NULL}; 370 vid_info_t _info; 371 372 struct sizeinfo { 373 int w; 374 int h; 375 unsigned long io; 376 } sizes[] = {{8, 16, PIO_FONT8x16}, 377 {8, 14, PIO_FONT8x14}, 378 {8, 8, PIO_FONT8x8}, 379 {0, 0, 0}}; 380 381 _info.size = sizeof(_info); 382 if (ioctl(0, CONS_GETINFO, &_info) == -1) { 383 revert(); 384 warn("failed to obtain current video mode parameters"); 385 return; 386 } 387 388 snprintf(size_sufx, sizeof(size_sufx), "-8x%d", _info.font_size); 389 fd = openguess(a, b, c, d, &name); 390 391 if (fd == NULL) { 392 revert(); 393 errx(1, "%s: can't load font file", filename); 394 } 395 396 if (type != NULL) { 397 size = 0; 398 if (sscanf(type, "%dx%d", &w, &h) == 2) { 399 for (i = 0; sizes[i].w != 0; i++) { 400 if (sizes[i].w == w && sizes[i].h == h) { 401 size = DATASIZE(sizes[i]); 402 io = sizes[i].io; 403 font_height = sizes[i].h; 404 } 405 } 406 } 407 if (size == 0) { 408 fclose(fd); 409 revert(); 410 errx(1, "%s: bad font size specification", type); 411 } 412 } else { 413 /* Apply heuristics */ 414 415 int j; 416 int dsize[2]; 417 418 size = DATASIZE(sizes[0]); 419 fontmap = (char*) malloc(size); 420 dsize[0] = decode(fd, fontmap, size); 421 dsize[1] = fsize(fd); 422 free(fontmap); 423 424 size = 0; 425 for (j = 0; j < 2; j++) { 426 for (i = 0; sizes[i].w != 0; i++) { 427 if (DATASIZE(sizes[i]) == dsize[j]) { 428 size = dsize[j]; 429 io = sizes[i].io; 430 font_height = sizes[i].h; 431 j = 2; /* XXX */ 432 break; 433 } 434 } 435 } 436 437 if (size == 0) { 438 fclose(fd); 439 revert(); 440 errx(1, "%s: can't guess font size", filename); 441 } 442 443 rewind(fd); 444 } 445 446 fontmap = (char*) malloc(size); 447 448 if (decode(fd, fontmap, size) != size) { 449 rewind(fd); 450 if (fsize(fd) != size || 451 fread(fontmap, 1, size, fd) != (size_t)size) { 452 warnx("%s: bad font file", filename); 453 fclose(fd); 454 free(fontmap); 455 revert(); 456 errx(1, "%s: bad font file", filename); 457 } 458 } 459 460 if (ioctl(0, io, fontmap) == -1) { 461 revert(); 462 errc(1, errno, "loading font"); 463 } 464 465 fclose(fd); 466 free(fontmap); 467} 468 469 470/* 471 * Set the timeout for the screensaver. 472 */ 473 474static void 475set_screensaver_timeout(char *arg) 476{ 477 int nsec; 478 479 if (!strcmp(arg, "off")) { 480 nsec = 0; 481 } else { 482 nsec = atoi(arg); 483 484 if ((*arg == '\0') || (nsec < 1)) { 485 revert(); 486 errx(1, "argument must be a positive number"); 487 } 488 } 489 490 if (ioctl(0, CONS_BLANKTIME, &nsec) == -1) { 491 revert(); 492 errc(1, errno, "setting screensaver period"); 493 } 494} 495 496 497/* 498 * Set the cursor's shape/type. 499 */ 500 501static void 502set_cursor_type(char *appearence) 503{ 504 int type; 505 506 if (!strcmp(appearence, "normal")) 507 type = 0; 508 else if (!strcmp(appearence, "blink")) 509 type = 1; 510 else if (!strcmp(appearence, "destructive")) 511 type = 3; 512 else { 513 revert(); 514 errx(1, "argument to -c must be normal, blink or destructive"); 515 } 516 517 if (ioctl(0, CONS_CURSORTYPE, &type) == -1) { 518 revert(); 519 errc(1, errno, "setting cursor type"); 520 } 521} 522 523 524/* 525 * Set the video mode. 526 */ 527 528static int 529video_mode(int argc, char **argv, int *mode_index) 530{ 531 static struct { 532 const char *name; 533 unsigned long mode; 534 unsigned long mode_num; 535 } modes[] = { 536 { "80x25", SW_TEXT_80x25, M_TEXT_80x25 }, 537 { "80x30", SW_TEXT_80x30, M_TEXT_80x30 }, 538 { "80x43", SW_TEXT_80x43, M_TEXT_80x43 }, 539 { "80x50", SW_TEXT_80x50, M_TEXT_80x50 }, 540 { "80x60", SW_TEXT_80x60, M_TEXT_80x60 }, 541 { "132x25", SW_TEXT_132x25, M_TEXT_132x25 }, 542 { "132x30", SW_TEXT_132x30, M_TEXT_132x30 }, 543 { "132x43", SW_TEXT_132x43, M_TEXT_132x43 }, 544 { "132x50", SW_TEXT_132x50, M_TEXT_132x50 }, 545 { "132x60", SW_TEXT_132x60, M_TEXT_132x60 }, 546 { "VGA_40x25", SW_VGA_C40x25, M_VGA_C40x25 }, 547 { "VGA_80x25", SW_VGA_C80x25, M_VGA_C80x25 }, 548 { "VGA_80x30", SW_VGA_C80x30, M_VGA_C80x30 }, 549 { "VGA_80x50", SW_VGA_C80x50, M_VGA_C80x50 }, 550 { "VGA_80x60", SW_VGA_C80x60, M_VGA_C80x60 }, 551#ifdef SW_VGA_C90x25 552 { "VGA_90x25", SW_VGA_C90x25, M_VGA_C90x25 }, 553 { "VGA_90x30", SW_VGA_C90x30, M_VGA_C90x30 }, 554 { "VGA_90x43", SW_VGA_C90x43, M_VGA_C90x43 }, 555 { "VGA_90x50", SW_VGA_C90x50, M_VGA_C90x50 }, 556 { "VGA_90x60", SW_VGA_C90x60, M_VGA_C90x60 }, 557#endif 558 { "VGA_320x200", SW_VGA_CG320, M_CG320 }, 559 { "EGA_80x25", SW_ENH_C80x25, M_ENH_C80x25 }, 560 { "EGA_80x43", SW_ENH_C80x43, M_ENH_C80x43 }, 561 { "VESA_132x25", SW_VESA_C132x25,M_VESA_C132x25 }, 562 { "VESA_132x43", SW_VESA_C132x43,M_VESA_C132x43 }, 563 { "VESA_132x50", SW_VESA_C132x50,M_VESA_C132x50 }, 564 { "VESA_132x60", SW_VESA_C132x60,M_VESA_C132x60 }, 565 { "VESA_800x600", SW_VESA_800x600,M_VESA_800x600 }, 566 { NULL, 0, 0 }, 567 }; 568 569 int new_mode_num = 0; 570 unsigned long mode = 0; 571 int cur_mode; 572 int ioerr; 573 int size[3]; 574 int i; 575 576 if (ioctl(0, CONS_GET, &cur_mode) < 0) 577 err(1, "cannot get the current video mode"); 578 579 /* 580 * Parse the video mode argument... 581 */ 582 583 if (*mode_index < argc) { 584 if (!strncmp(argv[*mode_index], "MODE_", 5)) { 585 if (!isdigit(argv[*mode_index][5])) 586 errx(1, "invalid video mode number"); 587 588 new_mode_num = atoi(&argv[*mode_index][5]); 589 } else { 590 for (i = 0; modes[i].name != NULL; ++i) { 591 if (!strcmp(argv[*mode_index], modes[i].name)) { 592 mode = modes[i].mode; 593 new_mode_num = modes[i].mode_num; 594 break; 595 } 596 } 597 598 if (modes[i].name == NULL) 599 return EXIT_FAILURE; 600 if (ioctl(0, mode, NULL) < 0) { 601 warn("cannot set videomode"); 602 return EXIT_FAILURE; 603 } 604 } 605 606 /* 607 * Collect enough information about the new video mode... 608 */ 609 610 new_mode_info.vi_mode = new_mode_num; 611 612 if (ioctl(0, CONS_MODEINFO, &new_mode_info) == -1) { 613 revert(); 614 errc(1, errno, "obtaining new video mode parameters"); 615 } 616 617 if (mode == 0) { 618 if (new_mode_num >= M_VESA_BASE) 619 mode = _IO('V', new_mode_num - M_VESA_BASE); 620 else 621 mode = _IO('S', new_mode_num); 622 } 623 624 /* 625 * Try setting the new mode. 626 */ 627 628 if (ioctl(0, mode, NULL) == -1) { 629 revert(); 630 errc(1, errno, "setting video mode"); 631 } 632 633 /* 634 * For raster modes it's not enough to just set the mode. 635 * We also need to explicitly set the raster mode. 636 */ 637 638 if (new_mode_info.vi_flags & V_INFO_GRAPHICS) { 639 /* font size */ 640 641 if (font_height == 0) 642 font_height = cur_info.console_info.font_size; 643 644 size[2] = font_height; 645 646 /* adjust columns */ 647 648 if ((vesa_cols * 8 > new_mode_info.vi_width) || 649 (vesa_cols <= 0)) { 650 size[0] = new_mode_info.vi_width / 8; 651 } else { 652 size[0] = vesa_cols; 653 } 654 655 /* adjust rows */ 656 657 if ((vesa_rows * font_height > new_mode_info.vi_height) || 658 (vesa_rows <= 0)) { 659 size[1] = new_mode_info.vi_height / 660 font_height; 661 } else { 662 size[1] = vesa_rows; 663 } 664 665 /* set raster mode */ 666 667 if (ioctl(0, KDRASTER, size)) { 668 ioerr = errno; 669 if (cur_mode >= M_VESA_BASE) 670 ioctl(0, 671 _IO('V', cur_mode - M_VESA_BASE), 672 NULL); 673 else 674 ioctl(0, _IO('S', cur_mode), NULL); 675 revert(); 676 warnc(ioerr, "cannot activate raster display"); 677 return EXIT_FAILURE; 678 } 679 } 680 681 video_mode_changed = 1; 682 683 (*mode_index)++; 684 } 685 return EXIT_SUCCESS; 686} 687 688 689/* 690 * Return the number for a specified color name. 691 */ 692 693static int 694get_color_number(char *color) 695{ 696 int i; 697 698 for (i=0; i<16; i++) { 699 if (!strcmp(color, legal_colors[i])) 700 return i; 701 } 702 return -1; 703} 704 705 706/* 707 * Get normal text and background colors. 708 */ 709 710static void 711get_normal_colors(int argc, char **argv, int *_index) 712{ 713 int color; 714 715 if (*_index < argc && (color = get_color_number(argv[*_index])) != -1) { 716 (*_index)++; 717 fprintf(stderr, "\033[=%dF", color); 718 if (*_index < argc 719 && (color = get_color_number(argv[*_index])) != -1 720 && color < 8) { 721 (*_index)++; 722 fprintf(stderr, "\033[=%dG", color); 723 } 724 } 725} 726 727 728/* 729 * Get reverse text and background colors. 730 */ 731 732static void 733get_reverse_colors(int argc, char **argv, int *_index) 734{ 735 int color; 736 737 if ((color = get_color_number(argv[*(_index)-1])) != -1) { 738 fprintf(stderr, "\033[=%dH", color); 739 if (*_index < argc 740 && (color = get_color_number(argv[*_index])) != -1 741 && color < 8) { 742 (*_index)++; 743 fprintf(stderr, "\033[=%dI", color); 744 } 745 } 746} 747 748 749/* 750 * Set normal and reverse foreground and background colors. 751 */ 752 753static void 754set_colors(void) 755{ 756 fprintf(stderr, "\033[=%dF", normal_fore_color); 757 fprintf(stderr, "\033[=%dG", normal_back_color); 758 fprintf(stderr, "\033[=%dH", revers_fore_color); 759 fprintf(stderr, "\033[=%dI", revers_back_color); 760} 761 762 763/* 764 * Switch to virtual terminal #arg. 765 */ 766 767static void 768set_console(char *arg) 769{ 770 int n; 771 772 if(!arg || strspn(arg,"0123456789") != strlen(arg)) { 773 revert(); 774 errx(1, "bad console number"); 775 } 776 777 n = atoi(arg); 778 779 if (n < 1 || n > 16) { 780 revert(); 781 errx(1, "console number out of range"); 782 } else if (ioctl(0, VT_ACTIVATE, (caddr_t) (long) n) == -1) { 783 revert(); 784 errc(1, errno, "switching vty"); 785 } 786} 787 788 789/* 790 * Sets the border color. 791 */ 792 793static void 794set_border_color(char *arg) 795{ 796 int color; 797 798 if ((color = get_color_number(arg)) != -1) { 799 fprintf(stderr, "\033[=%dA", color); 800 } 801 else 802 usage(); 803} 804 805static void 806set_mouse_char(char *arg) 807{ 808 struct mouse_info mouse; 809 long l; 810 811 l = strtol(arg, NULL, 0); 812 813 if ((l < 0) || (l > UCHAR_MAX - 3)) { 814 revert(); 815 warnx("argument to -M must be 0 through %d", UCHAR_MAX - 3); 816 return; 817 } 818 819 mouse.operation = MOUSE_MOUSECHAR; 820 mouse.u.mouse_char = (int)l; 821 822 if (ioctl(0, CONS_MOUSECTL, &mouse) == -1) { 823 revert(); 824 errc(1, errno, "setting mouse character"); 825 } 826} 827 828 829/* 830 * Show/hide the mouse. 831 */ 832 833static void 834set_mouse(char *arg) 835{ 836 struct mouse_info mouse; 837 838 if (!strcmp(arg, "on")) { 839 mouse.operation = MOUSE_SHOW; 840 } else if (!strcmp(arg, "off")) { 841 mouse.operation = MOUSE_HIDE; 842 } else { 843 revert(); 844 errx(1, "argument to -m must be either on or off"); 845 } 846 847 if (ioctl(0, CONS_MOUSECTL, &mouse) == -1) { 848 revert(); 849 errc(1, errno, "%sing the mouse", 850 mouse.operation == MOUSE_SHOW ? "show" : "hid"); 851 } 852} 853 854 855static void 856set_lockswitch(char *arg) 857{ 858 int data; 859 860 if (!strcmp(arg, "off")) { 861 data = 0x01; 862 } else if (!strcmp(arg, "on")) { 863 data = 0x02; 864 } else { 865 revert(); 866 errx(1, "argument to -S must be either on or off"); 867 } 868 869 if (ioctl(0, VT_LOCKSWITCH, &data) == -1) { 870 revert(); 871 errc(1, errno, "turning %s vty switching", 872 data == 0x01 ? "off" : "on"); 873 } 874} 875 876 877/* 878 * Return the adapter name for a specified type. 879 */ 880 881static const char 882*adapter_name(int type) 883{ 884 static struct { 885 int type; 886 const char *name; 887 } names[] = { 888 { KD_MONO, "MDA" }, 889 { KD_HERCULES, "Hercules" }, 890 { KD_CGA, "CGA" }, 891 { KD_EGA, "EGA" }, 892 { KD_VGA, "VGA" }, 893 { KD_PC98, "PC-98xx" }, 894 { KD_TGA, "TGA" }, 895 { -1, "Unknown" }, 896 }; 897 898 int i; 899 900 for (i = 0; names[i].type != -1; ++i) 901 if (names[i].type == type) 902 break; 903 return names[i].name; 904} 905 906 907/* 908 * Show graphics adapter information. 909 */ 910 911static void 912show_adapter_info(void) 913{ 914 struct video_adapter_info ad; 915 916 ad.va_index = 0; 917 918 if (ioctl(0, CONS_ADPINFO, &ad) == -1) { 919 revert(); 920 errc(1, errno, "obtaining adapter information"); 921 } 922 923 printf("fb%d:\n", ad.va_index); 924 printf(" %.*s%d, type:%s%s (%d), flags:0x%x\n", 925 (int)sizeof(ad.va_name), ad.va_name, ad.va_unit, 926 (ad.va_flags & V_ADP_VESA) ? "VESA " : "", 927 adapter_name(ad.va_type), ad.va_type, ad.va_flags); 928 printf(" initial mode:%d, current mode:%d, BIOS mode:%d\n", 929 ad.va_initial_mode, ad.va_mode, ad.va_initial_bios_mode); 930 printf(" frame buffer window:0x%zx, buffer size:0x%zx\n", 931 ad.va_window, ad.va_buffer_size); 932 printf(" window size:0x%zx, origin:0x%x\n", 933 ad.va_window_size, ad.va_window_orig); 934 printf(" display start address (%d, %d), scan line width:%d\n", 935 ad.va_disp_start.x, ad.va_disp_start.y, ad.va_line_width); 936 printf(" reserved:0x%zx\n", ad.va_unused0); 937} 938 939 940/* 941 * Show video mode information. 942 */ 943 944static void 945show_mode_info(void) 946{ 947 struct video_info _info; 948 char buf[80]; 949 int mode; 950 int c; 951 952 printf(" mode# flags type size " 953 "font window linear buffer\n"); 954 printf("---------------------------------------" 955 "---------------------------------------\n"); 956 957 for (mode = 0; mode < M_VESA_MODE_MAX; ++mode) { 958 _info.vi_mode = mode; 959 if (ioctl(0, CONS_MODEINFO, &_info)) 960 continue; 961 if (_info.vi_mode != mode) 962 continue; 963 964 printf("%3d (0x%03x)", mode, mode); 965 printf(" 0x%08x", _info.vi_flags); 966 if (_info.vi_flags & V_INFO_GRAPHICS) { 967 c = 'G'; 968 969 snprintf(buf, sizeof(buf), "%dx%dx%d %d", 970 _info.vi_width, _info.vi_height, 971 _info.vi_depth, _info.vi_planes); 972 } else { 973 c = 'T'; 974 975 snprintf(buf, sizeof(buf), "%dx%d", 976 _info.vi_width, _info.vi_height); 977 } 978 979 printf(" %c %-15s", c, buf); 980 snprintf(buf, sizeof(buf), "%dx%d", 981 _info.vi_cwidth, _info.vi_cheight); 982 printf(" %-5s", buf); 983 printf(" 0x%05zx %2dk %2dk", 984 _info.vi_window, (int)_info.vi_window_size/1024, 985 (int)_info.vi_window_gran/1024); 986 printf(" 0x%08zx %dk\n", 987 _info.vi_buffer, (int)_info.vi_buffer_size/1024); 988 } 989} 990 991 992static void 993show_info(char *arg) 994{ 995 if (!strcmp(arg, "adapter")) { 996 show_adapter_info(); 997 } else if (!strcmp(arg, "mode")) { 998 show_mode_info(); 999 } else { 1000 revert(); 1001 errx(1, "argument to -i must be either adapter or mode"); 1002 } 1003} 1004 1005 1006static void 1007test_frame(void) 1008{ 1009 int i, cur_mode, fore; 1010 1011 fore = 15; 1012 1013 if (ioctl(0, CONS_GET, &cur_mode) < 0) 1014 err(1, "must be on a virtual console"); 1015 switch (cur_mode) { 1016 case M_PC98_80x25: 1017 case M_PC98_80x30: 1018 fore = 7; 1019 break; 1020 } 1021 1022 fprintf(stdout, "\033[=0G\n\n"); 1023 for (i=0; i<8; i++) { 1024 fprintf(stdout, "\033[=%dF\033[=0G %2d \033[=%dF%-16s" 1025 "\033[=%dF\033[=0G %2d \033[=%dF%-16s " 1026 "\033[=%dF %2d \033[=%dGBACKGROUND\033[=0G\n", 1027 fore, i, i, legal_colors[i], 1028 fore, i+8, i+8, legal_colors[i+8], 1029 fore, i, i); 1030 } 1031 fprintf(stdout, "\033[=%dF\033[=%dG\033[=%dH\033[=%dI\n", 1032 info.mv_norm.fore, info.mv_norm.back, 1033 info.mv_rev.fore, info.mv_rev.back); 1034} 1035 1036 1037/* 1038 * Snapshot the video memory of that terminal, using the CONS_SCRSHOT 1039 * ioctl, and writes the results to stdout either in the special 1040 * binary format (see manual page for details), or in the plain 1041 * text format. 1042 */ 1043 1044static void 1045dump_screen(int mode, int opt) 1046{ 1047 scrshot_t shot; 1048 vid_info_t _info; 1049 1050 _info.size = sizeof(_info); 1051 1052 if (ioctl(0, CONS_GETINFO, &_info) == -1) { 1053 revert(); 1054 errc(1, errno, "obtaining current video mode parameters"); 1055 return; 1056 } 1057 1058 shot.x = shot.y = 0; 1059 shot.xsize = _info.mv_csz; 1060 shot.ysize = _info.mv_rsz; 1061 if (opt == DUMP_ALL) 1062 shot.ysize += _info.mv_hsz; 1063 1064 shot.buf = alloca(shot.xsize * shot.ysize * sizeof(u_int16_t)); 1065 if (shot.buf == NULL) { 1066 revert(); 1067 errx(1, "failed to allocate memory for dump"); 1068 } 1069 1070 if (ioctl(0, CONS_SCRSHOT, &shot) == -1) { 1071 revert(); 1072 errc(1, errno, "dumping screen"); 1073 } 1074 1075 if (mode == DUMP_FMT_RAW) { 1076 printf("SCRSHOT_%c%c%c%c", DUMP_FMT_REV, 2, 1077 shot.xsize, shot.ysize); 1078 1079 fflush(stdout); 1080 1081 write(STDOUT_FILENO, shot.buf, 1082 shot.xsize * shot.ysize * sizeof(u_int16_t)); 1083 } else { 1084 char *line; 1085 int x, y; 1086 u_int16_t ch; 1087 1088 line = alloca(shot.xsize + 1); 1089 1090 if (line == NULL) { 1091 revert(); 1092 errx(1, "failed to allocate memory for line buffer"); 1093 } 1094 1095 for (y = 0; y < shot.ysize; y++) { 1096 for (x = 0; x < shot.xsize; x++) { 1097 ch = shot.buf[x + (y * shot.xsize)]; 1098 ch &= 0xff; 1099 1100 if (isprint(ch) == 0) 1101 ch = ' '; 1102 1103 line[x] = (char)ch; 1104 } 1105 1106 /* Trim trailing spaces */ 1107 1108 do { 1109 line[x--] = '\0'; 1110 } while (line[x] == ' ' && x != 0); 1111 1112 puts(line); 1113 } 1114 1115 fflush(stdout); 1116 } 1117} 1118 1119 1120/* 1121 * Set the console history buffer size. 1122 */ 1123 1124static void 1125set_history(char *opt) 1126{ 1127 int size; 1128 1129 size = atoi(opt); 1130 1131 if ((*opt == '\0') || size < 0) { 1132 revert(); 1133 errx(1, "argument must be a positive number"); 1134 } 1135 1136 if (ioctl(0, CONS_HISTORY, &size) == -1) { 1137 revert(); 1138 errc(1, errno, "setting history buffer size"); 1139 } 1140} 1141 1142 1143/* 1144 * Clear the console history buffer. 1145 */ 1146 1147static void 1148clear_history(void) 1149{ 1150 if (ioctl(0, CONS_CLRHIST) == -1) { 1151 revert(); 1152 errc(1, errno, "clearing history buffer"); 1153 } 1154} 1155 1156 1157int 1158main(int argc, char **argv) 1159{ 1160 char *font, *type; 1161 int dumpmod, dumpopt, opt; 1162 int reterr; 1163 1164 init(); 1165 1166 info.size = sizeof(info); 1167 1168 if (ioctl(0, CONS_GETINFO, &info) == -1) 1169 err(1, "must be on a virtual console"); 1170 dumpmod = 0; 1171 dumpopt = DUMP_FBF; 1172 while((opt = getopt(argc, argv, "b:Cc:df:g:h:Hi:l:LM:m:pPr:S:s:t:x")) != -1) 1173 switch(opt) { 1174 case 'b': 1175 set_border_color(optarg); 1176 break; 1177 case 'C': 1178 clear_history(); 1179 break; 1180 case 'c': 1181 set_cursor_type(optarg); 1182 break; 1183 case 'd': 1184 print_scrnmap(); 1185 break; 1186 case 'f': 1187 type = optarg; 1188 font = nextarg(argc, argv, &optind, 'f', 0); 1189 1190 if (font == NULL) { 1191 type = NULL; 1192 font = optarg; 1193 } 1194 1195 load_font(type, font); 1196 break; 1197 case 'g': 1198 if (sscanf(optarg, "%dx%d", 1199 &vesa_cols, &vesa_rows) != 2) { 1200 revert(); 1201 warnx("incorrect geometry: %s", optarg); 1202 usage(); 1203 } 1204 break; 1205 case 'h': 1206 set_history(optarg); 1207 break; 1208 case 'H': 1209 dumpopt = DUMP_ALL; 1210 break; 1211 case 'i': 1212 show_info(optarg); 1213 break; 1214 case 'l': 1215 load_scrnmap(optarg); 1216 break; 1217 case 'L': 1218 load_default_scrnmap(); 1219 break; 1220 case 'M': 1221 set_mouse_char(optarg); 1222 break; 1223 case 'm': 1224 set_mouse(optarg); 1225 break; 1226 case 'p': 1227 dumpmod = DUMP_FMT_RAW; 1228 break; 1229 case 'P': 1230 dumpmod = DUMP_FMT_TXT; 1231 break; 1232 case 'r': 1233 get_reverse_colors(argc, argv, &optind); 1234 break; 1235 case 'S': 1236 set_lockswitch(optarg); 1237 break; 1238 case 's': 1239 set_console(optarg); 1240 break; 1241 case 't': 1242 set_screensaver_timeout(optarg); 1243 break; 1244 case 'x': 1245 hex = 1; 1246 break; 1247 default: 1248 usage(); 1249 } 1250 1251 if (dumpmod != 0) 1252 dump_screen(dumpmod, dumpopt); 1253 reterr = video_mode(argc, argv, &optind); 1254 get_normal_colors(argc, argv, &optind); 1255 1256 if (optind < argc && !strcmp(argv[optind], "show")) { 1257 test_frame(); 1258 optind++; 1259 } 1260 1261 video_mode(argc, argv, &optind); 1262 1263 get_normal_colors(argc, argv, &optind); 1264 1265 if (colors_changed || video_mode_changed) { 1266 if (!(new_mode_info.vi_flags & V_INFO_GRAPHICS)) { 1267 if ((normal_back_color < 8) && (revers_back_color < 8)) { 1268 set_colors(); 1269 } else { 1270 revert(); 1271 errx(1, "bg color for text modes must be < 8"); 1272 } 1273 } else { 1274 set_colors(); 1275 } 1276 } 1277 1278 if ((optind != argc) || (argc == 1)) 1279 usage(); 1280 return reterr; 1281} 1282 1283