1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2002 Jonathan Belson <jon@witchspace.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/types.h> 33 #include <sys/queue.h> 34 #include <sys/sysctl.h> 35 36 #include <assert.h> 37 #include <ctype.h> 38 #include <dirent.h> 39 #include <limits.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <stringlist.h> 44 #include <unistd.h> 45 46 #include "kbdmap.h" 47 48 49 static const char *lang_default = DEFAULT_LANG; 50 static const char *font; 51 static const char *lang; 52 static const char *program; 53 static const char *keymapdir = DEFAULT_VT_KEYMAP_DIR; 54 static const char *fontdir = DEFAULT_VT_FONT_DIR; 55 static const char *font_default = DEFAULT_VT_FONT; 56 static const char *sysconfig = DEFAULT_SYSCONFIG; 57 static const char *font_current; 58 static const char *dir; 59 static const char *menu = ""; 60 static const char *title = "Keyboard Menu"; 61 62 static int x11; 63 static int using_vt; 64 static int show; 65 static int verbose; 66 static int print; 67 68 69 struct keymap { 70 char *desc; 71 char *keym; 72 int mark; 73 SLIST_ENTRY(keymap) entries; 74 }; 75 static SLIST_HEAD(slisthead, keymap) head = SLIST_HEAD_INITIALIZER(head); 76 77 78 /* 79 * Get keymap entry for 'key', or NULL of not found 80 */ 81 static struct keymap * 82 get_keymap(const char *key) 83 { 84 struct keymap *km; 85 86 SLIST_FOREACH(km, &head, entries) 87 if (!strcmp(km->keym, key)) 88 return km; 89 90 return NULL; 91 } 92 93 /* 94 * Count the number of keymaps we found 95 */ 96 static int 97 get_num_keymaps(void) 98 { 99 struct keymap *km; 100 int count = 0; 101 102 SLIST_FOREACH(km, &head, entries) 103 count++; 104 105 return count; 106 } 107 108 /* 109 * Remove any keymap with given keym 110 */ 111 static void 112 remove_keymap(const char *keym) 113 { 114 struct keymap *km; 115 116 SLIST_FOREACH(km, &head, entries) { 117 if (!strcmp(keym, km->keym)) { 118 SLIST_REMOVE(&head, km, keymap, entries); 119 free(km); 120 break; 121 } 122 } 123 } 124 125 /* 126 * Add to hash with 'key' 127 */ 128 static void 129 add_keymap(const char *desc, int mark, const char *keym) 130 { 131 struct keymap *km, *km_new; 132 133 /* Is there already an entry with this key? */ 134 SLIST_FOREACH(km, &head, entries) { 135 if (!strcmp(km->keym, keym)) { 136 /* Reuse this entry */ 137 free(km->desc); 138 km->desc = strdup(desc); 139 km->mark = mark; 140 return; 141 } 142 } 143 144 km_new = (struct keymap *) malloc (sizeof(struct keymap)); 145 km_new->desc = strdup(desc); 146 km_new->keym = strdup(keym); 147 km_new->mark = mark; 148 149 /* Add to keymap list */ 150 SLIST_INSERT_HEAD(&head, km_new, entries); 151 } 152 153 /* 154 * Return 0 if syscons is in use (to select legacy defaults). 155 */ 156 static int 157 check_vt(void) 158 { 159 size_t len; 160 char term[3]; 161 162 len = 3; 163 if (sysctlbyname("kern.vty", &term, &len, NULL, 0) != 0 || 164 strcmp(term, "vt") != 0) 165 return 0; 166 return 1; 167 } 168 169 /* 170 * Figure out the default language to use. 171 */ 172 static const char * 173 get_locale(void) 174 { 175 const char *locale; 176 177 if ((locale = getenv("LC_ALL")) == NULL && 178 (locale = getenv("LC_CTYPE")) == NULL && 179 (locale = getenv("LANG")) == NULL) 180 locale = lang_default; 181 182 /* Check for alias */ 183 if (!strcmp(locale, "C")) 184 locale = DEFAULT_LANG; 185 186 return locale; 187 } 188 189 /* 190 * Extract filename part 191 */ 192 static const char * 193 extract_name(const char *name) 194 { 195 char *p; 196 197 p = strrchr(name, '/'); 198 if (p != NULL && p[1] != '\0') 199 return p + 1; 200 201 return name; 202 } 203 204 /* 205 * Return file extension or NULL 206 */ 207 static char * 208 get_extension(const char *name) 209 { 210 char *p; 211 212 p = strrchr(name, '.'); 213 214 if (p != NULL && p[1] != '\0') 215 return p; 216 217 return NULL; 218 } 219 220 /* 221 * Read font from /etc/rc.conf else return default. 222 * Freeing the memory is the caller's responsibility. 223 */ 224 static char * 225 get_font(void) 226 { 227 char line[256], buf[20]; 228 char *fnt = NULL; 229 230 FILE *fp = fopen(sysconfig, "r"); 231 if (fp) { 232 while (fgets(line, sizeof(line), fp)) { 233 int a, b, matches; 234 235 if (line[0] == '#') 236 continue; 237 238 matches = sscanf(line, 239 " font%dx%d = \"%20[-.0-9a-zA-Z_]", 240 &a, &b, buf); 241 if (matches==3) { 242 if (strcmp(buf, "NO")) { 243 if (fnt) 244 free(fnt); 245 fnt = strdup(buf); 246 } 247 } 248 } 249 fclose(fp); 250 } else 251 fprintf(stderr, "Could not open %s for reading\n", sysconfig); 252 253 return fnt; 254 } 255 256 /* 257 * Set a font using 'vidcontrol' 258 */ 259 static void 260 vidcontrol(const char *fnt) 261 { 262 char *tmp, *p, *q, *cmd; 263 char ch; 264 int i; 265 266 /* syscons test failed */ 267 if (x11) 268 return; 269 270 if (using_vt) { 271 asprintf(&cmd, "vidcontrol -f %s", fnt); 272 system(cmd); 273 free(cmd); 274 return; 275 } 276 277 tmp = strdup(fnt); 278 279 /* Extract font size */ 280 p = strrchr(tmp, '-'); 281 if (p && p[1] != '\0') { 282 p++; 283 /* Remove any '.fnt' extension */ 284 if ((q = strstr(p, ".fnt"))) 285 *q = '\0'; 286 287 /* 288 * Check font size is valid, with no trailing characters 289 * ('&ch' should not be matched) 290 */ 291 if (sscanf(p, "%dx%d%c", &i, &i, &ch) != 2) 292 fprintf(stderr, "Which font size? %s\n", fnt); 293 else { 294 asprintf(&cmd, "vidcontrol -f %s %s", p, fnt); 295 if (verbose) 296 fprintf(stderr, "%s\n", cmd); 297 system(cmd); 298 free(cmd); 299 } 300 } else 301 fprintf(stderr, "Which font size? %s\n", fnt); 302 303 free(tmp); 304 } 305 306 /* 307 * Execute 'kbdcontrol' with the appropriate arguments 308 */ 309 static void 310 do_kbdcontrol(struct keymap *km) 311 { 312 char *kbd_cmd; 313 asprintf(&kbd_cmd, "kbdcontrol -l %s/%s", dir, km->keym); 314 315 if (!x11) 316 system(kbd_cmd); 317 318 fprintf(stderr, "keymap=\"%s\"\n", km->keym); 319 free(kbd_cmd); 320 } 321 322 /* 323 * Call 'vidcontrol' with the appropriate arguments 324 */ 325 static void 326 do_vidfont(struct keymap *km) 327 { 328 char *vid_cmd, *tmp, *p, *q; 329 330 asprintf(&vid_cmd, "%s/%s", dir, km->keym); 331 vidcontrol(vid_cmd); 332 free(vid_cmd); 333 334 tmp = strdup(km->keym); 335 p = strrchr(tmp, '-'); 336 if (p && p[1]!='\0') { 337 p++; 338 q = get_extension(p); 339 if (q) { 340 *q = '\0'; 341 printf("font%s=%s\n", p, km->keym); 342 } 343 } 344 free(tmp); 345 } 346 347 /* 348 * Display dialog from 'keymaps[]' 349 */ 350 static void 351 show_dialog(struct keymap **km_sorted, int num_keymaps) 352 { 353 FILE *fp; 354 char *cmd, *dialog; 355 char tmp_name[] = "/tmp/_kbd_lang.XXXX"; 356 int fd, i, size; 357 358 fd = mkstemp(tmp_name); 359 if (fd == -1) { 360 fprintf(stderr, "Could not open temporary file \"%s\"\n", 361 tmp_name); 362 exit(1); 363 } 364 asprintf(&dialog, "/usr/bin/dialog --clear --title \"%s\" " 365 "--menu \"%s\" 0 0 0", title, menu); 366 367 /* start right font, assume that current font is equal 368 * to default font in /etc/rc.conf 369 * 370 * $font is the font which require the language $lang; e.g. 371 * russian *need* a koi8 font 372 * $font_current is the current font from /etc/rc.conf 373 */ 374 if (font && strcmp(font, font_current)) 375 vidcontrol(font); 376 377 /* Build up the command */ 378 size = 0; 379 for (i=0; i<num_keymaps; i++) { 380 /* 381 * Each 'font' is passed as ' "font" ""', so allow the 382 * extra space 383 */ 384 size += strlen(km_sorted[i]->desc) + 6; 385 } 386 387 /* Allow the space for '2> tmpfilename' redirection */ 388 size += strlen(tmp_name) + 3; 389 390 cmd = (char *) malloc(strlen(dialog) + size + 1); 391 strcpy(cmd, dialog); 392 393 for (i=0; i<num_keymaps; i++) { 394 strcat(cmd, " \""); 395 strcat(cmd, km_sorted[i]->desc); 396 strcat(cmd, "\""); 397 strcat(cmd, " \"\""); 398 } 399 400 strcat(cmd, " 2>"); 401 strcat(cmd, tmp_name); 402 403 /* Show the dialog.. */ 404 system(cmd); 405 406 fp = fopen(tmp_name, "r"); 407 if (fp) { 408 char choice[64]; 409 if (fgets(choice, sizeof(choice), fp) != NULL) { 410 /* Find key for desc */ 411 for (i=0; i<num_keymaps; i++) { 412 if (!strcmp(choice, km_sorted[i]->desc)) { 413 if (!strcmp(program, "kbdmap")) 414 do_kbdcontrol(km_sorted[i]); 415 else 416 do_vidfont(km_sorted[i]); 417 break; 418 } 419 } 420 } else { 421 if (font != NULL && strcmp(font, font_current)) 422 /* Cancelled, restore old font */ 423 vidcontrol(font_current); 424 } 425 fclose(fp); 426 } else 427 fprintf(stderr, "Failed to open temporary file"); 428 429 /* Tidy up */ 430 remove(tmp_name); 431 free(cmd); 432 free(dialog); 433 close(fd); 434 } 435 436 /* 437 * Search for 'token' in comma delimited array 'buffer'. 438 * Return true for found, false for not found. 439 */ 440 static int 441 find_token(const char *buffer, const char *token) 442 { 443 char *buffer_tmp, *buffer_copy, *inputstring; 444 char **ap; 445 int found; 446 447 buffer_copy = strdup(buffer); 448 buffer_tmp = buffer_copy; 449 inputstring = buffer_copy; 450 ap = &buffer_tmp; 451 452 found = 0; 453 454 while ((*ap = strsep(&inputstring, ",")) != NULL) { 455 if (strcmp(buffer_tmp, token) == 0) { 456 found = 1; 457 break; 458 } 459 } 460 461 free(buffer_copy); 462 463 return found; 464 } 465 466 /* 467 * Compare function for qsort 468 */ 469 static int 470 compare_keymap(const void *a, const void *b) 471 { 472 473 /* We've been passed pointers to pointers, so: */ 474 const struct keymap *km1 = *((const struct keymap * const *) a); 475 const struct keymap *km2 = *((const struct keymap * const *) b); 476 477 return strcmp(km1->desc, km2->desc); 478 } 479 480 /* 481 * Compare function for qsort 482 */ 483 static int 484 compare_lang(const void *a, const void *b) 485 { 486 const char *l1 = *((const char * const *) a); 487 const char *l2 = *((const char * const *) b); 488 489 return strcmp(l1, l2); 490 } 491 492 /* 493 * Change '8x8' to '8x08' so qsort will put it before eg. '8x14' 494 */ 495 static void 496 kludge_desc(struct keymap **km_sorted, int num_keymaps) 497 { 498 int i; 499 500 for (i=0; i<num_keymaps; i++) { 501 char *p; 502 char *km = km_sorted[i]->desc; 503 if ((p = strstr(km, "8x8")) != NULL) { 504 int len; 505 int j; 506 int offset; 507 508 offset = p - km; 509 510 /* Make enough space for the extra '0' */ 511 len = strlen(km); 512 km = realloc(km, len + 2); 513 514 for (j=len; j!=offset+1; j--) 515 km[j + 1] = km[j]; 516 517 km[offset+2] = '0'; 518 519 km_sorted[i]->desc = km; 520 } 521 } 522 } 523 524 /* 525 * Reverse 'kludge_desc()' - change '8x08' back to '8x8' 526 */ 527 static void 528 unkludge_desc(struct keymap **km_sorted, int num_keymaps) 529 { 530 int i; 531 532 for (i=0; i<num_keymaps; i++) { 533 char *p; 534 char *km = km_sorted[i]->desc; 535 if ((p = strstr(km, "8x08")) != NULL) { 536 p += 2; 537 while (*p++) 538 p[-1] = p[0]; 539 540 km = realloc(km, p - km - 1); 541 km_sorted[i]->desc = km; 542 } 543 } 544 } 545 546 /* 547 * Return 0 if file exists and is readable, else -1 548 */ 549 static int 550 check_file(const char *keym) 551 { 552 int status = 0; 553 554 if (access(keym, R_OK) == -1) { 555 char *fn; 556 asprintf(&fn, "%s/%s", dir, keym); 557 if (access(fn, R_OK) == -1) { 558 if (verbose) 559 fprintf(stderr, "%s not found!\n", fn); 560 status = -1; 561 } 562 free(fn); 563 } else { 564 if (verbose) 565 fprintf(stderr, "No read permission for %s!\n", keym); 566 status = -1; 567 } 568 569 return status; 570 } 571 572 /* 573 * Read options from the relevant configuration file, then 574 * present to user. 575 */ 576 static void 577 menu_read(void) 578 { 579 const char *lg; 580 char *p; 581 int mark, num_keymaps, items, i; 582 char buffer[256], filename[PATH_MAX]; 583 char keym[64], lng[64], desc[256]; 584 char dialect[64], lang_abk[64]; 585 struct keymap *km; 586 struct keymap **km_sorted; 587 struct dirent *dp; 588 StringList *lang_list; 589 FILE *fp; 590 DIR *dirp; 591 592 lang_list = sl_init(); 593 594 sprintf(filename, "%s/INDEX.%s", dir, extract_name(dir)); 595 596 /* en_US.ISO8859-1 -> en_..\.ISO8859-1 */ 597 strlcpy(dialect, lang, sizeof(dialect)); 598 if (strlen(dialect) >= 6 && dialect[2] == '_') { 599 dialect[3] = '.'; 600 dialect[4] = '.'; 601 } 602 603 604 /* en_US.ISO8859-1 -> en */ 605 strlcpy(lang_abk, lang, sizeof(lang_abk)); 606 if (strlen(lang_abk) >= 3 && lang_abk[2] == '_') 607 lang_abk[2] = '\0'; 608 609 fprintf(stderr, "lang_default = %s\n", lang_default); 610 fprintf(stderr, "dialect = %s\n", dialect); 611 fprintf(stderr, "lang_abk = %s\n", lang_abk); 612 613 fp = fopen(filename, "r"); 614 if (fp) { 615 int matches; 616 while (fgets(buffer, sizeof(buffer), fp)) { 617 p = buffer; 618 if (p[0] == '#') 619 continue; 620 621 while (isspace(*p)) 622 p++; 623 624 if (*p == '\0') 625 continue; 626 627 /* Parse input, removing newline */ 628 matches = sscanf(p, "%64[^:]:%64[^:]:%256[^:\n]", 629 keym, lng, desc); 630 if (matches == 3) { 631 if (strcmp(keym, "FONT") != 0 && 632 strcmp(keym, "MENU") != 0 && 633 strcmp(keym, "TITLE") != 0) { 634 /* Check file exists & is readable */ 635 if (check_file(keym) == -1) 636 continue; 637 } 638 } 639 640 if (show) { 641 /* 642 * Take note of supported languages, which 643 * might be in a comma-delimited list 644 */ 645 char *tmp = strdup(lng); 646 char *delim = tmp; 647 648 for (delim = tmp; ; ) { 649 char ch = *delim++; 650 if (ch == ',' || ch == '\0') { 651 delim[-1] = '\0'; 652 if (!sl_find(lang_list, tmp)) 653 sl_add(lang_list, tmp); 654 if (ch == '\0') 655 break; 656 tmp = delim; 657 } 658 } 659 } 660 /* Set empty language to default language */ 661 if (lng[0] == '\0') 662 lg = lang_default; 663 else 664 lg = lng; 665 666 667 /* 4) Your choice if it exists 668 * 3) Long match eg. en_GB.ISO8859-1 is equal to 669 * en_..\.ISO8859-1 670 * 2) short match 'de' 671 * 1) default langlist 'en' 672 * 0) any language 673 * 674 * Language may be a comma separated list 675 * A higher match overwrites a lower 676 * A later entry overwrites a previous if it exists 677 * twice in the database 678 */ 679 680 /* Check for favoured language */ 681 km = get_keymap(keym); 682 mark = (km) ? km->mark : 0; 683 684 if (find_token(lg, lang)) 685 add_keymap(desc, 4, keym); 686 else if (mark <= 3 && find_token(lg, dialect)) 687 add_keymap(desc, 3, keym); 688 else if (mark <= 2 && find_token(lg, lang_abk)) 689 add_keymap(desc, 2, keym); 690 else if (mark <= 1 && find_token(lg, lang_default)) 691 add_keymap(desc, 1, keym); 692 else if (mark <= 0) 693 add_keymap(desc, 0, keym); 694 } 695 fclose(fp); 696 697 } else 698 fprintf(stderr, "Could not open %s for reading\n", filename); 699 700 if (show) { 701 qsort(lang_list->sl_str, lang_list->sl_cur, sizeof(char*), 702 compare_lang); 703 printf("Currently supported languages: "); 704 for (i=0; i< (int) lang_list->sl_cur; i++) 705 printf("%s ", lang_list->sl_str[i]); 706 puts(""); 707 exit(0); 708 } 709 710 km = get_keymap("TITLE"); 711 if (km) 712 /* Take note of dialog title */ 713 title = strdup(km->desc); 714 km = get_keymap("MENU"); 715 if (km) 716 /* Take note of menu title */ 717 menu = strdup(km->desc); 718 km = get_keymap("FONT"); 719 if (km) 720 /* Take note of language font */ 721 font = strdup(km->desc); 722 723 /* Remove unwanted items from list */ 724 remove_keymap("FONT"); 725 remove_keymap("MENU"); 726 remove_keymap("TITLE"); 727 728 /* Look for keymaps not in database */ 729 dirp = opendir(dir); 730 if (dirp) { 731 while ((dp = readdir(dirp)) != NULL) { 732 const char *ext = get_extension(dp->d_name); 733 if (ext) { 734 if ((!strcmp(ext, ".fnt") || 735 !strcmp(ext, ".kbd")) && 736 !get_keymap(dp->d_name)) { 737 char *q; 738 739 /* Remove any .fnt or .kbd extension */ 740 q = strdup(dp->d_name); 741 *(get_extension(q)) = '\0'; 742 add_keymap(q, 0, dp->d_name); 743 free(q); 744 745 if (verbose) 746 fprintf(stderr, 747 "'%s' not in database\n", 748 dp->d_name); 749 } 750 } 751 } 752 closedir(dirp); 753 } else 754 fprintf(stderr, "Could not open directory '%s'\n", dir); 755 756 /* Sort items in keymap */ 757 num_keymaps = get_num_keymaps(); 758 759 km_sorted = (struct keymap **) 760 malloc(num_keymaps*sizeof(struct keymap *)); 761 762 /* Make array of pointers to items in hash */ 763 items = 0; 764 SLIST_FOREACH(km, &head, entries) 765 km_sorted[items++] = km; 766 767 /* Change '8x8' to '8x08' so sort works as we might expect... */ 768 kludge_desc(km_sorted, num_keymaps); 769 770 qsort(km_sorted, num_keymaps, sizeof(struct keymap *), compare_keymap); 771 772 /* ...change back again */ 773 unkludge_desc(km_sorted, num_keymaps); 774 775 if (print) { 776 for (i=0; i<num_keymaps; i++) 777 printf("%s\n", km_sorted[i]->desc); 778 exit(0); 779 } 780 781 show_dialog(km_sorted, num_keymaps); 782 783 free(km_sorted); 784 } 785 786 /* 787 * Display usage information and exit 788 */ 789 static void 790 usage(void) 791 { 792 793 fprintf(stderr, "usage: %s\t[-K] [-V] [-d|-default] [-h|-help] " 794 "[-l|-lang language]\n\t\t[-p|-print] [-r|-restore] [-s|-show] " 795 "[-v|-verbose]\n", program); 796 exit(1); 797 } 798 799 static void 800 parse_args(int argc, char **argv) 801 { 802 int i; 803 804 for (i=1; i<argc; i++) { 805 if (argv[i][0] != '-') 806 usage(); 807 else if (!strcmp(argv[i], "-help") || !strcmp(argv[i], "-h")) 808 usage(); 809 else if (!strcmp(argv[i], "-verbose") || !strcmp(argv[i], "-v")) 810 verbose = 1; 811 else if (!strcmp(argv[i], "-lang") || !strcmp(argv[i], "-l")) 812 if (i + 1 == argc) 813 usage(); 814 else 815 lang = argv[++i]; 816 else if (!strcmp(argv[i], "-default") || !strcmp(argv[i], "-d")) 817 lang = lang_default; 818 else if (!strcmp(argv[i], "-show") || !strcmp(argv[i], "-s")) 819 show = 1; 820 else if (!strcmp(argv[i], "-print") || !strcmp(argv[i], "-p")) 821 print = 1; 822 else if (!strcmp(argv[i], "-restore") || 823 !strcmp(argv[i], "-r")) { 824 vidcontrol(font_current); 825 exit(0); 826 } else if (!strcmp(argv[i], "-K")) 827 dir = keymapdir; 828 else if (!strcmp(argv[i], "-V")) 829 dir = fontdir; 830 else 831 usage(); 832 } 833 } 834 835 /* 836 * A front-end for the 'vidfont' and 'kbdmap' programs. 837 */ 838 int 839 main(int argc, char **argv) 840 { 841 842 x11 = system("kbdcontrol -d >/dev/null"); 843 844 if (x11) { 845 fprintf(stderr, "You are not on a virtual console - " 846 "expect certain strange side-effects\n"); 847 sleep(2); 848 } 849 850 using_vt = check_vt(); 851 if (using_vt == 0) { 852 keymapdir = DEFAULT_SC_KEYMAP_DIR; 853 fontdir = DEFAULT_SC_FONT_DIR; 854 font_default = DEFAULT_SC_FONT; 855 } 856 857 SLIST_INIT(&head); 858 859 lang = get_locale(); 860 861 program = extract_name(argv[0]); 862 863 font_current = get_font(); 864 if (font_current == NULL) 865 font_current = font_default; 866 867 if (strcmp(program, "kbdmap")) 868 dir = fontdir; 869 else 870 dir = keymapdir; 871 872 /* Parse command line arguments */ 873 parse_args(argc, argv); 874 875 /* Read and display options */ 876 menu_read(); 877 878 return 0; 879 } 880