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

Peter Jones pjones at fedoraproject.org
Wed Feb 20 16:07:25 UTC 2013


commit a10345813c38b020dc29a8409f82f3f42398fe0c
Author: Peter Jones <pjones at redhat.com>
Date:   Wed Feb 20 11:04:16 2013 -0500

    Add --debug style logging (for both success and failures) to /var/log/grubby
    
    Signed-off-by: Peter Jones <pjones at redhat.com>

 0001-Add-logging-when-things-fail.patch |  414 +++++++++++++++++++++++++++++++
 grubby.spec                             |    7 +-
 2 files changed, 420 insertions(+), 1 deletions(-)
---
diff --git a/0001-Add-logging-when-things-fail.patch b/0001-Add-logging-when-things-fail.patch
new file mode 100644
index 0000000..6b00d16
--- /dev/null
+++ b/0001-Add-logging-when-things-fail.patch
@@ -0,0 +1,414 @@
+From bfb7c70e7eaa1311cadc716c303ca694163f9e2f Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones at 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 at 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
+
diff --git a/grubby.spec b/grubby.spec
index 785eaee..850bf91 100644
--- a/grubby.spec
+++ b/grubby.spec
@@ -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 at 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 at lists.fedoraproject.org> - 8.22-2
 - Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
 


More information about the scm-commits mailing list