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
Version: 8.22
Release: 2%{?dist}
Release: 3%{?dist}
Summary: Command line tool for updating bootloader configs
Group: System Environment/Base
License: GPLv2+
@ -21,6 +21,8 @@ Requires: s390utils-base
Requires: uboot-tools
%endif
Patch0: 0001-Add-logging-when-things-fail.patch
%description
grubby is a command line tool for updating and displaying information about
the configuration files for the grub, lilo, elilo (ia64), yaboot (powerpc)
@ -71,6 +73,9 @@ rm -rf $RPM_BUILD_ROOT
%endif
%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
- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild