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