46 |
#define dbgPrintf(format, args...) |
#define dbgPrintf(format, args...) |
47 |
#endif |
#endif |
48 |
|
|
49 |
|
int debug = 0; /* Currently just for template debugging */ |
50 |
|
|
51 |
#define _(A) (A) |
#define _(A) (A) |
52 |
|
|
53 |
#define MAX_EXTRA_INITRDS 16 /* code segment checked by --bootloader-probe */ |
#define MAX_EXTRA_INITRDS 16 /* code segment checked by --bootloader-probe */ |
54 |
#define CODE_SEG_SIZE 128 /* code segment checked by --bootloader-probe */ |
#define CODE_SEG_SIZE 128 /* code segment checked by --bootloader-probe */ |
55 |
|
|
56 |
|
#define NOOP_OPCODE 0x90 |
57 |
|
#define JMP_SHORT_OPCODE 0xeb |
58 |
|
|
59 |
/* comments get lumped in with indention */ |
/* comments get lumped in with indention */ |
60 |
struct lineElement { |
struct lineElement { |
61 |
char * item; |
char * item; |
876 |
cfg->secondaryIndent = strdup(line->indent); |
cfg->secondaryIndent = strdup(line->indent); |
877 |
} |
} |
878 |
|
|
879 |
if (isEntryStart(line, cfi)) { |
if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) { |
880 |
sawEntry = 1; |
sawEntry = 1; |
881 |
if (!entry) { |
if (!entry) { |
882 |
cfg->entries = malloc(sizeof(*entry)); |
cfg->entries = malloc(sizeof(*entry)); |
1340 |
return NULL; |
return NULL; |
1341 |
} |
} |
1342 |
|
|
1343 |
|
void printEntry(struct singleEntry * entry) { |
1344 |
|
int i; |
1345 |
|
struct singleLine * line; |
1346 |
|
|
1347 |
|
for (line = entry->lines; line; line = line->next) { |
1348 |
|
fprintf(stderr, "DBG: %s", line->indent); |
1349 |
|
for (i = 0; i < line->numElements; i++) { |
1350 |
|
fprintf(stderr, "%s%s", |
1351 |
|
line->elements[i].item, line->elements[i].indent); |
1352 |
|
} |
1353 |
|
fprintf(stderr, "\n"); |
1354 |
|
} |
1355 |
|
} |
1356 |
|
|
1357 |
|
void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...) |
1358 |
|
{ |
1359 |
|
va_list argp; |
1360 |
|
|
1361 |
|
if (!debug) |
1362 |
|
return; |
1363 |
|
|
1364 |
|
va_start(argp, fmt); |
1365 |
|
fprintf(stderr, "DBG: Image entry failed: "); |
1366 |
|
vfprintf(stderr, fmt, argp); |
1367 |
|
printEntry(entry); |
1368 |
|
va_end(argp); |
1369 |
|
} |
1370 |
|
|
1371 |
int suitableImage(struct singleEntry * entry, const char * bootPrefix, |
int suitableImage(struct singleEntry * entry, const char * bootPrefix, |
1372 |
int skipRemoved, int flags) { |
int skipRemoved, int flags) { |
1373 |
struct singleLine * line; |
struct singleLine * line; |
1377 |
char * rootspec; |
char * rootspec; |
1378 |
char * rootdev; |
char * rootdev; |
1379 |
|
|
1380 |
if (skipRemoved && entry->skip) return 0; |
if (skipRemoved && entry->skip) { |
1381 |
|
notSuitablePrintf(entry, "marked to skip\n"); |
1382 |
|
return 0; |
1383 |
|
} |
1384 |
|
|
1385 |
line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines); |
line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines); |
1386 |
if (!line || line->numElements < 2) return 0; |
if (!line) { |
1387 |
|
notSuitablePrintf(entry, "no line found\n"); |
1388 |
|
return 0; |
1389 |
|
} |
1390 |
|
if (line->numElements < 2) { |
1391 |
|
notSuitablePrintf(entry, "line has only %d elements\n", |
1392 |
|
line->numElements); |
1393 |
|
return 0; |
1394 |
|
} |
1395 |
|
|
1396 |
if (flags & GRUBBY_BADIMAGE_OKAY) return 1; |
if (flags & GRUBBY_BADIMAGE_OKAY) return 1; |
1397 |
|
|
1400 |
rootspec = getRootSpecifier(line->elements[1].item); |
rootspec = getRootSpecifier(line->elements[1].item); |
1401 |
sprintf(fullName, "%s%s", bootPrefix, |
sprintf(fullName, "%s%s", bootPrefix, |
1402 |
line->elements[1].item + (rootspec ? strlen(rootspec) : 0)); |
line->elements[1].item + (rootspec ? strlen(rootspec) : 0)); |
1403 |
if (access(fullName, R_OK)) return 0; |
if (access(fullName, R_OK)) { |
1404 |
|
notSuitablePrintf(entry, "access to %s failed\n", fullName); |
1405 |
|
return 0; |
1406 |
|
} |
1407 |
for (i = 2; i < line->numElements; i++) |
for (i = 2; i < line->numElements; i++) |
1408 |
if (!strncasecmp(line->elements[i].item, "root=", 5)) break; |
if (!strncasecmp(line->elements[i].item, "root=", 5)) break; |
1409 |
if (i < line->numElements) { |
if (i < line->numElements) { |
1421 |
line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines); |
line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines); |
1422 |
|
|
1423 |
/* failed to find one */ |
/* failed to find one */ |
1424 |
if (!line) return 0; |
if (!line) { |
1425 |
|
notSuitablePrintf(entry, "no line found\n"); |
1426 |
|
return 0; |
1427 |
|
} |
1428 |
|
|
1429 |
for (i = 1; i < line->numElements; i++) |
for (i = 1; i < line->numElements; i++) |
1430 |
if (!strncasecmp(line->elements[i].item, "root=", 5)) break; |
if (!strncasecmp(line->elements[i].item, "root=", 5)) break; |
1431 |
if (i < line->numElements) |
if (i < line->numElements) |
1432 |
dev = line->elements[i].item + 5; |
dev = line->elements[i].item + 5; |
1433 |
else { |
else { |
1434 |
|
notSuitablePrintf(entry, "no root= entry found\n"); |
1435 |
/* it failed too... can't find root= */ |
/* it failed too... can't find root= */ |
1436 |
return 0; |
return 0; |
1437 |
} |
} |
1439 |
} |
} |
1440 |
|
|
1441 |
dev = getpathbyspec(dev); |
dev = getpathbyspec(dev); |
1442 |
if (!dev) |
if (!getpathbyspec(dev)) { |
1443 |
|
notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev); |
1444 |
return 0; |
return 0; |
1445 |
|
} else |
1446 |
|
dev = getpathbyspec(dev); |
1447 |
|
|
1448 |
rootdev = findDiskForRoot(); |
rootdev = findDiskForRoot(); |
1449 |
if (!rootdev) |
if (!rootdev) { |
1450 |
|
notSuitablePrintf(entry, "can't find root device\n"); |
1451 |
return 0; |
return 0; |
1452 |
|
} |
1453 |
|
|
1454 |
if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) { |
if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) { |
1455 |
|
notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n", |
1456 |
|
getuuidbydev(rootdev), getuuidbydev(dev)); |
1457 |
free(rootdev); |
free(rootdev); |
1458 |
return 0; |
return 0; |
1459 |
} |
} |
1460 |
|
|
1461 |
if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) { |
if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) { |
1462 |
|
notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n", |
1463 |
|
getuuidbydev(rootdev), getuuidbydev(dev)); |
1464 |
free(rootdev); |
free(rootdev); |
1465 |
return 0; |
return 0; |
1466 |
} |
} |
2527 |
if (memcmp(boot, bootSect, 3)) |
if (memcmp(boot, bootSect, 3)) |
2528 |
return 0; |
return 0; |
2529 |
|
|
2530 |
if (boot[1] == 0xeb) { |
if (boot[1] == JMP_SHORT_OPCODE) { |
2531 |
offset = boot[2] + 2; |
offset = boot[2] + 2; |
2532 |
} else if (boot[1] == 0xe8 || boot[1] == 0xe9) { |
} else if (boot[1] == 0xe8 || boot[1] == 0xe9) { |
2533 |
offset = (boot[3] << 8) + boot[2] + 2; |
offset = (boot[3] << 8) + boot[2] + 2; |
2534 |
} else if (boot[0] == 0xeb) { |
} else if (boot[0] == JMP_SHORT_OPCODE) { |
2535 |
offset = boot[1] + 2; |
offset = boot[1] + 2; |
2536 |
|
/* |
2537 |
|
* it looks like grub, when copying stage1 into the mbr, patches stage1 |
2538 |
|
* right after the JMP location, replacing other instructions such as |
2539 |
|
* JMPs for NOOPs. So, relax the check a little bit by skipping those |
2540 |
|
* different bytes. |
2541 |
|
*/ |
2542 |
|
if ((bootSect[offset + 1] == NOOP_OPCODE) |
2543 |
|
&& (bootSect[offset + 2] == NOOP_OPCODE)) { |
2544 |
|
offset = offset + 3; |
2545 |
|
} |
2546 |
} else if (boot[0] == 0xe8 || boot[0] == 0xe9) { |
} else if (boot[0] == 0xe8 || boot[0] == 0xe9) { |
2547 |
offset = (boot[2] << 8) + boot[1] + 2; |
offset = (boot[2] << 8) + boot[1] + 2; |
2548 |
} else { |
} else { |
3017 |
} |
} |
3018 |
} else if (tmplLine->type == LT_ECHO) { |
} else if (tmplLine->type == LT_ECHO) { |
3019 |
requote(tmplLine, config->cfi); |
requote(tmplLine, config->cfi); |
3020 |
|
static const char *prefix = "'Loading "; |
3021 |
if (tmplLine->numElements > 1 && |
if (tmplLine->numElements > 1 && |
3022 |
strstr(tmplLine->elements[1].item, "'Loading Linux ")) { |
strstr(tmplLine->elements[1].item, prefix) && |
3023 |
char *prefix = "'Loading "; |
masterLine->next && masterLine->next->type == LT_KERNEL) { |
3024 |
char *newTitle = malloc(strlen(prefix) + |
char *newTitle = malloc(strlen(prefix) + |
3025 |
strlen(newKernelTitle) + 2); |
strlen(newKernelTitle) + 2); |
3026 |
|
|
3217 |
struct singleEntry * template = NULL; |
struct singleEntry * template = NULL; |
3218 |
int copyDefault = 0, makeDefault = 0; |
int copyDefault = 0, makeDefault = 0; |
3219 |
int displayDefault = 0; |
int displayDefault = 0; |
3220 |
|
int displayDefaultIndex = 0; |
3221 |
|
int displayDefaultTitle = 0; |
3222 |
struct poptOption options[] = { |
struct poptOption options[] = { |
3223 |
{ "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0, |
{ "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0, |
3224 |
_("add an entry for the specified kernel"), _("kernel-path") }, |
_("add an entry for the specified kernel"), _("kernel-path") }, |
3249 |
"the kernel referenced by the default image does not exist, " |
"the kernel referenced by the default image does not exist, " |
3250 |
"the first linux entry whose kernel does exist is used as the " |
"the first linux entry whose kernel does exist is used as the " |
3251 |
"template"), NULL }, |
"template"), NULL }, |
3252 |
|
{ "debug", 0, 0, &debug, 0, |
3253 |
|
_("print debugging information for failures") }, |
3254 |
{ "default-kernel", 0, 0, &displayDefault, 0, |
{ "default-kernel", 0, 0, &displayDefault, 0, |
3255 |
_("display the path of the default kernel") }, |
_("display the path of the default kernel") }, |
3256 |
|
{ "default-index", 0, 0, &displayDefaultIndex, 0, |
3257 |
|
_("display the index of the default kernel") }, |
3258 |
|
{ "default-title", 0, 0, &displayDefaultTitle, 0, |
3259 |
|
_("display the title of the default kernel") }, |
3260 |
{ "elilo", 0, POPT_ARG_NONE, &configureELilo, 0, |
{ "elilo", 0, POPT_ARG_NONE, &configureELilo, 0, |
3261 |
_("configure elilo bootloader") }, |
_("configure elilo bootloader") }, |
3262 |
{ "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0, |
{ "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0, |
3400 |
|
|
3401 |
if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion || |
if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion || |
3402 |
newKernelPath || removeKernelPath || makeDefault || |
newKernelPath || removeKernelPath || makeDefault || |
3403 |
defaultKernel)) { |
defaultKernel || displayDefaultIndex || displayDefaultTitle)) { |
3404 |
fprintf(stderr, _("grubby: --bootloader-probe may not be used with " |
fprintf(stderr, _("grubby: --bootloader-probe may not be used with " |
3405 |
"specified option")); |
"specified option")); |
3406 |
return 1; |
return 1; |
3451 |
|
|
3452 |
if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel |
if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel |
3453 |
&& !kernelInfo && !bootloaderProbe && !updateKernelPath |
&& !kernelInfo && !bootloaderProbe && !updateKernelPath |
3454 |
&& !removeMBKernel) { |
&& !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle) { |
3455 |
fprintf(stderr, _("grubby: no action specified\n")); |
fprintf(stderr, _("grubby: no action specified\n")); |
3456 |
return 1; |
return 1; |
3457 |
} |
} |
3546 |
((rootspec != NULL) ? strlen(rootspec) : 0)); |
((rootspec != NULL) ? strlen(rootspec) : 0)); |
3547 |
|
|
3548 |
return 0; |
return 0; |
3549 |
|
|
3550 |
|
} else if (displayDefaultTitle) { |
3551 |
|
struct singleLine * line; |
3552 |
|
struct singleEntry * entry; |
3553 |
|
|
3554 |
|
if (config->defaultImage == -1) return 0; |
3555 |
|
entry = findEntryByIndex(config, config->defaultImage); |
3556 |
|
if (!entry) return 0; |
3557 |
|
|
3558 |
|
if (!configureGrub2) { |
3559 |
|
line = getLineByType(LT_TITLE, entry->lines); |
3560 |
|
if (!line) return 0; |
3561 |
|
printf("%s\n", line->elements[1].item); |
3562 |
|
|
3563 |
|
} else { |
3564 |
|
int i; |
3565 |
|
size_t len; |
3566 |
|
char * start; |
3567 |
|
char * tmp; |
3568 |
|
|
3569 |
|
dbgPrintf("This is GRUB2, default title is embeded in menuentry\n"); |
3570 |
|
line = getLineByType(LT_MENUENTRY, entry->lines); |
3571 |
|
if (!line) return 0; |
3572 |
|
|
3573 |
|
for (i = 0; i < line->numElements; i++) { |
3574 |
|
|
3575 |
|
if (!strcmp(line->elements[i].item, "menuentry")) |
3576 |
|
continue; |
3577 |
|
|
3578 |
|
if (*line->elements[i].item == '\'') |
3579 |
|
start = line->elements[i].item + 1; |
3580 |
|
else |
3581 |
|
start = line->elements[i].item; |
3582 |
|
|
3583 |
|
len = strlen(start); |
3584 |
|
if (*(start + len - 1) == '\'') { |
3585 |
|
tmp = strdup(start); |
3586 |
|
*(tmp + len - 1) = '\0'; |
3587 |
|
printf("%s", tmp); |
3588 |
|
free(tmp); |
3589 |
|
break; |
3590 |
|
} else { |
3591 |
|
printf("%s ", start); |
3592 |
|
} |
3593 |
|
} |
3594 |
|
printf("\n"); |
3595 |
|
} |
3596 |
|
return 0; |
3597 |
|
|
3598 |
|
} else if (displayDefaultIndex) { |
3599 |
|
if (config->defaultImage == -1) return 0; |
3600 |
|
printf("%i\n", config->defaultImage); |
3601 |
|
|
3602 |
} else if (kernelInfo) |
} else if (kernelInfo) |
3603 |
return displayInfo(config, kernelInfo, bootPrefix); |
return displayInfo(config, kernelInfo, bootPrefix); |
3604 |
|
|