debuggers.hg

view tools/python/xen/xend/XendBootloader.py @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children 183d253550f3
line source
1 #
2 # XendBootloader.py - Framework to run a boot loader for picking the kernel
3 #
4 # Copyright 2005-2006 Red Hat, Inc.
5 # Jeremy Katz <katzj@redhat.com>
6 #
7 # This software may be freely redistributed under the terms of the GNU
8 # general public license.
9 #
10 # You should have received a copy of the GNU General Public License
11 # along with this program; if not, write to the Free Software
12 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
13 #
15 import os, select, errno, stat, signal, tty
16 import random
17 import shlex
18 from xen.xend import sxp
20 from xen.util import mkdir
21 from XendLogging import log
22 from XendError import VmError
24 import pty, termios, fcntl
25 from xen.lowlevel import ptsname
27 def bootloader(blexec, disk, dom, quiet = False, blargs = '', kernel = '',
28 ramdisk = '', kernel_args = ''):
29 """Run the boot loader executable on the given disk and return a
30 config image.
31 @param blexec Binary to use as the boot loader
32 @param disk Disk to run the boot loader on.
33 @param dom DomainInfo representing the domain being booted.
34 @param quiet Run in non-interactive mode, just booting the default.
35 @param blargs Arguments to pass to the bootloader."""
37 if not os.access(blexec, os.X_OK):
38 msg = "Bootloader isn't executable"
39 log.error(msg)
40 raise VmError(msg)
41 if not os.access(disk, os.R_OK):
42 msg = "Disk isn't accessible"
43 log.error(msg)
44 raise VmError(msg)
46 if os.uname()[0] == "NetBSD" and disk.startswith('/dev/'):
47 disk = disk.replace("/dev/", "/dev/r")
49 mkdir.parents("/var/run/xend/boot/", stat.S_IRWXU)
51 while True:
52 fifo = "/var/run/xend/boot/xenbl.%s" %(random.randint(0, 32000),)
53 try:
54 os.mkfifo(fifo, 0600)
55 except OSError, e:
56 if (e.errno != errno.EEXIST):
57 raise
58 break
60 # We need to present the bootloader's tty as a pty slave that xenconsole
61 # can access. Since the bootloader itself needs a pty slave,
62 # we end up with a connection like this:
63 #
64 # xenconsole -- (slave pty1 master) <-> (master pty2 slave) -- bootloader
65 #
66 # where we copy characters between the two master fds, as well as
67 # listening on the bootloader's fifo for the results.
69 (m1, s1) = pty.openpty()
70 tty.setraw(m1);
71 fcntl.fcntl(m1, fcntl.F_SETFL, os.O_NDELAY);
72 os.close(s1)
73 slavename = ptsname.ptsname(m1)
74 dom.storeDom("console/tty", slavename)
76 # Release the domain lock here, because we definitely don't want
77 # a stuck bootloader to deny service to other xend clients.
78 from xen.xend import XendDomain
79 domains = XendDomain.instance()
80 domains.domains_lock.release()
82 (child, m2) = pty.fork()
83 if (not child):
84 args = [ blexec ]
85 if kernel:
86 args.append("--kernel=%s" % kernel)
87 if ramdisk:
88 args.append("--ramdisk=%s" % ramdisk)
89 if kernel_args:
90 args.append("--args=%s" % kernel_args)
91 if quiet:
92 args.append("-q")
93 args.append("--output=%s" % fifo)
94 if blargs:
95 args.extend(shlex.split(blargs))
96 args.append(disk)
98 try:
99 log.debug("Launching bootloader as %s." % str(args))
100 env = os.environ.copy()
101 env['TERM'] = 'vt100'
102 os.execvpe(args[0], args, env)
103 except OSError, e:
104 print e
105 pass
106 os._exit(1)
108 # record that this domain is bootloading
109 dom.bootloader_pid = child
111 tty.setraw(m2);
112 fcntl.fcntl(m2, fcntl.F_SETFL, os.O_NDELAY);
113 while True:
114 try:
115 r = os.open(fifo, os.O_RDONLY)
116 except OSError, e:
117 if e.errno == errno.EINTR:
118 continue
119 break
120 ret = ""
121 inbuf=""; outbuf="";
122 while True:
123 sel = select.select([r, m1, m2], [m1, m2], [])
124 try:
125 if m1 in sel[0]:
126 s = os.read(m1, 1)
127 inbuf += s
128 if m2 in sel[1] and len(inbuf) != 0:
129 os.write(m2, inbuf[0])
130 inbuf = inbuf[1:]
131 except OSError, e:
132 if e.errno == errno.EIO:
133 pass
134 try:
135 if m2 in sel[0]:
136 s = os.read(m2, 1)
137 outbuf += s
138 if m1 in sel[1] and len(outbuf) != 0:
139 os.write(m1, outbuf[0])
140 outbuf = outbuf[1:]
141 except OSError, e:
142 if e.errno == errno.EIO:
143 pass
144 if r in sel[0]:
145 s = os.read(r, 1)
146 ret = ret + s
147 if len(s) == 0:
148 break
149 del inbuf
150 del outbuf
151 os.waitpid(child, 0)
152 os.close(r)
153 os.close(m2)
154 os.close(m1)
155 os.unlink(fifo)
157 # Re-acquire the lock to cover the changes we're about to make
158 # when we return to domain creation.
159 domains.domains_lock.acquire()
161 if dom.bootloader_pid is None:
162 msg = "Domain was died while the bootloader was running."
163 log.error(msg)
164 raise VmError, msg
166 dom.bootloader_pid = None
168 if len(ret) == 0:
169 msg = "Boot loader didn't return any data!"
170 log.error(msg)
171 raise VmError, msg
173 pin = sxp.Parser()
174 pin.input(ret)
175 pin.input_eof()
176 blcfg = pin.val
177 return blcfg
180 def bootloader_tidy(dom):
181 if hasattr(dom, "bootloader_pid") and dom.bootloader_pid is not None:
182 pid = dom.bootloader_pid
183 dom.bootloader_pid = None
184 os.kill(pid, signal.SIGKILL)