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