--- trunk/grubby/grubby.c 2012/04/16 17:49:04 1802 +++ trunk/grubby/grubby.c 2012/07/02 13:11:38 1852 @@ -164,9 +164,9 @@ const char *grubFindConfig(struct configFileInfo *cfi) { static const char *configFiles[] = { - "/etc/grub.conf", "/boot/grub/grub.conf", "/boot/grub/menu.lst", + "/etc/grub.conf", NULL }; static int i = -1; @@ -243,10 +243,9 @@ } int sizeOfSingleLine(struct singleLine * line) { - int i; int count = 0; - for (i = 0; i < line->numElements; i++) { + for (int i = 0; i < line->numElements; i++) { int indentSize = 0; count = count + strlen(line->elements[i].item); @@ -573,8 +572,7 @@ static struct keywordTypes * getKeywordByType(enum lineType_e type, struct configFileInfo * cfi) { - struct keywordTypes * kw; - for (kw = cfi->keywords; kw->key; kw++) { + for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) { if (kw->type == type) return kw; } @@ -604,8 +602,7 @@ static enum lineType_e getTypeByKeyword(char * keyword, struct configFileInfo * cfi) { - struct keywordTypes * kw; - for (kw = cfi->keywords; kw->key; kw++) { + for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) { if (!strcmp(keyword, kw->key)) return kw->type; } @@ -692,7 +689,6 @@ } struct singleLine * lineDup(struct singleLine * line) { - int i; struct singleLine * newLine = malloc(sizeof(*newLine)); newLine->indent = strdup(line->indent); @@ -702,7 +698,7 @@ newLine->elements = malloc(sizeof(*newLine->elements) * newLine->numElements); - for (i = 0; i < newLine->numElements; i++) { + for (int i = 0; i < newLine->numElements; i++) { newLine->elements[i].indent = strdup(line->elements[i].indent); newLine->elements[i].item = strdup(line->elements[i].item); } @@ -711,11 +707,9 @@ } static void lineFree(struct singleLine * line) { - int i; - if (line->indent) free(line->indent); - for (i = 0; i < line->numElements; i++) { + for (int i = 0; i < line->numElements; i++) { free(line->elements[i].item); free(line->elements[i].indent); } @@ -726,11 +720,9 @@ static int lineWrite(FILE * out, struct singleLine * line, struct configFileInfo * cfi) { - int i; - if (fprintf(out, "%s", line->indent) == -1) return -1; - for (i = 0; i < line->numElements; i++) { + for (int i = 0; i < line->numElements; i++) { /* Need to handle this, because we strip the quotes from * menuentry when read it. */ if (line->type == LT_MENUENTRY && i == 1) { @@ -836,10 +828,9 @@ if (*line->elements[0].item == '#') { char * fullLine; int len; - int i; len = strlen(line->indent); - for (i = 0; i < line->numElements; i++) + for (int i = 0; i < line->numElements; i++) len += strlen(line->elements[i].item) + strlen(line->elements[i].indent); @@ -848,7 +839,7 @@ free(line->indent); line->indent = fullLine; - for (i = 0; i < line->numElements; i++) { + for (int i = 0; i < line->numElements; i++) { strcat(fullLine, line->elements[i].item); strcat(fullLine, line->elements[i].indent); free(line->elements[i].item); @@ -867,12 +858,10 @@ * elements up more */ if (!isspace(kw->separatorChar)) { - int i; char indent[2] = ""; indent[0] = kw->separatorChar; - for (i = 1; i < line->numElements; i++) { + for (int i = 1; i < line->numElements; i++) { char *p; - int j; int numNewElements; numNewElements = 0; @@ -888,7 +877,7 @@ sizeof(*line->elements) * elementsAlloced); } - for (j = line->numElements; j > i; j--) { + for (int j = line->numElements; j > i; j--) { line->elements[j + numNewElements] = line->elements[j]; } line->numElements += numNewElements; @@ -901,13 +890,11 @@ break; } - free(line->elements[i].indent); + line->elements[i + 1].indent = line->elements[i].indent; line->elements[i].indent = strdup(indent); *p++ = '\0'; i++; line->elements[i].item = strdup(p); - line->elements[i].indent = strdup(""); - p = line->elements[i].item; } } } @@ -928,7 +915,7 @@ struct singleLine * last = NULL, * line, * defaultLine = NULL; char * end; struct singleEntry * entry = NULL; - int i, len; + int len; char * buf; if (!strcmp(inName, "-")) { @@ -991,11 +978,10 @@ } if (line->type == LT_SET_VARIABLE) { - int i; dbgPrintf("found 'set' command (%d elements): ", line->numElements); dbgPrintf("%s", line->indent); - for (i = 0; i < line->numElements; i++) - dbgPrintf("%s\"%s\"", line->elements[i].indent, line->elements[i].item); + for (int i = 0; i < line->numElements; i++) + dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent); dbgPrintf("\n"); struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi); if (kwType && line->numElements == 3 && @@ -1022,8 +1008,7 @@ * This only applies to grub, but that's the only place we * should find LT_MBMODULE lines anyway. */ - struct singleLine * l; - for (l = entry->lines; l; l = l->next) { + for (struct singleLine *l = entry->lines; l; l = l->next) { if (l->type == LT_HYPER) break; else if (l->type == LT_KERNEL) { @@ -1043,14 +1028,14 @@ } else if (line->type == LT_TITLE && line->numElements > 1) { /* make the title a single argument (undoing our parsing) */ len = 0; - for (i = 1; i < line->numElements; i++) { + for (int i = 1; i < line->numElements; i++) { len += strlen(line->elements[i].item); len += strlen(line->elements[i].indent); } buf = malloc(len + 1); *buf = '\0'; - for (i = 1; i < line->numElements; i++) { + for (int i = 1; i < line->numElements; i++) { strcat(buf, line->elements[i].item); free(line->elements[i].item); @@ -1070,7 +1055,7 @@ char *extras; char *title; - for (i = 1; i < line->numElements; i++) { + for (int i = 1; i < line->numElements; i++) { len += strlen(line->elements[i].item); len += strlen(line->elements[i].indent); } @@ -1082,7 +1067,7 @@ *extras = '\0'; /* get title. */ - for (i = 0; i < line->numElements; i++) { + for (int i = 0; i < line->numElements; i++) { if (!strcmp(line->elements[i].item, "menuentry")) continue; if (isquote(*line->elements[i].item)) @@ -1102,8 +1087,8 @@ /* get extras */ int count = 0; - for (i = 0; i < line->numElements; i++) { - if (count == 2) { + for (int i = 0; i < line->numElements; i++) { + if (count >= 2) { strcat(extras, line->elements[i].item); strcat(extras, line->elements[i].indent); } @@ -1223,7 +1208,7 @@ cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10); if (*end) cfg->defaultImage = -1; } else if (defaultLine->numElements >= 2) { - i = 0; + int i = 0; while ((entry = findEntryByIndex(cfg, i))) { for (line = entry->lines; line; line = line->next) if (line->type == LT_TITLE) break; @@ -1325,7 +1310,7 @@ /* most likely the symlink is relative, so change our directory to the dir of the symlink */ - rc = chdir(dirname(strdupa(outName))); + rc = chdir(dirname(outName)); do { buf = alloca(len + 1); rc = readlink(basename(outName), buf, len); @@ -1463,6 +1448,8 @@ buf[rc] = '\0'; chptr = buf; + char *foundanswer = NULL; + while (chptr && chptr != buf+rc) { devname = chptr; @@ -1490,13 +1477,8 @@ * for '/' obviously. */ if (*(++chptr) == '/' && *(++chptr) == ' ') { - /* - * Move back 2, which is the first space after the device name, set - * it to \0 so strdup will just get the devicename. - */ - chptr -= 2; - *chptr = '\0'; - return strdup(devname); + /* remember the last / entry in mtab */ + foundanswer = devname; } /* Next line */ @@ -1505,6 +1487,13 @@ chptr++; } + /* Return the last / entry found */ + if (foundanswer) { + chptr = strchr(foundanswer, ' '); + *chptr = '\0'; + return strdup(foundanswer); + } + return NULL; } @@ -1965,7 +1954,10 @@ return; } - printf("kernel=%s%s\n", prefix, line->elements[1].item); + if (!strncmp(prefix, line->elements[1].item, strlen(prefix))) + printf("kernel=%s\n", line->elements[1].item); + else + printf("kernel=%s%s\n", prefix, line->elements[1].item); if (line->numElements >= 3) { printf("args=\""); @@ -2024,7 +2016,11 @@ line = getLineByType(LT_INITRD, entry->lines); if (line && line->numElements >= 2) { - printf("initrd=%s", prefix); + if (!strncmp(prefix, line->elements[1].item, strlen(prefix))) + printf("initrd="); + else + printf("initrd=%s", prefix); + for (i = 1; i < line->numElements; i++) printf("%s%s", line->elements[i].item, line->elements[i].indent); printf("\n"); @@ -2042,6 +2038,267 @@ } } +int isSuseSystem(void) { + const char * path; + const static char default_path[] = "/etc/SuSE-release"; + + if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL) + path = default_path; + + if (!access(path, R_OK)) + return 1; + return 0; +} + +int isSuseGrubConf(const char * path) { + FILE * grubConf; + char * line = NULL; + size_t len = 0, res = 0; + + grubConf = fopen(path, "r"); + if (!grubConf) { + dbgPrintf("Could not open SuSE configuration file '%s'\n", path); + return 0; + } + + while ((res = getline(&line, &len, grubConf)) != -1) { + if (!strncmp(line, "setup", 5)) { + fclose(grubConf); + free(line); + return 1; + } + } + + dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n", + path); + + fclose(grubConf); + free(line); + return 0; +} + +int suseGrubConfGetLba(const char * path, int * lbaPtr) { + FILE * grubConf; + char * line = NULL; + size_t res = 0, len = 0; + + if (!path) return 1; + if (!lbaPtr) return 1; + + grubConf = fopen(path, "r"); + if (!grubConf) return 1; + + while ((res = getline(&line, &len, grubConf)) != -1) { + if (line[res - 1] == '\n') + line[res - 1] = '\0'; + else if (len > res) + line[res] = '\0'; + else { + line = realloc(line, res + 1); + line[res] = '\0'; + } + + if (!strncmp(line, "setup", 5)) { + if (strstr(line, "--force-lba")) { + *lbaPtr = 1; + } else { + *lbaPtr = 0; + } + dbgPrintf("lba: %i\n", *lbaPtr); + break; + } + } + + free(line); + fclose(grubConf); + return 0; +} + +int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) { + FILE * grubConf; + char * line = NULL; + size_t res = 0, len = 0; + char * lastParamPtr = NULL; + char * secLastParamPtr = NULL; + char installDeviceNumber = '\0'; + char * bounds = NULL; + + if (!path) return 1; + if (!devicePtr) return 1; + + grubConf = fopen(path, "r"); + if (!grubConf) return 1; + + while ((res = getline(&line, &len, grubConf)) != -1) { + if (strncmp(line, "setup", 5)) + continue; + + if (line[res - 1] == '\n') + line[res - 1] = '\0'; + else if (len > res) + line[res] = '\0'; + else { + line = realloc(line, res + 1); + line[res] = '\0'; + } + + lastParamPtr = bounds = line + res; + + /* Last parameter in grub may be an optional IMAGE_DEVICE */ + while (!isspace(*lastParamPtr)) + lastParamPtr--; + lastParamPtr++; + + secLastParamPtr = lastParamPtr - 2; + dbgPrintf("lastParamPtr: %s\n", lastParamPtr); + + if (lastParamPtr + 3 > bounds) { + dbgPrintf("lastParamPtr going over boundary"); + fclose(grubConf); + free(line); + return 1; + } + if (!strncmp(lastParamPtr, "(hd", 3)) + lastParamPtr += 3; + dbgPrintf("lastParamPtr: %c\n", *lastParamPtr); + + /* + * Second last parameter will decide wether last parameter is + * an IMAGE_DEVICE or INSTALL_DEVICE + */ + while (!isspace(*secLastParamPtr)) + secLastParamPtr--; + secLastParamPtr++; + + if (secLastParamPtr + 3 > bounds) { + dbgPrintf("secLastParamPtr going over boundary"); + fclose(grubConf); + free(line); + return 1; + } + dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr); + if (!strncmp(secLastParamPtr, "(hd", 3)) { + secLastParamPtr += 3; + dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr); + installDeviceNumber = *secLastParamPtr; + } else { + installDeviceNumber = *lastParamPtr; + } + + *devicePtr = malloc(6); + snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber); + dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber); + fclose(grubConf); + free(line); + return 0; + } + + free(line); + fclose(grubConf); + return 1; +} + +int grubGetBootFromDeviceMap(const char * device, + char ** bootPtr) { + FILE * deviceMap; + char * line = NULL; + size_t res = 0, len = 0; + char * devicePtr; + char * bounds = NULL; + const char * path; + const static char default_path[] = "/boot/grub/device.map"; + + if (!device) return 1; + if (!bootPtr) return 1; + + if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL) + path = default_path; + + dbgPrintf("opening grub device.map file from: %s\n", path); + deviceMap = fopen(path, "r"); + if (!deviceMap) + return 1; + + while ((res = getline(&line, &len, deviceMap)) != -1) { + if (!strncmp(line, "#", 1)) + continue; + + if (line[res - 1] == '\n') + line[res - 1] = '\0'; + else if (len > res) + line[res] = '\0'; + else { + line = realloc(line, res + 1); + line[res] = '\0'; + } + + devicePtr = line; + bounds = line + res; + + while ((isspace(*line) && ((devicePtr + 1) <= bounds))) + devicePtr++; + dbgPrintf("device: %s\n", devicePtr); + + if (!strncmp(devicePtr, device, strlen(device))) { + devicePtr += strlen(device); + while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds)) + devicePtr++; + + *bootPtr = strdup(devicePtr); + break; + } + } + + free(line); + fclose(deviceMap); + return 0; +} + +int suseGrubConfGetBoot(const char * path, char ** bootPtr) { + char * grubDevice; + + if (suseGrubConfGetInstallDevice(path, &grubDevice)) + dbgPrintf("error looking for grub installation device\n"); + else + dbgPrintf("grubby installation device: %s\n", grubDevice); + + if (grubGetBootFromDeviceMap(grubDevice, bootPtr)) + dbgPrintf("error looking for grub boot device\n"); + else + dbgPrintf("grubby boot device: %s\n", *bootPtr); + + free(grubDevice); + return 0; +} + +int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) { + /* + * This SuSE grub configuration file at this location is not your average + * grub configuration file, but instead the grub commands used to setup + * grub on that system. + */ + const char * path; + const static char default_path[] = "/etc/grub.conf"; + + if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL) + path = default_path; + + if (!isSuseGrubConf(path)) return 1; + + if (lbaPtr) { + *lbaPtr = 0; + if (suseGrubConfGetLba(path, lbaPtr)) + return 1; + } + + if (bootPtr) { + *bootPtr = NULL; + suseGrubConfGetBoot(path, bootPtr); + } + + return 0; +} + int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) { FILE * in; char buf[1024]; @@ -2090,12 +2347,25 @@ } void dumpSysconfigGrub(void) { - char * boot; + char * boot = NULL; int lba; - if (!parseSysconfigGrub(&lba, &boot)) { - if (lba) printf("lba\n"); - if (boot) printf("boot=%s\n", boot); + if (isSuseSystem()) { + if (parseSuseGrubConf(&lba, &boot)) { + free(boot); + return; + } + } else { + if (parseSysconfigGrub(&lba, &boot)) { + free(boot); + return; + } + } + + if (lba) printf("lba\n"); + if (boot) { + printf("boot=%s\n", boot); + free(boot); } } @@ -2909,9 +3179,16 @@ int fd; unsigned char bootSect[512]; char * boot; + int onSuse = isSuseSystem(); - if (parseSysconfigGrub(NULL, &boot)) - return 0; + + if (onSuse) { + if (parseSuseGrubConf(NULL, &boot)) + return 0; + } else { + if (parseSysconfigGrub(NULL, &boot)) + return 0; + } /* assume grub is not installed -- not an error condition */ if (!boot) @@ -2930,6 +3207,12 @@ } close(fd); + /* The more elaborate checks do not work on SuSE. The checks done + * seem to be reasonble (at least for now), so just return success + */ + if (onSuse) + return 2; + return checkDeviceBootloader(boot, bootSect); } @@ -2977,7 +3260,7 @@ static char * getInitrdVal(struct grubConfig * config, const char * prefix, struct singleLine *tmplLine, const char * newKernelInitrd, - char ** extraInitrds, int extraInitrdCount) + const char ** extraInitrds, int extraInitrdCount) { char *initrdVal, *end; int i; @@ -3022,10 +3305,10 @@ int addNewKernel(struct grubConfig * config, struct singleEntry * template, const char * prefix, - char * newKernelPath, char * newKernelTitle, - char * newKernelArgs, char * newKernelInitrd, - char ** extraInitrds, int extraInitrdCount, - char * newMBKernel, char * newMBKernelArgs) { + const char * newKernelPath, const char * newKernelTitle, + const char * newKernelArgs, const char * newKernelInitrd, + const char ** extraInitrds, int extraInitrdCount, + const char * newMBKernel, const char * newMBKernelArgs) { struct singleEntry * new; struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL; int needs; @@ -3811,7 +4094,7 @@ } if (addNewKernel(config, template, bootPrefix, newKernelPath, newKernelTitle, newKernelArgs, newKernelInitrd, - extraInitrds, extraInitrdCount, + (const char **)extraInitrds, extraInitrdCount, newMBKernel, newMBKernelArgs)) return 1;