#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[] = { { "de", "de-latin1" }, { "fi", "fi-latin1" }, { "se", "se-latin1" }, { "no", "no-latin1" }, { "cs", "cz-lat2" }, { "tr", "trq" }, { NULL, NULL } }; #ifdef __sparc__ struct defaultKeyboardByLang defaultSunKeyboards[] = { { "fi", "sunt5-fi-latin1" }, { "cs", "sunt5-cz-us" }, { NULL, NULL } }; #endif /* 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, char ** kbdtypep) { 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 = keymap ? *keymap : NULL; struct defaultKeyboardByLang * kbdEntry; #ifdef __sparc__ #define KBDTYPE_SUN 0 #define KBDTYPE_PC 1 int kbdtype = -1; int j; #endif /*if (testing) return 0;*/ #ifdef __sparc__ if (kickstart) { kbdtype = KBDTYPE_SUN; if (!ksGetCommand(KS_CMD_KBDTYPE, NULL, &argc, &argv)) { if (argc < 2) { logMessage("no argument passed to keyboard " "kickstart command"); } else { if (!strcasecmp (argv[1], "sun")) kbdtype = KBDTYPE_SUN; else if (!strcasecmp (argv[1], "pc")) kbdtype = KBDTYPE_PC; } } } else { char twelve = 12; int fd; if (ioctl (0, TIOCLINUX, &twelve) < 0) kbdtype = KBDTYPE_SUN; /* probably serial console, but one should not call us in such a case */ else { fd = open("/dev/kbd", O_RDWR); if (fd < 0) kbdtype = KBDTYPE_PC; /* if PC keyboard, then there is no driver for /dev/kbd */ else { close(fd); kbdtype = KBDTYPE_SUN; } } } #endif if (!defkbd && getenv("LANG")) { kbdEntry = defaultKeyboards; #ifdef __sparc__ if (kbdtype == KBDTYPE_SUN) kbdEntry = defaultSunKeyboards; #endif while (kbdEntry->lang && strcmp(kbdEntry->lang, getenv("LANG"))) kbdEntry++; if (kbdEntry->keyboard) defkbd = kbdEntry->keyboard; } if (!defkbd) #ifdef __sparc__ if (kbdtype == KBDTYPE_SUN) defkbd = "sunkeymap"; else #endif 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; #ifdef __sparc__ if (i < hdr.numEntries) { if (kbdtype == KBDTYPE_SUN && strncmp (argv[1], "sun", 3)) i = hdr.numEntries; else if (kbdtype == KBDTYPE_PC && !strncmp (argv[1], "sun", 3)) i = hdr.numEntries; } #endif if (i < hdr.numEntries) num = i; else newtWinMessage("Kickstart Error", "Ok", "Bad keymap " "name %s passed to kickstart command.", argv[1]); } } } if (num == -1 ) { #ifdef __sparc__ kbds = alloca(sizeof(*kbds) * (hdr.numEntries + 1)); for (j = 0, i = 0; j < hdr.numEntries; j++) { if (kbdtype == KBDTYPE_SUN && strncmp (infoTable[j].name, "sun", 3)) continue; else if (kbdtype == KBDTYPE_PC && !strncmp (infoTable[j].name, "sun", 3)) continue; kbds[i] = infoTable[j].name; if (!strcmp(infoTable[j].name, defkbd)) num = i; i++; } #else 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; } #endif 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; #ifdef __sparc__ for (j = 0, i = 0; i < hdr.numEntries; i++) { if (kbdtype == KBDTYPE_SUN && strncmp (infoTable[i].name, "sun", 3)) continue; if (kbdtype == KBDTYPE_PC && !strncmp (infoTable[i].name, "sun", 3)) continue; if (j == num) { num = i; break; } j++; } #endif 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, #ifdef __sparc__ kbdtype == KBDTYPE_SUN ? "sun" : "pci" #else NULL #endif ); if (keymap) *keymap = strdup(infoTable[num].name); #ifdef __sparc__ if (kbdtypep) *kbdtypep = (kbdtype == KBDTYPE_SUN) ? "sun" : "pci"; #endif return rc; } int writeKbdConfig(char * prefix, char * keymap, char * kbdtype) { FILE * f; char * filename; char * rootpath; int pid; 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=%s\n", keymap) < 0) { errorWindow("failed to write keyboard configuration: %s"); return INST_ERROR; } #ifdef __sparc__ if (fprintf(f, "KEYBOARDTYPE=%s\n", kbdtype) < 0) { errorWindow("failed to write keyboard configuration: %s"); return INST_ERROR; } #endif fclose(f); /* write default keymap */ if (strlen(prefix)>=14) { rootpath = alloca(strlen(prefix)); rootpath = strncpy(rootpath,prefix,strlen(prefix)-14); rootpath[strlen(prefix)-14]='\0'; if ((pid=fork())!=-1) { if (pid) { wait(&pid); } else { chroot(rootpath); system("/usr/bin/dumpkeys > /etc/sysconfig/console/default.kmap 2>/dev/null"); exit(0); } } } return 0; } int readKbdConfig(char * prefix, char ** keymap, char ** kbdtype) { 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; } if (strncmp("KEYTABLE=", buf, 9)) { errorWindow("unrecognized entry in keyboard configuration file"); fclose(f); 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 != '=') chptr--; if (*chptr == '.') *chptr-- = '\0'; while (chptr > buf && *chptr != '/' && *chptr != '=') chptr--; if (*chptr == '/' || *chptr == '=') chptr++; *keymap = strdup(chptr); #ifdef __sparc__ if (!fgets(buf, sizeof(buf) - 1, f)) { errorWindow("empty keyboard configuration file"); fclose(f); return INST_ERROR; } if (strncmp("KEYBOARDTYPE=", buf, 13)) { errorWindow("unrecognized entry in keyboard configuration file"); fclose(f); return INST_ERROR; } for (chptr = buf + 13; *chptr == ' ' || *chptr == '"' || *chptr == '\t'; chptr++); if (!strcasecmp (chptr, "pc")) *kbdtype = "pc"; else *kbdtype = "sun"; #endif fclose(f); return 0; }