# HG changeset patch
# User Zhigang Wang <zhigang.x.wang@oracle.com>
# Date 1342720736 14400
# Node ID ec9655b30a5fa5b5abb3e05505f681f9be559613
# Parent 43e21ce7f22151524b800a6cf0ac4ba1233b34a7
pygrub: add syslog support to pygrub
Currently, when pygrub failed, we don''t know the reason because xend/xl
will
not capture the stderr message.
This patch will log the error message to syslog.
We choosing syslog because pygrub could be called concurrently. If we want
dedicated log file for pygrub, we need a log server. Using syslog is simple.
Example /var/log/messages log:
Jul 19 11:59:53 ovs030 [2012-07-19 11:59:53,504 7112] ERROR (pygrub:848)
[Errno 95] Operation not supported Traceback (most recent call last): File
"/share/repos/xen-unstable/tools/pygrub/src/pygrub", line 828, in ?
fs = fsimage.open(file, offset, bootfsoptions) IOError: [Errno 95] Operation not
supported
Jul 19 11:59:53 ovs030 [2012-07-19 11:59:53,508 7112] ERROR (pygrub:892)
Unable to find partition containing kernel
''7112'' is the pygrub PID, so we can distinguish each process.
Also in this patch:
1). Fix indentation for some lines.
2). Removed some trailing spaces.
3). Mark ''isconfig'' a duplicate option of
''debug'' and remove the currently broken code:
if isconfig:
chosencfg = run_grub(file, entry, fs, incfg["args"])
''fs'' is not defined yet here, so it will raise an
exception.
Signed-off-by: Zhigang Wang <zhigang.x.wang@oracle.com>
diff -r 43e21ce7f221 -r ec9655b30a5f tools/pygrub/src/pygrub
--- a/tools/pygrub/src/pygrub Tue Jul 17 17:33:31 2012 +0100
+++ b/tools/pygrub/src/pygrub Thu Jul 19 13:58:56 2012 -0400
@@ -13,9 +13,10 @@
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
-import os, sys, string, struct, tempfile, re, traceback
+import os, sys, string, struct, tempfile, re
import copy
import logging
+import logging.handlers
import platform
import xen.lowlevel.xc
@@ -35,7 +36,7 @@ def enable_cursor(ison):
val = 2
else:
val = 0
-
+
try:
curses.curs_set(val)
except _curses.error:
@@ -79,7 +80,7 @@ def get_solaris_slice(file, offset):
if slicetag == V_ROOT:
return slicesect * SECTOR_SIZE
- raise RuntimeError, "No root slice found"
+ raise RuntimeError, "No root slice found"
def get_fs_offset_gpt(file):
fd = os.open(file, os.O_RDONLY)
@@ -102,7 +103,7 @@ FDISK_PART_GPT=0xee
def get_partition_offsets(file):
image_type = identify_disk_image(file)
if image_type == DISK_TYPE_RAW:
- # No MBR: assume whole disk filesystem, which is like a
+ # No MBR: assume whole disk filesystem, which is like a
# single partition starting at 0
return [0]
elif image_type == DISK_TYPE_HYBRIDISO:
@@ -122,7 +123,7 @@ def get_partition_offsets(file):
partbuf = buf[poff:poff+16]
offset = struct.unpack("<L", partbuf[8:12])[0] *
SECTOR_SIZE
type = struct.unpack("<B", partbuf[4:5])[0]
-
+
# offset == 0 implies this partition is not enabled
if offset == 0:
continue
@@ -153,7 +154,7 @@ class GrubLineEditor(curses.textpad.Text
screen.noutrefresh()
win = curses.newwin(1, 74, startx, starty + 2)
curses.textpad.Textbox.__init__(self, win)
-
+
self.line = list(line)
self.pos = len(line)
self.cancelled = False
@@ -219,7 +220,7 @@ class GrubLineEditor(curses.textpad.Text
if self.cancelled:
return None
return string.join(self.line, "")
-
+
class Grub:
ENTRY_WIN_LINES = 8
@@ -243,7 +244,7 @@ class Grub:
self.entry_win = curses.newwin(Grub.ENTRY_WIN_LINES + 2, 74, 2, 1)
self.text_win = curses.newwin(10, 70, 12, 5)
curses.def_prog_mode()
-
+
curses.reset_prog_mode()
self.screen.erase()
@@ -261,7 +262,7 @@ class Grub:
self.start_image = self.selected_image
if self.selected_image < self.start_image:
self.start_image = self.selected_image
-
+
for y in range(self.start_image, len(self.cf.images)):
i = self.cf.images[y]
if y > self.start_image + maxy:
@@ -311,7 +312,7 @@ class Grub:
l = img.lines[idx].expandtabs().ljust(70)
if len(l) > 70:
l = l[:69] + ">"
-
+
self.entry_win.addstr(idp, 2, l)
if idx == curline:
self.entry_win.attroff(curses.A_REVERSE)
@@ -349,7 +350,7 @@ class Grub:
self.command_line_mode()
if self.isdone:
return
-
+
# bound at the top and bottom
if curline < 0:
curline = 0
@@ -357,11 +358,11 @@ class Grub:
curline = len(img.lines) - 1
if self.isdone:
- # Fix to allow pygrub command-line editing in Lilo bootloader (used
by IA64)
- if platform.machine() == ''ia64'':
- origimg.reset(img.lines, img.path)
- else:
- origimg.reset(img.lines)
+ # Fix to allow pygrub command-line editing in Lilo bootloader (used
by IA64)
+ if platform.machine() == ''ia64'':
+ origimg.reset(img.lines, img.path)
+ else:
+ origimg.reset(img.lines)
def edit_line(self, line):
self.screen.erase()
@@ -386,7 +387,7 @@ class Grub:
lines = []
while 1:
t = GrubLineEditor(self.screen, y, 2)
- enable_cursor(True)
+ enable_cursor(True)
ret = t.edit()
if ret:
if ret in ("quit", "return"):
@@ -396,7 +397,7 @@ class Grub:
lines.append(ret)
continue
- # if we got boot, then we want to boot the entered image
+ # if we got boot, then we want to boot the entered image
img = self.cf.new_image("entered", lines)
self.cf.add_image(img)
self.selected_image = len(self.cf.images) - 1
@@ -409,16 +410,16 @@ class Grub:
def read_config(self, fn, fs = None):
"""Read the given file to parse the config. If fs =
None, then
we''re being given a raw config file rather than a disk
image."""
-
+
if not os.access(fn, os.R_OK):
raise RuntimeError, "Unable to access %s" %(fn,)
if platform.machine() == ''ia64'':
- cfg_list = map(lambda x: (x,grub.LiloConf.LiloConfigFile),
+ cfg_list = map(lambda x: (x,grub.LiloConf.LiloConfigFile),
# common distributions
- ["/efi/debian/elilo.conf",
"/efi/gentoo/elilo.conf",
- "/efi/redflag/elilo.conf",
"/efi/redhat/elilo.conf",
- "/efi/SuSE/elilo.conf",] +
+ ["/efi/debian/elilo.conf",
"/efi/gentoo/elilo.conf",
+ "/efi/redflag/elilo.conf",
"/efi/redhat/elilo.conf",
+ "/efi/SuSE/elilo.conf",] +
# fallbacks
["/efi/boot/elilo.conf",
"/elilo.conf",])
else:
@@ -442,7 +443,8 @@ class Grub:
for f,parser in cfg_list:
if fs.file_exists(f):
- print >>sys.stderr, "Using %s to parse %s" %
(parser,f)
+ if debug:
+ print >> sys.stderr, "Using %s to parse %s"
% (parser,f)
self.cf = parser()
self.cf.filename = f
break
@@ -465,7 +467,7 @@ class Grub:
while not self.isdone:
self.run_main(timeout)
timeout = -1
-
+
return self.selected_image
def run_main(self, timeout = -1):
@@ -495,7 +497,7 @@ class Grub:
self.start_image = 0
while (timeout == -1 or mytime < int(timeout)):
draw()
- if timeout != -1 and mytime != -1:
+ if timeout != -1 and mytime != -1:
self.screen.addstr(20, 5, "Will boot selected entry in %2d
seconds"
%(int(timeout) - mytime))
else:
@@ -566,7 +568,7 @@ class Grub:
self.selected_image = 0
elif self.selected_image >= len(self.cf.images):
self.selected_image = len(self.cf.images) - 1
-
+
def get_entry_idx(cf, entry):
# first, see if the given entry is numeric
try:
@@ -601,7 +603,7 @@ def run_grub(file, entry, fs, arg):
if entry is not None:
idx = get_entry_idx(g.cf, entry)
if idx is not None and idx > 0 and idx < len(g.cf.images):
- sel = idx
+ sel = idx
if sel == -1:
print "No kernel image selected!"
@@ -651,10 +653,10 @@ def sniff_solaris(fs, cfg):
# Unpleasant. Typically we''ll have ''root=foo -k''
or ''root=foo /kernel -k'',
# and we need to maintain Xen properties (root= and ip=) and the kernel
# before any user args.
-
+
xenargs = ""
userargs = ""
-
+
if not cfg["args"]:
cfg["args"] = cfg["kernel"]
else:
@@ -666,7 +668,7 @@ def sniff_solaris(fs, cfg):
cfg["args"] = xenargs + " " +
cfg["kernel"] + " " + userargs
return cfg
-
+
def sniff_netware(fs, cfg):
if not fs.file_exists("/nwserver/xnloader.sys"):
return cfg
@@ -683,7 +685,7 @@ def format_sxp(kernel, ramdisk, args):
if args:
s += "(args \"%s\")" % args
return s
-
+
def format_simple(kernel, ramdisk, args, sep):
s = ("kernel %s" % kernel) + sep
if ramdisk:
@@ -693,9 +695,19 @@ def format_simple(kernel, ramdisk, args,
s += sep
return s
+def init_log():
+ logger = logging.getLogger()
+ handler =
logging.handlers.SysLogHandler(address=''/dev/log'')
+ file_format = (''[%(asctime)s %(process)d] %(levelname)s ''
+ ''(%(module)s:%(lineno)d) %(message)s'')
+ handler.setFormatter(logging.Formatter(file_format))
+ logger.addHandler(handler)
+ logger.setLevel(logging.DEBUG)
+
if __name__ == "__main__":
+ init_log()
sel = None
-
+
def usage():
print >> sys.stderr, "Usage: %s [-q|--quiet]
[-i|--interactive] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=]
[--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0]
<image>" %(sys.argv[0],)
@@ -732,9 +744,9 @@ if __name__ == "__main__":
try:
opts, args = getopt.gnu_getopt(sys.argv[1:],
''qinh::'',
- ["quiet", "interactive",
"not-really", "help",
+ ["quiet", "interactive",
"not-really", "help",
"output=",
"output-format=", "output-directory=",
- "entry=", "kernel=",
+ "entry=", "kernel=",
"ramdisk=", "args=",
"isconfig", "debug"])
except getopt.GetoptError:
usage()
@@ -744,7 +756,7 @@ if __name__ == "__main__":
usage()
sys.exit(1)
file = args[0]
-
+
output = None
entry = None
interactive = True
@@ -783,9 +795,7 @@ if __name__ == "__main__":
entry = a
# specifying the entry to boot implies non-interactive
interactive = False
- elif o in ("--isconfig",):
- isconfig = True
- elif o in ("--debug",):
+ elif o in ("--debug", "--isconfig"):
debug = True
elif o in ("--output-format",):
if a not in ["sxp", "simple",
"simple0"]:
@@ -796,96 +806,88 @@ if __name__ == "__main__":
elif o in ("--output-directory",):
output_directory = a
- if debug:
- logging.basicConfig(level=logging.DEBUG)
+ try:
+ if output is None or output == "-":
+ fd = sys.stdout.fileno()
+ else:
+ fd = os.open(output, os.O_WRONLY)
- if output is None or output == "-":
- fd = sys.stdout.fileno()
- else:
- fd = os.open(output, os.O_WRONLY)
+ # if boot filesystem is set then pass to fsimage.open
+ bootfsargs = ''"%s"'' %
incfg["args"]
+ bootfsgroup =
re.findall(''zfs-bootfs=(.*?)[\s\,\"]'', bootfsargs)
+ if bootfsgroup:
+ bootfsoptions = bootfsgroup[0]
+ else:
+ bootfsoptions = ""
- # debug
- if isconfig:
- chosencfg = run_grub(file, entry, fs, incfg["args"])
- print " kernel: %s" % chosencfg["kernel"]
+ # get list of offsets into file which start partitions
+ part_offs = get_partition_offsets(file)
+
+ for offset in part_offs:
+ try:
+ fs = fsimage.open(file, offset, bootfsoptions)
+
+ chosencfg = sniff_solaris(fs, incfg)
+
+ if not chosencfg["kernel"]:
+ chosencfg = sniff_netware(fs, incfg)
+
+ if not chosencfg["kernel"]:
+ chosencfg = run_grub(file, entry, fs,
incfg["args"])
+
+ # Break as soon as we''ve found the kernel so that we
continue
+ # to use this fsimage object
+ if chosencfg["kernel"]:
+ break
+ fs = None
+
+ except Exception, err:
+ # IOErrors raised by fsimage.open
+ # RuntimeErrors raised by run_grub if no menu.lst present
+ if debug:
+ logging.exception(err)
+ fs = None
+ continue
+
+ # Did looping through partitions find us a kernel?
+ if not fs:
+ raise RuntimeError, "Unable to find partition containing
kernel"
+
+ bootcfg["kernel"] = copy_from_image(fs,
chosencfg["kernel"], "kernel",
+ output_directory, not_really)
+
if chosencfg["ramdisk"]:
- print " initrd: %s" % chosencfg["ramdisk"]
- print " args: %s" % chosencfg["args"]
- sys.exit(0)
+ try:
+ bootcfg["ramdisk"] = copy_from_image(fs,
chosencfg["ramdisk"],
+ "ramdisk",
output_directory,
+ not_really)
+ except:
+ if not not_really:
+ os.unlink(bootcfg["kernel"])
+ raise
+ else:
+ initrd = None
- # if boot filesystem is set then pass to fsimage.open
- bootfsargs = ''"%s"'' % incfg["args"]
- bootfsgroup = re.findall(''zfs-bootfs=(.*?)[\s\,\"]'',
bootfsargs)
- if bootfsgroup:
- bootfsoptions = bootfsgroup[0]
- else:
- bootfsoptions = ""
+ args = None
+ if chosencfg["args"]:
+ zfsinfo = fsimage.getbootstring(fs)
+ if zfsinfo is not None:
+ e = re.compile("zfs-bootfs=[\w\-\.\:@/]+" )
+ (chosencfg["args"],count) = e.subn(zfsinfo,
chosencfg["args"])
+ if count == 0:
+ chosencfg["args"] += " -B %s" % zfsinfo
+ args = chosencfg["args"]
- # get list of offsets into file which start partitions
- part_offs = get_partition_offsets(file)
+ if output_format == "sxp":
+ ostring = format_sxp(bootcfg["kernel"],
bootcfg["ramdisk"], args)
+ elif output_format == "simple":
+ ostring = format_simple(bootcfg["kernel"],
bootcfg["ramdisk"], args, "\n")
+ elif output_format == "simple0":
+ ostring = format_simple(bootcfg["kernel"],
bootcfg["ramdisk"], args, "\0")
- for offset in part_offs:
- try:
- fs = fsimage.open(file, offset, bootfsoptions)
-
- chosencfg = sniff_solaris(fs, incfg)
-
- if not chosencfg["kernel"]:
- chosencfg = sniff_netware(fs, incfg)
-
- if not chosencfg["kernel"]:
- chosencfg = run_grub(file, entry, fs, incfg["args"])
-
- # Break as soon as we''ve found the kernel so that we
continue
- # to use this fsimage object
- if chosencfg["kernel"]:
- break
- fs = None
-
- except:
- # IOErrors raised by fsimage.open
- # RuntimeErrors raised by run_grub if no menu.lst present
- if debug:
- traceback.print_exc()
- fs = None
- continue
-
- # Did looping through partitions find us a kernel?
- if not fs:
- raise RuntimeError, "Unable to find partition containing
kernel"
-
- bootcfg["kernel"] = copy_from_image(fs,
chosencfg["kernel"], "kernel",
- output_directory, not_really)
-
- if chosencfg["ramdisk"]:
- try:
- bootcfg["ramdisk"] = copy_from_image(fs,
chosencfg["ramdisk"],
- "ramdisk",
output_directory,
- not_really)
- except:
- if not not_really:
- os.unlink(bootcfg["kernel"])
- raise
- else:
- initrd = None
-
- args = None
- if chosencfg["args"]:
- zfsinfo = fsimage.getbootstring(fs)
- if zfsinfo is not None:
- e = re.compile("zfs-bootfs=[\w\-\.\:@/]+" )
- (chosencfg["args"],count) = e.subn(zfsinfo,
chosencfg["args"])
- if count == 0:
- chosencfg["args"] += " -B %s" % zfsinfo
- args = chosencfg["args"]
-
- if output_format == "sxp":
- ostring = format_sxp(bootcfg["kernel"],
bootcfg["ramdisk"], args)
- elif output_format == "simple":
- ostring = format_simple(bootcfg["kernel"],
bootcfg["ramdisk"], args, "\n")
- elif output_format == "simple0":
- ostring = format_simple(bootcfg["kernel"],
bootcfg["ramdisk"], args, "\0")
-
- sys.stdout.flush()
- os.write(fd, ostring)
-
+ sys.stdout.flush()
+ os.write(fd, ostring)
+ except Exception, err:
+ print >> sys.stderr, str(err)
+ logging.error(err)
+ sys.exit(1)