From bfb7c70e7eaa1311cadc716c303ca694163f9e2f Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 19 Feb 2013 18:00:36 -0500 Subject: [PATCH] Add logging when things fail. Actually also logs when things succeed. Signed-off-by: Peter Jones --- Makefile | 2 +- grubby.c | 92 ++++++++++++++++++++++++++++---------- log.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++ log.h | 27 ++++++++++++ test/results/debug/g2.1 | 1 + 5 files changed, 212 insertions(+), 24 deletions(-) create mode 100644 log.c create mode 100644 log.h diff --git a/Makefile b/Makefile index fcf2dd2..325ffd8 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ VERSION=8.22 TARGETS = grubby -OBJECTS = grubby.o +OBJECTS = grubby.o log.o CC = gcc RPM_OPT_FLAGS := -O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector diff --git a/grubby.c b/grubby.c index edbeb64..408e3ca 100644 --- a/grubby.c +++ b/grubby.c @@ -36,6 +36,8 @@ #include #include +#include "log.h" + #ifndef DEBUG #define DEBUG 0 #endif @@ -58,6 +60,8 @@ int debug = 0; /* Currently just for template debugging */ int isEfi = 0; +char *saved_command_line = NULL; + /* comments get lumped in with indention */ struct lineElement { char * item; @@ -1533,43 +1537,67 @@ static char *findDiskForRoot() return NULL; } -void printEntry(struct singleEntry * entry) { +void printEntry(struct singleEntry * entry, FILE *f) { int i; struct singleLine * line; for (line = entry->lines; line; line = line->next) { - fprintf(stderr, "DBG: %s", line->indent); + log_message(f, "DBG: %s", line->indent); for (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) { if(!isquote(*line->elements[i].item)) - fprintf(stderr, "\'%s\'", line->elements[i].item); + log_message(f, "\'%s\'", line->elements[i].item); else - fprintf(stderr, "%s", line->elements[i].item); - fprintf(stderr, "%s", line->elements[i].indent); + log_message(f, "%s", line->elements[i].item); + log_message(f, "%s", line->elements[i].indent); continue; } - fprintf(stderr, "%s%s", + log_message(f, "%s%s", line->elements[i].item, line->elements[i].indent); } - fprintf(stderr, "\n"); + log_message(f, "\n"); } } -void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...) +void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...) { - va_list argp; + static int once; + va_list argp, argq; - if (!debug) + va_start(argp, fmt); + + va_copy(argq, argp); + if (!once) { + log_time(NULL); + log_message(NULL, "command line: %s\n", saved_command_line); + } + log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed"); + log_vmessage(NULL, fmt, argq); + + printEntry(entry, NULL); + va_end(argq); + + if (!debug) { + once = 1; + va_end(argp); return; + } - va_start(argp, fmt); + if (okay) { + va_end(argp); + return; + } + + if (!once) + log_message(stderr, "DBG: command line: %s\n", saved_command_line); + once = 1; fprintf(stderr, "DBG: Image entry failed: "); vfprintf(stderr, fmt, argp); - printEntry(entry); + printEntry(entry, stderr); va_end(argp); } @@ -1596,22 +1624,25 @@ int suitableImage(struct singleEntry * entry, const char * bootPrefix, char * rootdev; if (skipRemoved && entry->skip) { - notSuitablePrintf(entry, "marked to skip\n"); + notSuitablePrintf(entry, 0, "marked to skip\n"); return 0; } line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines); if (!line) { - notSuitablePrintf(entry, "no line found\n"); + notSuitablePrintf(entry, 0, "no line found\n"); return 0; } if (line->numElements < 2) { - notSuitablePrintf(entry, "line has only %d elements\n", + notSuitablePrintf(entry, 0, "line has only %d elements\n", line->numElements); return 0; } - if (flags & GRUBBY_BADIMAGE_OKAY) return 1; + if (flags & GRUBBY_BADIMAGE_OKAY) { + notSuitablePrintf(entry, 1, "\n"); + return 1; + } fullName = alloca(strlen(bootPrefix) + strlen(line->elements[1].item) + 1); @@ -1622,7 +1653,7 @@ int suitableImage(struct singleEntry * entry, const char * bootPrefix, sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/", line->elements[1].item + rootspec_offset); if (access(fullName, R_OK)) { - notSuitablePrintf(entry, "access to %s failed\n", fullName); + notSuitablePrintf(entry, 0, "access to %s failed\n", fullName); return 0; } for (i = 2; i < line->numElements; i++) @@ -1643,7 +1674,7 @@ int suitableImage(struct singleEntry * entry, const char * bootPrefix, /* failed to find one */ if (!line) { - notSuitablePrintf(entry, "no line found\n"); + notSuitablePrintf(entry, 0, "no line found\n"); return 0; } @@ -1652,7 +1683,7 @@ int suitableImage(struct singleEntry * entry, const char * bootPrefix, if (i < line->numElements) dev = line->elements[i].item + 5; else { - notSuitablePrintf(entry, "no root= entry found\n"); + notSuitablePrintf(entry, 0, "no root= entry found\n"); /* it failed too... can't find root= */ return 0; } @@ -1661,32 +1692,33 @@ int suitableImage(struct singleEntry * entry, const char * bootPrefix, dev = getpathbyspec(dev); if (!getpathbyspec(dev)) { - notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev); + notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev); return 0; } else dev = getpathbyspec(dev); rootdev = findDiskForRoot(); if (!rootdev) { - notSuitablePrintf(entry, "can't find root device\n"); + notSuitablePrintf(entry, 0, "can't find root device\n"); return 0; } if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) { - notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n", + notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n", getuuidbydev(rootdev), getuuidbydev(dev)); free(rootdev); return 0; } if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) { - notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n", + notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n", getuuidbydev(rootdev), getuuidbydev(dev)); free(rootdev); return 0; } free(rootdev); + notSuitablePrintf(entry, 1, "\n"); return 1; } @@ -3898,6 +3930,20 @@ int main(int argc, const char ** argv) { signal(SIGSEGV, traceback); + int i = 0; + for (int j = 1; j < argc; j++) + i += strlen(argv[j]) + 1; + saved_command_line = malloc(i); + if (!saved_command_line) { + fprintf(stderr, "grubby: %m\n"); + exit(1); + } + saved_command_line[0] = '\0'; + for (int j = 1; j < argc; j++) { + strcat(saved_command_line, argv[j]); + strncat(saved_command_line, j == argc -1 ? "" : " ", 1); + } + optCon = poptGetContext("grubby", argc, argv, options, 0); poptReadDefaultConfig(optCon, 1); diff --git a/log.c b/log.c new file mode 100644 index 0000000..1ddb8c1 --- /dev/null +++ b/log.c @@ -0,0 +1,114 @@ +/* + * log.c + * + * Copyright 2013 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" + +static int log_fd = -1; +static FILE *f = NULL; + +static int +open_log(void) +{ + if (log_fd > -1) + return 0; + log_fd = open("/var/log/grubby", O_RDWR|O_APPEND|O_CREAT|O_CLOEXEC, 0600); + if (log_fd < 0) + return log_fd; + + f = fdopen(log_fd, "a+"); + if (f == NULL) { + typeof(errno) saved_errno = errno; + close(log_fd); + log_fd = -1; + errno = saved_errno; + return -1; + } + + setbuf(f, NULL); + return 0; +} + +int +log_time(FILE *log) +{ + if (!log) { + int rc = open_log(); + if (rc < 0) + return rc; + } + + time_t t = time(NULL); + char timestr[27]; + + ctime_r(&t, timestr); + timestr[26] = '\0'; + for (int i = 26; i >= 0; i--) + if (timestr[i] == '\n') + timestr[i] = '\0'; + + return log_message(log, "DBG: %d: %s: ", getpid(), timestr); +} + +int +log_vmessage(FILE *log, const char *msg, va_list ap) +{ + int rc; + + if (!msg) + return -1; + if (msg[0] == '\0') + return 0; + + if (!log) { + rc = open_log(); + if (rc < 0) + return rc; + } + + vfprintf(log ? log : f, msg, ap); + fdatasync(log ? fileno(log) : log_fd); + + return 0; +} + +int +log_message(FILE *log, const char *msg, ...) +{ + va_list argp; + + va_start(argp, msg); + int rc = log_vmessage(log, msg, argp); + va_end(argp); + return rc; +} diff --git a/log.h b/log.h new file mode 100644 index 0000000..082a59e --- /dev/null +++ b/log.h @@ -0,0 +1,27 @@ +/* + * log.h + * + * Copyright 2013 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef GRUBBY_LOG_H +#define GRUBBY_LOG_H 1 + +extern int log_time(FILE *log); +extern int log_vmessage(FILE *log, const char *msg, va_list ap); +extern int log_message(FILE *log, const char *msg, ...); + +#endif /* GRUBBY_LOG_H */ diff --git a/test/results/debug/g2.1 b/test/results/debug/g2.1 index 9de4595..45c64ae 100644 --- a/test/results/debug/g2.1 +++ b/test/results/debug/g2.1 @@ -1,3 +1,4 @@ +DBG: command line: --grub2 -c test/grub2.1 --boot-filesystem=/boot --default-kernel --debug DBG: Image entry failed: access to /boot/vmlinuz-2.6.38.8-32.fc15.x86_64 failed DBG: menuentry 'Linux, with Fedora 2.6.38.8-32.fc15.x86_64' --class gnu-linux --class gnu --class os { DBG: load_video -- 1.8.1.2