#include #include #include #include #include #include #include #include #include #include #include #include #include /* XXX rpmlib.h */ #include /* XXX rpmlib.h */ #include #include #include "isys/cpio.h" #include "loader.h" #include "lang.h" #include "log.h" #include "windows.h" #define errorWindow(String) \ newtWinMessage(_("Error"), _("OK"), String, strerror (errno)); extern int haveKon; struct aString { unsigned int hash; short length; char * str; } ; struct aString * strings = NULL; int numStrings = 0, allocedStrings = 0; static int aStringCmp(const void * a, const void * b) { const struct aString * first = a; const struct aString * second = b; if (first->hash < second->hash) return -1; else if (first->hash == second->hash) return 0; return 1; } static int simpleStringCmp(const void * a, const void * b) { const char * first = *((const char **) a); const char * second = *((const char **) b); return strcmp(first, second); } char * translateString(char * str) { unsigned int sum = 0, xor = 0; int len = 0; char * chptr; struct aString * match; struct aString key; for (chptr = str; *chptr; chptr++) { sum += *chptr; xor ^= *chptr; len++; } key.hash = (sum << 16) | ((xor & 0xFF) << 8) | (len & 0xFF); match = bsearch(&key, strings, numStrings, sizeof(*strings), aStringCmp); if (!match) return str; return match->str; } struct langInfo { char * lang, * key, * font, * map, * lc_all, * keyboard; } ; static struct langInfo * languages = NULL; static int numLanguages = 0; static void loadLanguageList(int flags) { char * file = FL_TESTING(flags) ? "../lang-table" : "/etc/lang-table"; FILE * f; char line[256]; char name[256], key[256], sun[256], console[256], code[256], keyboard[256], timezone[256]; int lineNum = 0; f = fopen(file, "r"); if (!f) { newtWinMessage(_("Error"), _("OK"), "cannot open %s: %s", file, strerror (errno)); return; } while (fgets(line, sizeof(line), f)) { lineNum++; languages = realloc(languages, sizeof(*languages) * (numLanguages + 1)); if (sscanf(line, "%s %s %s %s %s %s %s\n", name, key, sun, console, code, keyboard, timezone) != 7) { logMessage("bad line %d in lang-table", lineNum); } else { if (!haveKon && !strcmp (name, "Japanese")) continue; languages[numLanguages].lang = strdup(name); languages[numLanguages].key = strdup(key); languages[numLanguages].font = strdup(sun); languages[numLanguages].map = strdup(console); languages[numLanguages].lc_all = strdup(code); languages[numLanguages].keyboard = strdup(keyboard); numLanguages++; } } } void loadLanguage (char * file, int flags) { char filename[200]; gzFile stream; int fd, hash, rc; char * key = getenv("LANGKEY"); if (!key || !strcmp(key, "en_US")) { if (strings) { free(strings), strings = NULL; numStrings = allocedStrings = 0; } return; } if (!file) { file = filename; if (FL_TESTING(flags)) sprintf(filename, "loader.tr"); else sprintf(filename, "/etc/loader.tr"); } stream = gzopen(file, "r"); if (!stream) { newtWinMessage("Error", "OK", "Cannot open %s: %s. Installation will " "proceed in English.", file, strerror(errno)); return ; } sprintf(filename, "%s.tr", key); rc = installCpioFile(stream, filename, "/tmp/translation", 1); gzclose(stream); if (rc || access("/tmp/translation", R_OK)) { newtWinMessage("Error", "OK", "Cannot get translation file %s.\n", filename); return; } fd = open("/tmp/translation", O_RDONLY); if (fd < 0) { newtWinMessage("Error", "OK", "Failed to open /tmp/translation: %s\n", strerror(errno)); return; } while (read(fd, &hash, 4) == 4) { if (allocedStrings == numStrings) { allocedStrings += 10; strings = realloc(strings, sizeof(*strings) * allocedStrings); } strings[numStrings].hash = ntohl(hash); read(fd, &strings[numStrings].length, 2); strings[numStrings].length = ntohs(strings[numStrings].length); strings[numStrings].str = malloc(strings[numStrings].length + 1); read(fd, strings[numStrings].str, strings[numStrings].length); strings[numStrings].str[strings[numStrings].length] = '\0'; numStrings++; } close(fd); unlink("/tmp/translation"); qsort(strings, numStrings, sizeof(*strings), aStringCmp); } static int loadFont(char * fontFile, int flags) { char font[8192]; unsigned short map[E_TABSZ]; struct unimapdesc d; struct unimapinit u; struct unipair desc[2048]; int fd; gzFile stream; int rc; if (!strcmp(fontFile, "None")) return 0; #if 0 if (!FL_TESTING(flags)) { #endif stream = gzopen("/etc/fonts.cgz", "r"); if (!stream) { newtWinMessage("Error", "OK", "Cannot open fonts: %s", strerror(errno)); return LOADER_ERROR; } rc = installCpioFile(stream, fontFile, "/tmp/font", 1); gzclose(stream); if (rc || access("/tmp/font", R_OK)) { return LOADER_ERROR; } fd = open("/tmp/font", O_RDONLY); read(fd, font, sizeof(font)); read(fd, map, sizeof(map)); read(fd, &d.entry_ct, sizeof(d.entry_ct)); d.entries = desc; read(fd, desc, d.entry_ct * sizeof(desc[0])); close(fd); if (ioctl(1, PIO_FONT, font)) logMessage("PIO_FONT failed: %s", strerror(errno)); if (ioctl(1, PIO_UNIMAPCLR, &u)) logMessage("PIO_UNIMAPCLR failed: %s", strerror(errno)); if (ioctl(1, PIO_UNIMAP, &d)) logMessage("PIO_UNIMAP failed: %s", strerror(errno)); if (ioctl(1, PIO_UNISCRNMAP, map)) logMessage("PIO_UNISCRNMAP failed: %s", strerror(errno)); fprintf(stderr, "\033(K"); #if 0 } #endif return 0; } void setLanguage (char * key, int flags) { int i; if (!languages) loadLanguageList(flags); for (i = 0; i < numLanguages; i++) { if (!strcmp(languages[i].key, key)) { setenv("LANG", languages[i].lc_all, 1); setenv("LANGKEY", languages[i].key, 1); setenv("LC_ALL", languages[i].lc_all, 1); setenv("LINGUAS", languages[i].lc_all, 1); loadLanguage (NULL, flags); if (languages[i].map) loadFont(languages[i].map, 0); break; } } } int chooseLanguage(char ** lang, int flags) { int choice = 0; char ** langs; int i; int english = 0; if (!languages) loadLanguageList(flags); langs = alloca(sizeof(*langs) * (numLanguages + 1)); for (i = 0; i < numLanguages; i++) { if (!strncmp(languages[i].key, "en", 2)) english = i; langs[i] = languages[i].lang; } langs[i] = NULL; choice = english; if (getenv("LANG")) { for (choice = 0; choice < numLanguages; choice++) if (!strcmp(languages[choice].lc_all, getenv("LANG"))) break; if (choice == numLanguages) choice = 0; } newtWinMenu(_("Choose a Language"), _("What language should be used " "during the installation process?"), 40, 5, 5, 8, langs, &choice, _("OK"), NULL); *lang = languages[choice].lc_all; if (choice == english) { /* stick with the default (English) */ unsetenv("LANG"); unsetenv("LANGKEY"); unsetenv("LC_ALL"); unsetenv("LINGUAS"); if (strings) { free(strings), strings = NULL; numStrings = allocedStrings = 0; } return 0; } setenv("LANG", languages[choice].lc_all, 1); setenv("LANGKEY", languages[choice].key, 1); setenv("LC_ALL", languages[choice].lc_all, 1); setenv("LINGUAS", languages[choice].lc_all, 1); if (strings) { free(strings), strings = NULL; numStrings = allocedStrings = 0; } if (haveKon) { extern int continuing; extern void stopNewt(void); if (!strcmp (languages[choice].key, "ja") && !continuing) { char * args[4]; stopNewt(); args[0] = "kon"; args[1] = "-e"; args[2] = FL_TESTING(flags) ? "./loader" : "/sbin/continue"; args[3] = NULL; execv(FL_TESTING(flags) ? "./loader" : "/sbin/loader", args); } } loadLanguage (NULL, flags); if (languages[choice].map) loadFont(languages[choice].map, flags); newtDrawRootText(0, 0, _("Welcome to Red Hat Linux")); newtPushHelpLine(_(" / between elements | selects | next screen ")); return 0; } #ifdef __sparc__ struct defaultKeyboardByLang { char * lang, * keyboard; } defaultSunKeyboards[] = { { "fi_FI", "sunt5-fi-latin1" }, { "cs_CZ", "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 LOADER_ERROR; } if (magic != KMAP_MAGIC) { logMessage("bad magic for keymap!"); return LOADER_ERROR; } if (gzread(stream, keymaps, sizeof(keymaps)) != sizeof(keymaps)) { logMessage("failed to read keymap header: %s", strerror(errno)); return LOADER_ERROR; } console = open("/dev/console", O_RDWR); if (console < 0) { logMessage("failed to open /dev/console: %s", strerror(errno)); return LOADER_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 LOADER_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 chooseKeyboard(char ** keymap, char ** kbdtypep, int flags) { int num = -1; int rc; gzFile f; struct kmapHeader hdr; struct kmapInfo * infoTable; char ** kbds; char buf[16384]; /* I hope this is big enough */ int i; char * defkbd = keymap ? *keymap : NULL; struct defaultKeyboardByLang * kbdEntry; char *lang; #ifdef __sparc__ #define KBDTYPE_SUN 0 #define KBDTYPE_PC 1 int kbdtype = -1; int j; #endif if (FL_SERIAL (flags)) return LOADER_NOOP; /*if (testing) return 0;*/ #ifdef __sparc__ #if 0 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 #endif { 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 (!languages) loadLanguageList(flags); lang = getenv("LANG"); if (!defkbd && lang) { for (i = 0; i < numLanguages; i++) { if (!strncmp(languages[i].lc_all, lang, 2)) { defkbd = languages[i].keyboard; break; } } #ifdef __sparc__ if (kbdtype == KBDTYPE_SUN) kbdEntry = defaultSunKeyboards; while (kbdEntry->lang && strcmp(kbdEntry->lang, getenv("LANG"))) kbdEntry++; if (kbdEntry->keyboard) defkbd = kbdEntry->keyboard; #endif } 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 LOADER_ERROR; } if (gzread(f, &hdr, sizeof(hdr)) != sizeof(hdr)) { errorWindow("failed to read keymaps header: %s"); gzclose(f); return LOADER_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 LOADER_ERROR; } #if 0 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]); } } } #endif 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; i++; } #else kbds = alloca(sizeof(*kbds) * (hdr.numEntries + 1)); for (i = 0; i < hdr.numEntries; i++) { kbds[i] = infoTable[i].name; } #endif kbds[i] = NULL; qsort(kbds, i, sizeof(*kbds), simpleStringCmp); for (i = 0; i < hdr.numEntries; i++) if (!strcmp(kbds[i], defkbd)) num = i; rc = newtWinMenu(_("Keyboard Type"), _("What type of keyboard do you have?"), 40, 5, 5, 8, kbds, &num, _("OK"), _("Back"), NULL); if (rc == 2) return LOADER_BACK; /* num needs to index the right keyboard infoTable */ for (i = 0; i < hdr.numEntries; i++) if (!strcmp(kbds[num], infoTable[i].name)) break; num = i; } 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 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 = LOADER_ERROR; } } if (!rc) rc = loadKeymap(f); gzclose(f); if (keymap) *keymap = strdup(infoTable[num].name); #ifdef __sparc__ if (kbdtypep) *kbdtypep = (kbdtype == KBDTYPE_SUN) ? "sun" : "pc"; #endif return rc; }