Add --debug style logging (for both success and failures) to /var/log/grubby

Signed-off-by: Peter Jones <pjones@redhat.com>
This commit is contained in:
Peter Jones 2013-02-20 11:04:16 -05:00
parent 24e2f46051
commit a10345813c
2 changed files with 420 additions and 1 deletions

View File

@ -0,0 +1,414 @@
From bfb7c70e7eaa1311cadc716c303ca694163f9e2f Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
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 <pjones@redhat.com>
---
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 <signal.h>
#include <blkid/blkid.h>
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+
+#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 <http://www.gnu.org/licenses/>.
+ */
+#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

View File

@ -1,6 +1,6 @@
Name: grubby Name: grubby
Version: 8.22 Version: 8.22
Release: 2%{?dist} Release: 3%{?dist}
Summary: Command line tool for updating bootloader configs Summary: Command line tool for updating bootloader configs
Group: System Environment/Base Group: System Environment/Base
License: GPLv2+ License: GPLv2+
@ -21,6 +21,8 @@ Requires: s390utils-base
Requires: uboot-tools Requires: uboot-tools
%endif %endif
Patch0: 0001-Add-logging-when-things-fail.patch
%description %description
grubby is a command line tool for updating and displaying information about grubby is a command line tool for updating and displaying information about
the configuration files for the grub, lilo, elilo (ia64), yaboot (powerpc) the configuration files for the grub, lilo, elilo (ia64), yaboot (powerpc)
@ -71,6 +73,9 @@ rm -rf $RPM_BUILD_ROOT
%endif %endif
%changelog %changelog
* Wed Feb 20 2013 Peter Jones <pjones@redhat.com> - 8.22-3
- Add --debug style logging (for both success and failures) to /var/log/grubby
* Thu Feb 14 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 8.22-2 * Thu Feb 14 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 8.22-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild - Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild