#include #include #include #include #include #include #include #include #include #include #include #include "install.h" #include "intl.h" #include "kbd.h" #include "kickstart.h" #include "log.h" #include "newt.h" #include "windows.h" struct defaultKeyboardByLang { char * lang, * keyboard; } defaultKeyboards[] = { { "no", "no-latin1" }, { "cz", "cz-lat2" }, { "tr", "trq" }, { NULL, NULL } }; /* the file pointer must be at the beginning of the section already! */ static int loadKeymap(gzFile stream) { int console; int kmap, key; struct kbentry entry; int keymaps[MAX_NR_KEYMAPS]; int count = 0; int magic; short keymap[NR_KEYS]; if (gzread(stream, &magic, sizeof(magic)) != sizeof(magic)) { logMessage("failed to read kmap magic: %s", strerror(errno)); return INST_ERROR; } if (magic != KMAP_MAGIC) { logMessage("bad magic for keymap!"); return INST_ERROR; } if (gzread(stream, keymaps, sizeof(keymaps)) != sizeof(keymaps)) { logMessage("failed to read keymap header: %s", strerror(errno)); return INST_ERROR; } console = open("/dev/console", O_RDWR); if (console < 0) { logMessage("failed to open /dev/console: %s", strerror(errno)); return INST_ERROR; } for (kmap = 0; kmap < MAX_NR_KEYMAPS; kmap++) { if (!keymaps[kmap]) continue; if (gzread(stream, keymap, sizeof(keymap)) != sizeof(keymap)) { logMessage("failed to read keymap data: %s", strerror(errno)); close(console); return INST_ERROR; } count++; for (key = 0; key < NR_KEYS; key++) { entry.kb_index = key; entry.kb_table = kmap; entry.kb_value = keymap[key]; if (KTYP(entry.kb_value) != KT_SPEC) { if (ioctl(console, KDSKBENT, &entry)) { close(console); logMessage("keymap ioctl failed: %s", strerror(errno)); } } } } logMessage("loaded %d keymap tables", count); close(console); return 0; } int setupKeyboard(char ** keymap) { int num = -1; int rc; gzFile f; struct kmapHeader hdr; struct kmapInfo * infoTable; char ** argv; int argc; char ** kbds; char buf[16384]; /* I hope this is big enough */ int i; char * defkbd = NULL; struct defaultKeyboardByLang * kbdEntry; /*if (testing) return 0;*/ if (getenv("LANG")) { kbdEntry = defaultKeyboards; while (kbdEntry->lang && strcmp(kbdEntry->lang, getenv("LANG"))) kbdEntry++; if (kbdEntry->keyboard) defkbd = kbdEntry->keyboard; } if (!defkbd) defkbd = "us"; f = gzopen("/etc/keymaps.gz", "r"); if (!f) { errorWindow("cannot open /etc/keymaps.gz: %s"); return INST_ERROR; } if (gzread(f, &hdr, sizeof(hdr)) != sizeof(hdr)) { errorWindow("failed to read keymaps header: %s"); gzclose(f); return INST_ERROR; } logMessage("%d keymaps are available", hdr.numEntries); i = hdr.numEntries * sizeof(*infoTable); infoTable = alloca(i); if (gzread(f, infoTable, i) != i) { errorWindow("failed to read keymap information: %s"); gzclose(f); return INST_ERROR; } if (kickstart) { if (!ksGetCommand(KS_CMD_KEYBOARD, NULL, &argc, &argv)) { if (argc < 2) { logMessage("no argument passed to keyboard " "kickstart command"); } else { for (i = 0; i < hdr.numEntries; i++) if (!strcmp(infoTable[i].name, argv[1])) break; if (i < hdr.numEntries) num = i; else newtWinMessage("Kickstart Error", "Ok", "Bad keymap " "name %s passed to kickstart command.", argv[1]); } } } if (num == -1 ) { kbds = alloca(sizeof(*kbds) * (hdr.numEntries + 1)); for (i = 0; i < hdr.numEntries; i++) { kbds[i] = infoTable[i].name; if (!strcmp(infoTable[i].name, defkbd)) num = i; } kbds[i] = NULL; rc = newtWinMenu(_("Keyboard Type"), _("What type of keyboard do you have?"), 40, 5, 5, 8, kbds, &num, _("Ok"), /*_("Back"),*/ NULL); if (rc == 2) return INST_CANCEL; } rc = 0; logMessage("using keymap %s", infoTable[num].name); for (i = 0; i < num; i++) { if (gzread(f, buf, infoTable[i].size) != infoTable[i].size) { logMessage("error reading %d bytes from file: %s", infoTable[i].size, strerror(errno)); gzclose(f); rc = INST_ERROR; } } if (!rc) rc = loadKeymap(f); gzclose(f); writeKbdConfig("/tmp", infoTable[num].name); if (keymap) *keymap = strdup(infoTable[num].name); return rc; } int writeKbdConfig(char * prefix, char * keymap) { FILE * f; char * filename; if (testing || !keymap) return 0; filename = alloca(strlen(prefix) + 20); sprintf(filename, "%s/keyboard", prefix); f = fopen(filename, "w"); if (!f) { errorWindow("failed to create keyboard configuration: %s"); return INST_ERROR; } if (fprintf(f, "KEYTABLE=\"/usr/lib/kbd/keytables/%s.map\"\n", keymap) < 0) { errorWindow("failed to write keyboard configuration: %s"); return INST_ERROR; } fclose(f); return 0; } int readKbdConfig(char * prefix, char ** keymap) { FILE * f; char * filename; char buf[255]; char * chptr; *keymap = NULL; if (testing) return 0; filename = alloca(strlen(prefix) + 20); sprintf(filename, "%s/keyboard", prefix); f = fopen(filename, "r"); if (!f) { /* fail silently -- old bootdisks won't create this */ logMessage("failed to read keyboard configuration (proably ok)"); return 0; } /* this is a bit braindead -- we can steal better parsing from kbdconfig if we ever need it */ if (!fgets(buf, sizeof(buf) - 1, f)) { errorWindow("empty keyboard configuration file"); fclose(f); return INST_ERROR; } fclose(f); if (strncmp("KEYTABLE=", buf, 9)) { errorWindow("unrecognized entry in keyboard configuration file"); return INST_ERROR; } chptr = buf + strlen(buf) - 1; /* ignore the '\n' on the end */ *chptr-- = '\0'; if (*chptr == '"') *chptr-- = '\0'; while (chptr > buf && *chptr != '.') chptr--; if (*chptr == '.') *chptr-- = '\0'; while (chptr > buf && *chptr != '/') chptr--; if (*chptr == '/') chptr++; *keymap = strdup(chptr); return 0; }