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