--- trunk/mkinitrd-magellan/grubby/grubby.c 2009/10/28 13:29:38 926 +++ trunk/mkinitrd-magellan/grubby/grubby.c 2010/09/14 19:47:52 1156 @@ -356,6 +356,8 @@ struct configFileInfo * cfi; }; +blkid_cache blkid; + struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index); struct singleEntry * findEntryByPath(struct grubConfig * cfg, const char * path, const char * prefix, @@ -434,14 +436,19 @@ } static char * getpathbyspec(char *device) { - static blkid_cache blkid; - if (!blkid) blkid_get_cache(&blkid, NULL); return blkid_get_devname(blkid, device, NULL); } +static char * getuuidbydev(char *device) { + if (!blkid) + blkid_get_cache(&blkid, NULL); + + return blkid_get_tag_value(blkid, "UUID", device); +} + static enum lineType_e getTypeByKeyword(char * keyword, struct configFileInfo * cfi) { struct keywordTypes * kw; @@ -1155,14 +1162,84 @@ return i; } +static char *findDiskForRoot() +{ + int fd; + char buf[65536]; + char *devname; + char *chptr; + int rc; + + if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) { + fprintf(stderr, "grubby: failed to open %s: %s\n", + _PATH_MOUNTED, strerror(errno)); + return NULL; + } + + rc = read(fd, buf, sizeof(buf) - 1); + if (rc <= 0) { + fprintf(stderr, "grubby: failed to read %s: %s\n", + _PATH_MOUNTED, strerror(errno)); + close(fd); + return NULL; + } + close(fd); + buf[rc] = '\0'; + chptr = buf; + + while (chptr && chptr != buf+rc) { + devname = chptr; + + /* + * The first column of a mtab entry is the device, but if the entry is a + * special device it won't start with /, so move on to the next line. + */ + if (*devname != '/') { + chptr = strchr(chptr, '\n'); + if (chptr) + chptr++; + continue; + } + + /* Seek to the next space */ + chptr = strchr(chptr, ' '); + if (!chptr) { + fprintf(stderr, "grubby: error parsing %s: %s\n", + _PATH_MOUNTED, strerror(errno)); + return NULL; + } + + /* + * The second column of a mtab entry is the mount point, we are looking + * 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); + } + + /* Next line */ + chptr = strchr(chptr, '\n'); + if (chptr) + chptr++; + } + + return NULL; +} + int suitableImage(struct singleEntry * entry, const char * bootPrefix, int skipRemoved, int flags) { struct singleLine * line; char * fullName; int i; - struct stat sb, sb2; char * dev; char * rootspec; + char * rootdev; if (skipRemoved && entry->skip) return 0; @@ -1212,14 +1289,17 @@ if (!dev) return 0; - i = stat(dev, &sb); - if (i) + rootdev = findDiskForRoot(); + if (!rootdev) return 0; - stat("/", &sb2); - if (sb.st_rdev != sb2.st_dev) + if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) { + free(rootdev); return 0; + } + + free(rootdev); return 1; } @@ -2119,6 +2199,34 @@ return rc; } +int updateInitrd(struct grubConfig * cfg, const char * image, + const char * prefix, const char * initrd) { + struct singleEntry * entry; + struct singleLine * line, * kernelLine; + int index = 0; + + if (!image) return 0; + + for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) { + kernelLine = getLineByType(LT_KERNEL, entry->lines); + if (!kernelLine) continue; + + line = getLineByType(LT_INITRD, entry->lines); + if (line) + removeLine(entry, line); + if (prefix) { + int prefixLen = strlen(prefix); + if (!strncmp(initrd, prefix, prefixLen)) + initrd += prefixLen; + } + line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd); + if (!line) return 1; + break; + } + + return 0; +} + int checkDeviceBootloader(const char * device, const unsigned char * boot) { int fd; unsigned char bootSect[512]; @@ -2948,8 +3056,8 @@ if (newKernelPath && !newKernelTitle) { fprintf(stderr, _("grubby: kernel title must be specified\n")); return 1; - } else if (!newKernelPath && (newKernelTitle || newKernelInitrd || - newKernelInitrd || copyDefault || + } else if (!newKernelPath && (newKernelTitle || copyDefault || + (newKernelInitrd && !updateKernelPath)|| makeDefault || extraInitrdCount > 0)) { fprintf(stderr, _("grubby: kernel path expected\n")); return 1; @@ -3082,6 +3190,10 @@ setFallbackImage(config, newKernelPath != NULL); if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs, removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1; + if (updateKernelPath && newKernelInitrd) { + if (updateInitrd(config, updateKernelPath, bootPrefix, + newKernelInitrd)) return 1; + } if (addNewKernel(config, template, bootPrefix, newKernelPath, newKernelTitle, newKernelArgs, newKernelInitrd, extraInitrds, extraInitrdCount,