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 35 static const char rcsid[] = 36 "$FreeBSD$"; 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 66 char 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 73 struct { 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 81 int hex = 0; 82 int number; 83 int vesa_cols; 84 int vesa_rows; 85 int font_height; 86 int colors_changed; 87 int video_mode_changed; 88 int normal_fore_color, normal_back_color; 89 int revers_fore_color, revers_back_color; 90 char letter; 91 struct vid_info info; 92 struct 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 109 static void 110 init(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 145 static void 146 revert(void) 147 { 148 int size[3]; 149 150 ioctl(0, VT_ACTIVATE, 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 181 static void 182 usage(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 199 static char * 200 nextarg(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 219 static FILE * 220 openguess(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 250 static void 251 load_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 295 static void 296 load_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 315 static void 316 print_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 343 static int 344 fsize(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 359 static void 360 load_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 474 static void 475 set_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 501 static void 502 set_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 528 static int 529 video_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 693 static int 694 get_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 710 static void 711 get_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 normal_fore_color=color; 719 colors_changed = 1; 720 if (*_index < argc 721 && (color = get_color_number(argv[*_index])) != -1 722 && color < 8) { 723 (*_index)++; 724 fprintf(stderr, "\033[=%dG", color); 725 normal_back_color=color; 726 } 727 } 728 } 729 730 731 /* 732 * Get reverse text and background colors. 733 */ 734 735 static void 736 get_reverse_colors(int argc, char **argv, int *_index) 737 { 738 int color; 739 740 if ((color = get_color_number(argv[*(_index)-1])) != -1) { 741 fprintf(stderr, "\033[=%dH", color); 742 revers_fore_color=color; 743 colors_changed = 1; 744 if (*_index < argc 745 && (color = get_color_number(argv[*_index])) != -1 746 && color < 8) { 747 (*_index)++; 748 fprintf(stderr, "\033[=%dI", color); 749 revers_back_color=color; 750 } 751 } 752 } 753 754 755 /* 756 * Set normal and reverse foreground and background colors. 757 */ 758 759 static void 760 set_colors(void) 761 { 762 fprintf(stderr, "\033[=%dF", normal_fore_color); 763 fprintf(stderr, "\033[=%dG", normal_back_color); 764 fprintf(stderr, "\033[=%dH", revers_fore_color); 765 fprintf(stderr, "\033[=%dI", revers_back_color); 766 } 767 768 769 /* 770 * Switch to virtual terminal #arg. 771 */ 772 773 static void 774 set_console(char *arg) 775 { 776 int n; 777 778 if(!arg || strspn(arg,"0123456789") != strlen(arg)) { 779 revert(); 780 errx(1, "bad console number"); 781 } 782 783 n = atoi(arg); 784 785 if (n < 1 || n > 16) { 786 revert(); 787 errx(1, "console number out of range"); 788 } else if (ioctl(0, VT_ACTIVATE, n) == -1) { 789 revert(); 790 errc(1, errno, "switching vty"); 791 } 792 } 793 794 795 /* 796 * Sets the border color. 797 */ 798 799 static void 800 set_border_color(char *arg) 801 { 802 int color; 803 804 if ((color = get_color_number(arg)) != -1) { 805 fprintf(stderr, "\033[=%dA", color); 806 } 807 else 808 usage(); 809 } 810 811 static void 812 set_mouse_char(char *arg) 813 { 814 struct mouse_info mouse; 815 long l; 816 817 l = strtol(arg, NULL, 0); 818 819 if ((l < 0) || (l > UCHAR_MAX - 3)) { 820 revert(); 821 warnx("argument to -M must be 0 through %d", UCHAR_MAX - 3); 822 return; 823 } 824 825 mouse.operation = MOUSE_MOUSECHAR; 826 mouse.u.mouse_char = (int)l; 827 828 if (ioctl(0, CONS_MOUSECTL, &mouse) == -1) { 829 revert(); 830 errc(1, errno, "setting mouse character"); 831 } 832 } 833 834 835 /* 836 * Show/hide the mouse. 837 */ 838 839 static void 840 set_mouse(char *arg) 841 { 842 struct mouse_info mouse; 843 844 if (!strcmp(arg, "on")) { 845 mouse.operation = MOUSE_SHOW; 846 } else if (!strcmp(arg, "off")) { 847 mouse.operation = MOUSE_HIDE; 848 } else { 849 revert(); 850 errx(1, "argument to -m must be either on or off"); 851 } 852 853 if (ioctl(0, CONS_MOUSECTL, &mouse) == -1) { 854 revert(); 855 errc(1, errno, "%sing the mouse", 856 mouse.operation == MOUSE_SHOW ? "show" : "hid"); 857 } 858 } 859 860 861 static void 862 set_lockswitch(char *arg) 863 { 864 int data; 865 866 if (!strcmp(arg, "off")) { 867 data = 0x01; 868 } else if (!strcmp(arg, "on")) { 869 data = 0x02; 870 } else { 871 revert(); 872 errx(1, "argument to -S must be either on or off"); 873 } 874 875 if (ioctl(0, VT_LOCKSWITCH, &data) == -1) { 876 revert(); 877 errc(1, errno, "turning %s vty switching", 878 data == 0x01 ? "off" : "on"); 879 } 880 } 881 882 883 /* 884 * Return the adapter name for a specified type. 885 */ 886 887 static const char 888 *adapter_name(int type) 889 { 890 static struct { 891 int type; 892 const char *name; 893 } names[] = { 894 { KD_MONO, "MDA" }, 895 { KD_HERCULES, "Hercules" }, 896 { KD_CGA, "CGA" }, 897 { KD_EGA, "EGA" }, 898 { KD_VGA, "VGA" }, 899 { KD_PC98, "PC-98xx" }, 900 { KD_TGA, "TGA" }, 901 { -1, "Unknown" }, 902 }; 903 904 int i; 905 906 for (i = 0; names[i].type != -1; ++i) 907 if (names[i].type == type) 908 break; 909 return names[i].name; 910 } 911 912 913 /* 914 * Show graphics adapter information. 915 */ 916 917 static void 918 show_adapter_info(void) 919 { 920 struct video_adapter_info ad; 921 922 ad.va_index = 0; 923 924 if (ioctl(0, CONS_ADPINFO, &ad) == -1) { 925 revert(); 926 errc(1, errno, "obtaining adapter information"); 927 } 928 929 printf("fb%d:\n", ad.va_index); 930 printf(" %.*s%d, type:%s%s (%d), flags:0x%x\n", 931 (int)sizeof(ad.va_name), ad.va_name, ad.va_unit, 932 (ad.va_flags & V_ADP_VESA) ? "VESA " : "", 933 adapter_name(ad.va_type), ad.va_type, ad.va_flags); 934 printf(" initial mode:%d, current mode:%d, BIOS mode:%d\n", 935 ad.va_initial_mode, ad.va_mode, ad.va_initial_bios_mode); 936 printf(" frame buffer window:0x%zx, buffer size:0x%zx\n", 937 ad.va_window, ad.va_buffer_size); 938 printf(" window size:0x%zx, origin:0x%x\n", 939 ad.va_window_size, ad.va_window_orig); 940 printf(" display start address (%d, %d), scan line width:%d\n", 941 ad.va_disp_start.x, ad.va_disp_start.y, ad.va_line_width); 942 printf(" reserved:0x%zx\n", ad.va_unused0); 943 } 944 945 946 /* 947 * Show video mode information. 948 */ 949 950 static void 951 show_mode_info(void) 952 { 953 struct video_info _info; 954 char buf[80]; 955 int mode; 956 int c; 957 958 printf(" mode# flags type size " 959 "font window linear buffer\n"); 960 printf("---------------------------------------" 961 "---------------------------------------\n"); 962 963 for (mode = 0; mode < M_VESA_MODE_MAX; ++mode) { 964 _info.vi_mode = mode; 965 if (ioctl(0, CONS_MODEINFO, &_info)) 966 continue; 967 if (_info.vi_mode != mode) 968 continue; 969 970 printf("%3d (0x%03x)", mode, mode); 971 printf(" 0x%08x", _info.vi_flags); 972 if (_info.vi_flags & V_INFO_GRAPHICS) { 973 c = 'G'; 974 975 snprintf(buf, sizeof(buf), "%dx%dx%d %d", 976 _info.vi_width, _info.vi_height, 977 _info.vi_depth, _info.vi_planes); 978 } else { 979 c = 'T'; 980 981 snprintf(buf, sizeof(buf), "%dx%d", 982 _info.vi_width, _info.vi_height); 983 } 984 985 printf(" %c %-15s", c, buf); 986 snprintf(buf, sizeof(buf), "%dx%d", 987 _info.vi_cwidth, _info.vi_cheight); 988 printf(" %-5s", buf); 989 printf(" 0x%05zx %2dk %2dk", 990 _info.vi_window, (int)_info.vi_window_size/1024, 991 (int)_info.vi_window_gran/1024); 992 printf(" 0x%08zx %dk\n", 993 _info.vi_buffer, (int)_info.vi_buffer_size/1024); 994 } 995 } 996 997 998 static void 999 show_info(char *arg) 1000 { 1001 if (!strcmp(arg, "adapter")) { 1002 show_adapter_info(); 1003 } else if (!strcmp(arg, "mode")) { 1004 show_mode_info(); 1005 } else { 1006 revert(); 1007 errx(1, "argument to -i must be either adapter or mode"); 1008 } 1009 } 1010 1011 1012 static void 1013 test_frame(void) 1014 { 1015 int i, cur_mode, fore; 1016 1017 fore = 15; 1018 1019 if (ioctl(0, CONS_GET, &cur_mode) < 0) 1020 err(1, "must be on a virtual console"); 1021 switch (cur_mode) { 1022 case M_PC98_80x25: 1023 case M_PC98_80x30: 1024 fore = 7; 1025 break; 1026 } 1027 1028 fprintf(stdout, "\033[=0G\n\n"); 1029 for (i=0; i<8; i++) { 1030 fprintf(stdout, "\033[=%dF\033[=0G %2d \033[=%dF%-16s" 1031 "\033[=%dF\033[=0G %2d \033[=%dF%-16s " 1032 "\033[=%dF %2d \033[=%dGBACKGROUND\033[=0G\n", 1033 fore, i, i, legal_colors[i], 1034 fore, i+8, i+8, legal_colors[i+8], 1035 fore, i, i); 1036 } 1037 fprintf(stdout, "\033[=%dF\033[=%dG\033[=%dH\033[=%dI\n", 1038 info.mv_norm.fore, info.mv_norm.back, 1039 info.mv_rev.fore, info.mv_rev.back); 1040 } 1041 1042 1043 /* 1044 * Snapshot the video memory of that terminal, using the CONS_SCRSHOT 1045 * ioctl, and writes the results to stdout either in the special 1046 * binary format (see manual page for details), or in the plain 1047 * text format. 1048 */ 1049 1050 static void 1051 dump_screen(int mode, int opt) 1052 { 1053 scrshot_t shot; 1054 vid_info_t _info; 1055 1056 _info.size = sizeof(_info); 1057 1058 if (ioctl(0, CONS_GETINFO, &_info) == -1) { 1059 revert(); 1060 errc(1, errno, "obtaining current video mode parameters"); 1061 return; 1062 } 1063 1064 shot.x = shot.y = 0; 1065 shot.xsize = _info.mv_csz; 1066 shot.ysize = _info.mv_rsz; 1067 if (opt == DUMP_ALL) 1068 shot.ysize += _info.mv_hsz; 1069 1070 shot.buf = alloca(shot.xsize * shot.ysize * sizeof(u_int16_t)); 1071 if (shot.buf == NULL) { 1072 revert(); 1073 errx(1, "failed to allocate memory for dump"); 1074 } 1075 1076 if (ioctl(0, CONS_SCRSHOT, &shot) == -1) { 1077 revert(); 1078 errc(1, errno, "dumping screen"); 1079 } 1080 1081 if (mode == DUMP_FMT_RAW) { 1082 printf("SCRSHOT_%c%c%c%c", DUMP_FMT_REV, 2, 1083 shot.xsize, shot.ysize); 1084 1085 fflush(stdout); 1086 1087 write(STDOUT_FILENO, shot.buf, 1088 shot.xsize * shot.ysize * sizeof(u_int16_t)); 1089 } else { 1090 char *line; 1091 int x, y; 1092 u_int16_t ch; 1093 1094 line = alloca(shot.xsize + 1); 1095 1096 if (line == NULL) { 1097 revert(); 1098 errx(1, "failed to allocate memory for line buffer"); 1099 } 1100 1101 for (y = 0; y < shot.ysize; y++) { 1102 for (x = 0; x < shot.xsize; x++) { 1103 ch = shot.buf[x + (y * shot.xsize)]; 1104 ch &= 0xff; 1105 1106 if (isprint(ch) == 0) 1107 ch = ' '; 1108 1109 line[x] = (char)ch; 1110 } 1111 1112 /* Trim trailing spaces */ 1113 1114 do { 1115 line[x--] = '\0'; 1116 } while (line[x] == ' ' && x != 0); 1117 1118 puts(line); 1119 } 1120 1121 fflush(stdout); 1122 } 1123 } 1124 1125 1126 /* 1127 * Set the console history buffer size. 1128 */ 1129 1130 static void 1131 set_history(char *opt) 1132 { 1133 int size; 1134 1135 size = atoi(opt); 1136 1137 if ((*opt == '\0') || size < 0) { 1138 revert(); 1139 errx(1, "argument must be a positive number"); 1140 } 1141 1142 if (ioctl(0, CONS_HISTORY, &size) == -1) { 1143 revert(); 1144 errc(1, errno, "setting history buffer size"); 1145 } 1146 } 1147 1148 1149 /* 1150 * Clear the console history buffer. 1151 */ 1152 1153 static void 1154 clear_history(void) 1155 { 1156 if (ioctl(0, CONS_CLRHIST) == -1) { 1157 revert(); 1158 errc(1, errno, "clearing history buffer"); 1159 } 1160 } 1161 1162 1163 int 1164 main(int argc, char **argv) 1165 { 1166 char *font, *type; 1167 int dumpmod, dumpopt, opt; 1168 int reterr; 1169 1170 init(); 1171 1172 info.size = sizeof(info); 1173 1174 if (ioctl(0, CONS_GETINFO, &info) == -1) 1175 err(1, "must be on a virtual console"); 1176 dumpmod = 0; 1177 dumpopt = DUMP_FBF; 1178 while((opt = getopt(argc, argv, "b:Cc:df:g:h:Hi:l:LM:m:pPr:S:s:t:x")) != -1) 1179 switch(opt) { 1180 case 'b': 1181 set_border_color(optarg); 1182 break; 1183 case 'C': 1184 clear_history(); 1185 break; 1186 case 'c': 1187 set_cursor_type(optarg); 1188 break; 1189 case 'd': 1190 print_scrnmap(); 1191 break; 1192 case 'f': 1193 type = optarg; 1194 font = nextarg(argc, argv, &optind, 'f', 0); 1195 1196 if (font == NULL) { 1197 type = NULL; 1198 font = optarg; 1199 } 1200 1201 load_font(type, font); 1202 break; 1203 case 'g': 1204 if (sscanf(optarg, "%dx%d", 1205 &vesa_cols, &vesa_rows) != 2) { 1206 revert(); 1207 warnx("incorrect geometry: %s", optarg); 1208 usage(); 1209 } 1210 break; 1211 case 'h': 1212 set_history(optarg); 1213 break; 1214 case 'H': 1215 dumpopt = DUMP_ALL; 1216 break; 1217 case 'i': 1218 show_info(optarg); 1219 break; 1220 case 'l': 1221 load_scrnmap(optarg); 1222 break; 1223 case 'L': 1224 load_default_scrnmap(); 1225 break; 1226 case 'M': 1227 set_mouse_char(optarg); 1228 break; 1229 case 'm': 1230 set_mouse(optarg); 1231 break; 1232 case 'p': 1233 dumpmod = DUMP_FMT_RAW; 1234 break; 1235 case 'P': 1236 dumpmod = DUMP_FMT_TXT; 1237 break; 1238 case 'r': 1239 get_reverse_colors(argc, argv, &optind); 1240 break; 1241 case 'S': 1242 set_lockswitch(optarg); 1243 break; 1244 case 's': 1245 set_console(optarg); 1246 break; 1247 case 't': 1248 set_screensaver_timeout(optarg); 1249 break; 1250 case 'x': 1251 hex = 1; 1252 break; 1253 default: 1254 usage(); 1255 } 1256 1257 if (dumpmod != 0) 1258 dump_screen(dumpmod, dumpopt); 1259 reterr = video_mode(argc, argv, &optind); 1260 get_normal_colors(argc, argv, &optind); 1261 1262 if (optind < argc && !strcmp(argv[optind], "show")) { 1263 test_frame(); 1264 optind++; 1265 } 1266 1267 video_mode(argc, argv, &optind); 1268 1269 get_normal_colors(argc, argv, &optind); 1270 1271 if (colors_changed || video_mode_changed) { 1272 if (!(new_mode_info.vi_flags & V_INFO_GRAPHICS)) { 1273 if ((normal_back_color < 8) && (revers_back_color < 8)) { 1274 set_colors(); 1275 } else { 1276 revert(); 1277 errx(1, "bg color for text modes must be < 8"); 1278 } 1279 } else { 1280 set_colors(); 1281 } 1282 } 1283 1284 if ((optind != argc) || (argc == 1)) 1285 usage(); 1286 return reterr; 1287 } 1288 1289