--- trunk/grubby/grubby.c 2020/07/07 11:09:37 3136 +++ trunk/grubby/grubby.c 2020/07/07 11:24:19 3150 @@ -68,6 +68,8 @@ char *saved_command_line = NULL; +const char *mounts = "/proc/mounts"; + /* comments get lumped in with indention */ struct lineElement { char *item; @@ -480,20 +482,28 @@ snprintf(result, resultMaxSize, "%s", ++current); i++; + int result_len = 0; for (; i < line->numElements; ++i) { current = line->elements[i].item; current_len = strlen(current); current_indent = line->elements[i].indent; current_indent_len = strlen(current_indent); - strncat(result, current_indent, current_indent_len); + memcpy(result + result_len, current_indent, current_indent_len); + result_len += current_indent_len; + if (current[current_len - 1] != quote_char) { - strncat(result, current, current_len); + memcpy(result + result_len, current_indent, + current_indent_len); + result_len += current_len; } else { - strncat(result, current, current_len - 1); + memcpy(result + result_len, current_indent, + current_indent_len); + result_len += (current_len - 1); break; } } + result[result_len] = '\0'; return result; } @@ -701,7 +711,7 @@ struct configFileInfo *cfi); static int getNextLine(char **bufPtr, struct singleLine *line, struct configFileInfo *cfi); -static char *getRootSpecifier(char *str); +static size_t getRootSpecifier(const char *str); static void requote(struct singleLine *line, struct configFileInfo *cfi); static void insertElement(struct singleLine *line, const char *item, int insertHere, @@ -1438,6 +1448,7 @@ extras = malloc(len + 1); *extras = '\0'; + int buf_len = 0; /* get title. */ for (int i = 0; i < line->numElements; i++) { if (!strcmp @@ -1454,13 +1465,18 @@ len = strlen(title); if (title[len - 1] == quote_char) { - strncat(buf, title, len - 1); + memcpy(buf + buf_len, title, len - 1); + buf_len += (len - 1); break; } else { - strcat(buf, title); - strcat(buf, line->elements[i].indent); + memcpy(buf + buf_len, title, len); + buf_len += len; + len = strlen(line->elements[i].indent); + memcpy(buf + buf_len, line->elements[i].indent, len); + buf_len += len; } } + buf[buf_len] = '\0'; /* get extras */ int count = 0; @@ -2118,6 +2134,129 @@ return s[slen] == c; } +typedef struct { + const char *start; + size_t chars; +} field; + +static int iscomma(int c) +{ + return c == ','; +} + +static int isequal(int c) +{ + return c == '='; +} + +static field findField(const field *in, typeof(isspace) *isdelim, field *out) +{ + field nxt = {}; + size_t off = 0; + + while (off < in->chars && isdelim(in->start[off])) + off++; + + if (off == in->chars) + return nxt; + + out->start = &in->start[off]; + out->chars = 0; + + while (off + out->chars < in->chars && !isdelim(out->start[out->chars])) + out->chars++; + + nxt.start = out->start + out->chars; + nxt.chars = in->chars - off - out->chars; + return nxt; +} + +static int fieldEquals(const field *in, const char *str) +{ + return in->chars == strlen(str) && + strncmp(in->start, str, in->chars) == 0; +} + +/* Parse /proc/mounts to determine the subvolume prefix. */ +static size_t subvolPrefix(const char *str) +{ + FILE *file = NULL; + char *line = NULL; + size_t prfx = 0; + size_t size = 0; + + file = fopen(mounts, "r"); + if (!file) + return 0; + + for (ssize_t s; (s = getline(&line, &size, file)) >= 0; ) { + field nxt = { line, s }; + field dev = {}; + field path = {}; + field type = {}; + field opts = {}; + field opt = {}; + + nxt = findField(&nxt, isspace, &dev); + if (!nxt.start) + continue; + + nxt = findField(&nxt, isspace, &path); + if (!nxt.start) + continue; + + nxt = findField(&nxt, isspace, &type); + if (!nxt.start) + continue; + + nxt = findField(&nxt, isspace, &opts); + if (!nxt.start) + continue; + + if (!fieldEquals(&type, "btrfs")) + continue; + + /* We have found a btrfs mount point. */ + + nxt = opts; + while ((nxt = findField(&nxt, iscomma, &opt)).start) { + field key = {}; + field val = {}; + + opt = findField(&opt, isequal, &key); + if (!opt.start) + continue; + + opt = findField(&opt, isequal, &val); + if (!opt.start) + continue; + + if (!fieldEquals(&key, "subvol")) + continue; + + /* We have found a btrfs subvolume mount point. */ + + if (strncmp(val.start, str, val.chars)) + continue; + + if (val.start[val.chars - 1] != '/' && + str[val.chars] != '/') + continue; + + /* The subvolume mount point matches our input. */ + + if (prfx < val.chars) + prfx = val.chars; + } + } + + dbgPrintf("%s(): str: '%s', prfx: '%s'\n", __FUNCTION__, str, prfx); + + fclose(file); + free(line); + return prfx; +} + int suitableImage(struct singleEntry *entry, const char *bootPrefix, int skipRemoved, int flags) { @@ -2125,7 +2264,7 @@ char *fullName; int i; char *dev; - char *rootspec; + size_t rs; char *rootdev; if (skipRemoved && entry->skip) { @@ -2153,12 +2292,11 @@ fullName = alloca(strlen(bootPrefix) + strlen(line->elements[1].item) + 1); - rootspec = getRootSpecifier(line->elements[1].item); - int rootspec_offset = rootspec ? strlen(rootspec) : 0; + rs = getRootSpecifier(line->elements[1].item); int hasslash = endswith(bootPrefix, '/') || - beginswith(line->elements[1].item + rootspec_offset, '/'); + beginswith(line->elements[1].item + rs, '/'); sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/", - line->elements[1].item + rootspec_offset); + line->elements[1].item + rs); if (access(fullName, R_OK)) { notSuitablePrintf(entry, 0, "access to %s failed\n", fullName); return 0; @@ -2250,7 +2388,6 @@ struct singleLine *line; int i; char *chptr; - char *rootspec = NULL; enum lineType_e checkType = LT_KERNEL; if (isdigit(*kernel)) { @@ -2355,14 +2492,10 @@ if (line && line->type != LT_MENUENTRY && line->numElements >= 2) { - rootspec = - getRootSpecifier(line->elements[1]. - item); - if (!strcmp - (line->elements[1].item + - ((rootspec != - NULL) ? strlen(rootspec) : 0), - kernel + strlen(prefix))) + if (!strcmp(line->elements[1].item + + getRootSpecifier( + line->elements[1].item), + kernel + strlen(prefix))) break; } if (line->type == LT_MENUENTRY && @@ -3271,12 +3404,22 @@ type & (LT_HYPER | LT_KERNEL | LT_MBMODULE | LT_INITRD | LT_KERNEL_EFI | LT_INITRD_EFI | LT_KERNEL_16 | LT_INITRD_16)) { - char *rootspec = - getRootSpecifier(tmplLine->elements[1].item); - if (rootspec != NULL) { + const char *prfx = tmplLine->elements[1].item; + size_t rs = getRootSpecifier(prfx); + if (isinitrd(tmplLine->type)) { + for (struct singleLine *l = entry->lines; + rs == 0 && l; l = l->next) { + if (iskernel(l->type)) { + prfx = l->elements[1].item; + rs = getRootSpecifier(prfx); + break; + } + } + } + if (rs > 0) { free(newLine->elements[1].item); - newLine->elements[1].item = - sdupprintf("%s%s", rootspec, val); + newLine->elements[1].item = sdupprintf( + "%.*s%s", (int) rs, prfx, val); } } } @@ -3621,9 +3764,9 @@ if (!chptra && !chptrb) return 0; - else if (!chptra) + else if (!chptra && chptrb) return *chptrb - 0; - else if (!chptrb) + else if (!chptrb && chptra) return 0 - *chptra; else return strcmp(chptra, chptrb); @@ -4328,17 +4471,19 @@ return 1; } -static char *getRootSpecifier(char *str) +static size_t getRootSpecifier(const char *str) { - char *idx, *rootspec = NULL; + size_t rs = 0; if (*str == '(') { - idx = rootspec = strdup(str); - while (*idx && (*idx != ')') && (!isspace(*idx))) - idx++; - *(++idx) = '\0'; + for (; str[rs] != ')' && !isspace(str[rs]); rs++) { + if (!str[rs]) + return rs; + } + rs++; } - return rootspec; + + return rs + subvolPrefix(str + rs); } static char *getInitrdVal(struct grubConfig *config, @@ -4970,6 +5115,9 @@ {"mbargs", 0, POPT_ARG_STRING, &newMBKernelArgs, 0, _("default arguments for the new multiboot kernel or " "new arguments for multiboot kernel being updated"), NULL}, + {"mounts", 0, POPT_ARG_STRING, &mounts, 0, + _("path to fake /proc/mounts file (for testing only)"), + _("mounts")}, {"bad-image-okay", 0, 0, &badImageOkay, 0, _ ("don't sanity check images in boot entries (for testing only)"), @@ -5078,10 +5226,18 @@ exit(1); } saved_command_line[0] = '\0'; + int cmdline_len = 0, arg_len; for (int j = 1; j < argc; j++) { - strcat(saved_command_line, argv[j]); - strncat(saved_command_line, j == argc - 1 ? "" : " ", 1); + arg_len = strlen(argv[j]); + memcpy(saved_command_line + cmdline_len, argv[j], arg_len); + cmdline_len += arg_len; + if (j != argc - 1) { + memcpy(saved_command_line + cmdline_len, " ", 1); + cmdline_len++; + } + } + saved_command_line[cmdline_len] = '\0'; optCon = poptGetContext("grubby", argc, argv, options, 0); poptReadDefaultConfig(optCon, 1); @@ -5154,22 +5310,27 @@ if (!cfi) { if (grub2FindConfig(&grub2ConfigType)) { cfi = &grub2ConfigType; + configureGrub2 = 1; if (envPath) cfi->envFile = envPath; - } else + } else { #ifdef __ia64__ cfi = &eliloConfigType; -#elif __powerpc__ + configureLilo = 1; +#elif defined(__powerpc__) cfi = &yabootConfigType; -#elif __sparc__ + configureYaboot = 1; +#elif defined(__sparc__) cfi = &siloConfigType; -#elif __s390__ + configureSilo = 1; +#elif defined(__s390__) || defined(__s390x__) cfi = &ziplConfigType; -#elif __s390x__ - cfi = &ziplConfigtype; + configureZipl = 1; #else cfi = &grubConfigType; + configureGrub = 1; #endif + } } if (!grubConfig) { @@ -5363,7 +5524,7 @@ if (displayDefault) { struct singleLine *line; struct singleEntry *entry; - char *rootspec; + size_t rs; if (config->defaultImage == NO_DEFAULT_ENTRY) return 0; @@ -5382,9 +5543,8 @@ if (!line) return 0; - rootspec = getRootSpecifier(line->elements[1].item); - printf("%s%s\n", bootPrefix, line->elements[1].item + - ((rootspec != NULL) ? strlen(rootspec) : 0)); + rs = getRootSpecifier(line->elements[1].item); + printf("%s%s\n", bootPrefix, line->elements[1].item + rs); return 0;