ia64/xen-unstable

view tools/pygrub/src/pygrub @ 19527:0e24e9674ded

tools: Always use sane upstream (`native') python paths

Previously, by default we would install our python modules into
/usr/lib/python/xen, for example /usr/lib/python/xen/__init__.py.
Upstream python's standard install location (a) includes the Python
version number and (b) puts things in site-packages by default.

Our best conjecture for the reason for this was an attempt to make the
installs portable between different python versions. However, that
doesn't work because compiled python modules (.pyc), and C python
extensions corresponding to one version of python, are not compatible
across different versions of python.

This is why upstream include the version number.

site-packages is the standard location for locally-installed packages
and is automatically included on the python search path.

In this change, we abandon our own unusual python path setup:

* Invoke setup.py in an entirely standard manner. We pass
PREFIX and DESTDIR using the appropriate options provided by
setup.py for those purposes (adding them to setup.py calls
which were previously lacking them).

* Since the installation locations are now on the standard
python path, we no longer need to add anything to the path
in any of our python utilities. Therefore remove all that
code from every python script. (Many of these scripts
unconditionally added /usr/lib/python and /usr/lib64/python which
is wrong even in the old world.)

* There is no longer any special `Xen python path'. xen-python-path
is no longer needed. It is no longer called by anything in our
tree. However since out-of-tree callers may still invoke it, we
retain it. It now prints a fixed string referring to a directory
which does not to exist; callers (who use it to augment their
python path) will thus add a nonexistent directory to their python
path which is harmless.

* Remove various workarounds including use of setup.py --home
(which is intended for something completely different).

* Remove tests for the XEN_PYTHON_NATIVE_INSTALL build-time
environment variable. The new behaviour is the behaviour which we
should have had if this variable had been set. That is, it is now
as if this variable was always set but also bugs in the resulting
install have been fixed.

This should be a proper fix for the bug addressed by c/s 19515.

Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Apr 08 19:13:04 2009 +0100 (2009-04-08)
parents 4b602fff137b
children
line source
1 #!/usr/bin/python
2 #
3 # pygrub - simple python-based bootloader for Xen
4 #
5 # Copyright 2005-2006 Red Hat, Inc.
6 # Jeremy Katz <katzj@redhat.com>
7 #
8 # This software may be freely redistributed under the terms of the GNU
9 # general public license.
10 #
11 # You should have received a copy of the GNU General Public License
12 # along with this program; if not, write to the Free Software
13 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
14 #
16 import os, sys, string, struct, tempfile, re
17 import copy
18 import logging
19 import platform
21 import curses, _curses, curses.wrapper, curses.textpad, curses.ascii
22 import getopt
24 import fsimage
25 import grub.GrubConf
26 import grub.LiloConf
28 PYGRUB_VER = 0.6
30 def enable_cursor(ison):
31 if ison:
32 val = 2
33 else:
34 val = 0
36 try:
37 curses.curs_set(val)
38 except _curses.error:
39 pass
41 def is_disk_image(file):
42 fd = os.open(file, os.O_RDONLY)
43 buf = os.read(fd, 512)
44 os.close(fd)
46 if len(buf) >= 512 and \
47 struct.unpack("H", buf[0x1fe: 0x200]) == (0xaa55,):
48 return True
49 return False
51 def get_active_partition(file):
52 """Find the offset for the start of the first active partition "
53 "in the disk image file."""
55 fd = os.open(file, os.O_RDONLY)
56 buf = os.read(fd, 512)
57 for poff in (446, 462, 478, 494): # partition offsets
58 # active partition has 0x80 as the first byte
59 if struct.unpack("<c", buf[poff:poff+1]) == ('\x80',):
60 return buf[poff:poff+16]
62 # if there's not a partition marked as active, fall back to
63 # the first partition
64 return buf[446:446+16]
66 SECTOR_SIZE=512
67 DK_LABEL_LOC=1
68 DKL_MAGIC=0xdabe
69 V_ROOT=0x2
71 def get_solaris_slice(file, offset):
72 """Find the root slice in a Solaris VTOC."""
74 fd = os.open(file, os.O_RDONLY)
75 os.lseek(fd, offset + (DK_LABEL_LOC * SECTOR_SIZE), 0)
76 buf = os.read(fd, 512)
77 if struct.unpack("<H", buf[508:510])[0] != DKL_MAGIC:
78 raise RuntimeError, "Invalid disklabel magic"
80 nslices = struct.unpack("<H", buf[30:32])[0]
82 for i in range(nslices):
83 sliceoff = 72 + 12 * i
84 slicetag = struct.unpack("<H", buf[sliceoff:sliceoff+2])[0]
85 slicesect = struct.unpack("<L", buf[sliceoff+4:sliceoff+8])[0]
86 if slicetag == V_ROOT:
87 return slicesect * SECTOR_SIZE
89 raise RuntimeError, "No root slice found"
91 def get_fs_offset_gpt(file):
92 fd = os.open(file, os.O_RDONLY)
93 # assume the first partition is an EFI system partition.
94 os.lseek(fd, SECTOR_SIZE * 2, 0)
95 buf = os.read(fd, 512)
96 return struct.unpack("<Q", buf[32:40])[0] * SECTOR_SIZE
98 FDISK_PART_SOLARIS=0xbf
99 FDISK_PART_SOLARIS_OLD=0x82
100 FDISK_PART_GPT=0xee
102 def get_fs_offset(file):
103 if not is_disk_image(file):
104 return 0
106 partbuf = get_active_partition(file)
107 if len(partbuf) == 0:
108 raise RuntimeError, "Unable to find active partition on disk"
110 offset = struct.unpack("<L", partbuf[8:12])[0] * SECTOR_SIZE
112 type = struct.unpack("<B", partbuf[4:5])[0]
114 if type == FDISK_PART_SOLARIS or type == FDISK_PART_SOLARIS_OLD:
115 offset += get_solaris_slice(file, offset)
117 if type == FDISK_PART_GPT:
118 offset = get_fs_offset_gpt(file)
120 return offset
122 class GrubLineEditor(curses.textpad.Textbox):
123 def __init__(self, screen, startx, starty, line = ""):
124 screen.addstr(startx, starty, "> ")
125 screen.noutrefresh()
126 win = curses.newwin(1, 74, startx, starty + 2)
127 curses.textpad.Textbox.__init__(self, win)
129 self.line = list(line)
130 self.pos = len(line)
131 self.cancelled = False
132 self.show_text()
134 def show_text(self):
135 """Show the text. One of our advantages over standard textboxes
136 is that we can handle lines longer than the window."""
138 self.win.erase()
139 p = self.pos
140 off = 0
141 while p > 70:
142 p -= 55
143 off += 55
145 l = self.line[off:off+70]
146 self.win.addstr(0, 0, string.join(l, ("")))
147 if self.pos > 70:
148 self.win.addch(0, 0, curses.ACS_LARROW)
150 self.win.move(0, p)
152 def do_command(self, ch):
153 # we handle escape as well as moving the line around, so have
154 # to override some of the default handling
156 self.lastcmd = ch
157 if ch == 27: # esc
158 self.cancelled = True
159 return 0
160 elif curses.ascii.isprint(ch):
161 self.line.insert(self.pos, chr(ch))
162 self.pos += 1
163 elif ch == curses.ascii.SOH: # ^a
164 self.pos = 0
165 elif ch in (curses.ascii.STX,curses.KEY_LEFT):
166 if self.pos > 0:
167 self.pos -= 1
168 elif ch in (curses.ascii.BS,curses.KEY_BACKSPACE):
169 if self.pos > 0:
170 self.pos -= 1
171 if self.pos < len(self.line):
172 self.line.pop(self.pos)
173 elif ch == curses.ascii.EOT: # ^d
174 if self.pos < len(self.line):
175 self.line.pop(self.pos)
176 elif ch == curses.ascii.ENQ: # ^e
177 self.pos = len(self.line)
178 elif ch in (curses.ascii.ACK, curses.KEY_RIGHT):
179 if self.pos < len(self.line):
180 self.pos +=1
181 elif ch == curses.ascii.VT: # ^k
182 self.line = self.line[:self.pos]
183 else:
184 return curses.textpad.Textbox.do_command(self, ch)
185 self.show_text()
186 return 1
188 def edit(self):
189 curses.doupdate()
190 r = curses.textpad.Textbox.edit(self)
191 if self.cancelled:
192 return None
193 return string.join(self.line, "")
196 class Grub:
197 def __init__(self, file, fs = None):
198 self.screen = None
199 self.entry_win = None
200 self.text_win = None
201 if file:
202 self.read_config(file, fs)
204 def draw_main_windows(self):
205 if self.screen is None: #only init stuff once
206 self.screen = curses.initscr()
207 self.screen.timeout(1000)
208 if hasattr(curses, 'use_default_colors'):
209 try:
210 curses.use_default_colors()
211 except:
212 pass # Not important if we can't use colour
213 enable_cursor(False)
214 self.entry_win = curses.newwin(10, 74, 2, 1)
215 self.text_win = curses.newwin(10, 70, 12, 5)
216 curses.def_prog_mode()
218 curses.reset_prog_mode()
219 self.screen.erase()
221 # create basic grub screen with a box of entries and a textbox
222 self.screen.addstr(1, 4, "pyGRUB version %s" %(PYGRUB_VER,))
223 self.entry_win.box()
224 self.screen.noutrefresh()
226 def fill_entry_list(self):
227 self.entry_win.erase()
228 self.entry_win.box()
230 maxy = self.entry_win.getmaxyx()[0]-3 # maxy - 2 for the frame + index
231 if self.selected_image > self.start_image + maxy:
232 self.start_image = self.selected_image
233 if self.selected_image < self.start_image:
234 self.start_image = self.selected_image
236 for y in range(self.start_image, len(self.cf.images)):
237 i = self.cf.images[y]
238 if y > self.start_image + maxy:
239 break
240 if y == self.selected_image:
241 self.entry_win.attron(curses.A_REVERSE)
242 self.entry_win.addstr(y + 1 - self.start_image, 2, i.title.ljust(70))
243 if y == self.selected_image:
244 self.entry_win.attroff(curses.A_REVERSE)
245 self.entry_win.noutrefresh()
247 def edit_entry(self, origimg):
248 def draw():
249 self.draw_main_windows()
251 self.text_win.addstr(0, 0, "Use the U and D keys to select which entry is highlighted.")
252 self.text_win.addstr(1, 0, "Press 'b' to boot, 'e' to edit the selected command in the")
253 self.text_win.addstr(2, 0, "boot sequence, 'c' for a command-line, 'o' to open a new line")
254 self.text_win.addstr(3, 0, "after ('O' for before) the selected line, 'd' to remove the")
255 self.text_win.addstr(4, 0, "selected line, or escape to go back to the main menu.")
256 self.text_win.addch(0, 8, curses.ACS_UARROW)
257 self.text_win.addch(0, 14, curses.ACS_DARROW)
258 (y, x) = self.text_win.getmaxyx()
259 self.text_win.move(y - 1, x - 1)
260 self.text_win.noutrefresh()
262 curline = 1
263 img = copy.deepcopy(origimg)
264 while 1:
265 draw()
266 self.entry_win.erase()
267 self.entry_win.box()
268 for idx in range(1, len(img.lines)):
269 # current line should be highlighted
270 if idx == curline:
271 self.entry_win.attron(curses.A_REVERSE)
273 # trim the line
274 l = img.lines[idx].ljust(70)
275 if len(l) > 70:
276 l = l[:69] + ">"
278 self.entry_win.addstr(idx, 2, l)
279 if idx == curline:
280 self.entry_win.attroff(curses.A_REVERSE)
281 self.entry_win.noutrefresh()
282 curses.doupdate()
284 c = self.screen.getch()
285 if c in (ord('q'), 27): # 27 == esc
286 break
287 elif c == curses.KEY_UP:
288 curline -= 1
289 elif c == curses.KEY_DOWN:
290 curline += 1
291 elif c == ord('b'):
292 self.isdone = True
293 break
294 elif c == ord('e'):
295 l = self.edit_line(img.lines[curline])
296 if l is not None:
297 img.set_from_line(l, replace = curline)
298 elif c == ord('d'):
299 img.lines.pop(curline)
300 elif c == ord('o'):
301 img.lines.insert(curline+1, "")
302 curline += 1
303 elif c == ord('O'):
304 img.lines.insert(curline, "")
305 elif c == ord('c'):
306 self.command_line_mode()
307 if self.isdone:
308 return
310 # bound at the top and bottom
311 if curline < 1:
312 curline = 1
313 elif curline >= len(img.lines):
314 curline = len(img.lines) - 1
316 if self.isdone:
317 # Fix to allow pygrub command-line editing in Lilo bootloader (used by IA64)
318 if platform.machine() == 'ia64':
319 origimg.reset(img.lines, img.path)
320 else:
321 origimg.reset(img.lines)
323 def edit_line(self, line):
324 self.screen.erase()
325 self.screen.addstr(1, 2, "[ Minimal BASH-like line editing is supported. ")
326 self.screen.addstr(2, 2, " ESC at any time cancels. ENTER at any time accepts your changes. ]")
327 self.screen.noutrefresh()
329 t = GrubLineEditor(self.screen, 5, 2, line)
330 enable_cursor(True)
331 ret = t.edit()
332 if ret:
333 return ret
334 return None
336 def command_line_mode(self):
337 self.screen.erase()
338 self.screen.addstr(1, 2, "[ Minimal BASH-like line editing is supported. ESC at any time ")
339 self.screen.addstr(2, 2, " exits. Typing 'boot' will boot with your entered commands. ] ")
340 self.screen.noutrefresh()
342 y = 5
343 lines = []
344 while 1:
345 t = GrubLineEditor(self.screen, y, 2)
346 enable_cursor(True)
347 ret = t.edit()
348 if ret:
349 if ret in ("quit", "return"):
350 break
351 elif ret != "boot":
352 y += 1
353 lines.append(ret)
354 continue
356 # if we got boot, then we want to boot the entered image
357 img = grub.GrubConf.GrubImage(lines)
358 self.cf.add_image(img)
359 self.selected_image = len(self.cf.images) - 1
360 self.isdone = True
361 break
363 # else, we cancelled and should just go back
364 break
366 def read_config(self, fn, fs = None):
367 """Read the given file to parse the config. If fs = None, then
368 we're being given a raw config file rather than a disk image."""
370 if not os.access(fn, os.R_OK):
371 raise RuntimeError, "Unable to access %s" %(fn,)
373 if platform.machine() == 'ia64':
374 self.cf = grub.LiloConf.LiloConfigFile()
375 # common distributions
376 file_list = ("/efi/debian/elilo.conf", "/efi/gentoo/elilo.conf",
377 "/efi/redflag/elilo.conf", "/efi/redhat/elilo.conf",
378 "/efi/SuSE/elilo.conf",)
379 # fallbacks
380 file_list += ("/efi/boot/elilo.conf", "/elilo.conf",)
381 else:
382 self.cf = grub.GrubConf.GrubConfigFile()
383 file_list = ("/boot/grub/menu.lst", "/boot/grub/grub.conf",
384 "/grub/menu.lst", "/grub/grub.conf")
386 if not fs:
387 # set the config file and parse it
388 self.cf.filename = fn
389 self.cf.parse()
390 return
392 for f in file_list:
393 if fs.file_exists(f):
394 self.cf.filename = f
395 break
396 if self.cf.filename is None:
397 raise RuntimeError, "couldn't find bootloader config file in the image provided."
398 f = fs.open_file(self.cf.filename)
399 buf = f.read()
400 del f
401 self.cf.parse(buf)
403 def run(self):
404 timeout = int(self.cf.timeout)
406 self.selected_image = self.cf.default
407 self.isdone = False
408 while not self.isdone:
409 self.run_main(timeout)
410 timeout = -1
412 return self.selected_image
414 def run_main(self, timeout = -1):
415 def draw():
416 # set up the screen
417 self.draw_main_windows()
418 self.text_win.addstr(0, 0, "Use the U and D keys to select which entry is highlighted.")
419 self.text_win.addstr(1, 0, "Press enter to boot the selected OS. 'e' to edit the")
420 self.text_win.addstr(2, 0, "commands before booting, 'a' to modify the kernel arguments ")
421 self.text_win.addstr(3, 0, "before booting, or 'c' for a command line.")
422 self.text_win.addch(0, 8, curses.ACS_UARROW)
423 self.text_win.addch(0, 14, curses.ACS_DARROW)
424 (y, x) = self.text_win.getmaxyx()
425 self.text_win.move(y - 1, x - 1)
426 self.text_win.noutrefresh()
428 # now loop until we hit the timeout or get a go from the user
429 mytime = 0
430 self.start_image = 0
431 while (timeout == -1 or mytime < int(timeout)):
432 draw()
433 if timeout != -1 and mytime != -1:
434 self.screen.addstr(20, 5, "Will boot selected entry in %2d seconds"
435 %(int(timeout) - mytime))
436 else:
437 self.screen.addstr(20, 5, " " * 80)
438 self.fill_entry_list()
439 curses.doupdate()
441 c = self.screen.getch()
442 if c == -1:
443 # Timed out waiting for a keypress
444 if mytime != -1:
445 mytime += 1
446 # curses.timeout() does not work properly on Solaris
447 # So we may come here even after a key has been pressed.
448 # Check both timeout and mytime to avoid exiting
449 # when we shouldn't.
450 if timeout != -1 and mytime >= int(timeout):
451 self.isdone = True
452 break
453 else:
454 # received a keypress: stop the timer
455 mytime = -1
456 self.screen.timeout(-1)
458 # handle keypresses
459 if c == ord('c'):
460 self.command_line_mode()
461 break
462 elif c == ord('a'):
463 # find the kernel line, edit it and then boot
464 img = self.cf.images[self.selected_image]
465 for line in img.lines:
466 if line.startswith("kernel"):
467 l = self.edit_line(line)
468 if l is not None:
469 img.set_from_line(l, replace = True)
470 self.isdone = True
471 break
472 break
473 elif c == ord('e'):
474 img = self.cf.images[self.selected_image]
475 self.edit_entry(img)
476 break
477 elif c in (curses.KEY_ENTER, ord('\n'), ord('\r')):
478 self.isdone = True
479 break
480 elif c == curses.KEY_UP:
481 self.selected_image -= 1
482 elif c == curses.KEY_DOWN:
483 self.selected_image += 1
484 # elif c in (ord('q'), 27): # 27 == esc
485 # self.selected_image = -1
486 # self.isdone = True
487 # break
489 # bound at the top and bottom
490 if self.selected_image < 0:
491 self.selected_image = 0
492 elif self.selected_image >= len(self.cf.images):
493 self.selected_image = len(self.cf.images) - 1
495 def get_entry_idx(cf, entry):
496 # first, see if the given entry is numeric
497 try:
498 idx = string.atoi(entry)
499 return idx
500 except ValueError:
501 pass
503 # it's not, now check the labels for a match
504 for i in range(len(cf.images)):
505 if entry == cf.images[i].title:
506 return i
508 return None
510 def run_grub(file, entry, fs, arg):
511 global g
512 global sel
514 def run_main(scr, *args):
515 global sel
516 global g
517 sel = g.run()
519 g = Grub(file, fs)
520 if interactive:
521 curses.wrapper(run_main)
522 else:
523 sel = g.cf.default
525 # set the entry to boot as requested
526 if entry is not None:
527 idx = get_entry_idx(g.cf, entry)
528 if idx is not None and idx > 0 and idx < len(g.cf.images):
529 sel = idx
531 if sel == -1:
532 print "No kernel image selected!"
533 sys.exit(1)
535 try:
536 img = g.cf.images[sel]
537 except IndexError:
538 log.debug("PyGrub: Default selection is not valid, using first boot configuration...")
539 img = g.cf.images[0]
541 grubcfg = { "kernel": None, "ramdisk": None, "args": None }
543 grubcfg["kernel"] = img.kernel[1]
544 if img.initrd:
545 grubcfg["ramdisk"] = img.initrd[1]
546 if img.args:
547 grubcfg["args"] = img.args + " " + arg
549 return grubcfg
551 # If nothing has been specified, look for a Solaris domU. If found, perform the
552 # necessary tweaks.
553 def sniff_solaris(fs, cfg):
554 if not fs.file_exists("/platform/i86xpv/kernel/unix"):
555 return cfg
557 # darned python
558 longmode = (sys.maxint != 2147483647L)
559 if not longmode:
560 longmode = os.uname()[4] == "x86_64"
561 if not longmode:
562 if (os.access("/usr/bin/isainfo", os.R_OK) and
563 os.popen("/usr/bin/isainfo -b").read() == "64\n"):
564 longmode = True
566 if not cfg["kernel"]:
567 cfg["kernel"] = "/platform/i86xpv/kernel/unix"
568 cfg["ramdisk"] = "/platform/i86pc/boot_archive"
569 if longmode:
570 cfg["kernel"] = "/platform/i86xpv/kernel/amd64/unix"
571 cfg["ramdisk"] = "/platform/i86pc/amd64/boot_archive"
573 # Unpleasant. Typically we'll have 'root=foo -k' or 'root=foo /kernel -k',
574 # and we need to maintain Xen properties (root= and ip=) and the kernel
575 # before any user args.
577 xenargs = ""
578 userargs = ""
580 if not cfg["args"]:
581 cfg["args"] = cfg["kernel"]
582 else:
583 for arg in cfg["args"].split():
584 if re.match("^root=", arg) or re.match("^ip=", arg):
585 xenargs += arg + " "
586 elif arg != cfg["kernel"]:
587 userargs += arg + " "
588 cfg["args"] = xenargs + " " + cfg["kernel"] + " " + userargs
590 return cfg
592 def sniff_netware(fs, cfg):
593 if not fs.file_exists("/nwserver/xnloader.sys"):
594 return cfg
596 if not cfg["kernel"]:
597 cfg["kernel"] = "/nwserver/xnloader.sys"
599 return cfg
601 if __name__ == "__main__":
602 sel = None
604 def usage():
605 print >> sys.stderr, "Usage: %s [-q|--quiet] [-i|--interactive] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] <image>" %(sys.argv[0],)
607 try:
608 opts, args = getopt.gnu_getopt(sys.argv[1:], 'qih::',
609 ["quiet", "interactive", "help", "output=",
610 "entry=", "kernel=", "ramdisk=", "args=",
611 "isconfig"])
612 except getopt.GetoptError:
613 usage()
614 sys.exit(1)
616 if len(args) < 1:
617 usage()
618 sys.exit(1)
619 file = args[0]
621 output = None
622 entry = None
623 interactive = True
624 isconfig = False
626 # what was passed in
627 incfg = { "kernel": None, "ramdisk": None, "args": "" }
628 # what grub or sniffing chose
629 chosencfg = { "kernel": None, "ramdisk": None, "args": None }
630 # what to boot
631 bootcfg = { "kernel": None, "ramdisk": None, "args": None }
633 for o, a in opts:
634 if o in ("-q", "--quiet"):
635 interactive = False
636 elif o in ("-i", "--interactive"):
637 interactive = True
638 elif o in ("-h", "--help"):
639 usage()
640 sys.exit()
641 elif o in ("--output",):
642 output = a
643 elif o in ("--kernel",):
644 incfg["kernel"] = a
645 elif o in ("--ramdisk",):
646 incfg["ramdisk"] = a
647 elif o in ("--args",):
648 incfg["args"] = a
649 elif o in ("--entry",):
650 entry = a
651 # specifying the entry to boot implies non-interactive
652 interactive = False
653 elif o in ("--isconfig",):
654 isconfig = True
656 if output is None or output == "-":
657 fd = sys.stdout.fileno()
658 else:
659 fd = os.open(output, os.O_WRONLY)
661 # debug
662 if isconfig:
663 chosencfg = run_grub(file, entry, fs, incfg["args"])
664 print " kernel: %s" % chosencfg["kernel"]
665 if img.initrd:
666 print " initrd: %s" % chosencfg["ramdisk"]
667 print " args: %s" % chosencfg["args"]
668 sys.exit(0)
670 # if boot filesystem is set then pass to fsimage.open
671 bootfsargs = '"%s"' % incfg["args"]
672 bootfsgroup = re.findall('zfs-bootfs=(.*?)[\s\,\"]', bootfsargs)
673 if bootfsgroup:
674 fs = fsimage.open(file, get_fs_offset(file), bootfsgroup[0])
675 else:
676 fs = fsimage.open(file, get_fs_offset(file))
678 chosencfg = sniff_solaris(fs, incfg)
680 if not chosencfg["kernel"]:
681 chosencfg = sniff_netware(fs, incfg)
683 if not chosencfg["kernel"]:
684 chosencfg = run_grub(file, entry, fs, incfg["args"])
686 data = fs.open_file(chosencfg["kernel"]).read()
687 (tfd, bootcfg["kernel"]) = tempfile.mkstemp(prefix="boot_kernel.",
688 dir="/var/run/xend/boot")
689 os.write(tfd, data)
690 os.close(tfd)
692 if chosencfg["ramdisk"]:
693 data = fs.open_file(chosencfg["ramdisk"],).read()
694 (tfd, bootcfg["ramdisk"]) = tempfile.mkstemp(prefix="boot_ramdisk.",
695 dir="/var/run/xend/boot")
696 os.write(tfd, data)
697 os.close(tfd)
698 else:
699 initrd = None
701 sxp = "linux (kernel %s)" % bootcfg["kernel"]
702 if bootcfg["ramdisk"]:
703 sxp += "(ramdisk %s)" % bootcfg["ramdisk"]
704 if chosencfg["args"]:
705 zfsinfo = fsimage.getbootstring(fs)
706 if zfsinfo is None:
707 sxp += "(args \"%s\")" % chosencfg["args"]
708 else:
709 e = re.compile("zfs-bootfs=[\w\-\.\:@/]+" )
710 (chosencfg["args"],count) = e.subn(zfsinfo, chosencfg["args"])
711 if count == 0:
712 chosencfg["args"] += " -B %s" % zfsinfo
713 sxp += "(args \"%s\")" % (chosencfg["args"])
715 sys.stdout.flush()
716 os.write(fd, sxp)