Statistics
| Branch: | Tag: | Revision:

root / tools / lvmstrap @ 1a8c0ce1

History | View | Annotate | Download (23.3 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 a8083063 Iustin Pop
"""Program which configures LVM on the Ganeti nodes.
23 a8083063 Iustin Pop
24 a8083063 Iustin Pop
This program wipes disks and creates a volume group on top of them. It
25 a8083063 Iustin Pop
can also show disk information to help you decide which disks you want
26 a8083063 Iustin Pop
to wipe.
27 a8083063 Iustin Pop
28 a8083063 Iustin Pop
The error handling is done by raising our own exceptions from most of
29 a8083063 Iustin Pop
the functions; these exceptions then handled globally in the main()
30 a8083063 Iustin Pop
function. The exceptions that each function can raise are not
31 a8083063 Iustin Pop
documented individually, since almost every error path ends in a
32 a8083063 Iustin Pop
raise.
33 a8083063 Iustin Pop
34 a8083063 Iustin Pop
Another two exceptions that are handled globally are IOError and
35 a8083063 Iustin Pop
OSError. The idea behind this is, since we run as root, we should
36 a8083063 Iustin Pop
usually not get these errors, but if we do it's most probably a system
37 a8083063 Iustin Pop
error, so they should be handled and the user instructed to report
38 a8083063 Iustin Pop
them.
39 a8083063 Iustin Pop
"""
40 a8083063 Iustin Pop
41 a8083063 Iustin Pop
42 a8083063 Iustin Pop
import os
43 a8083063 Iustin Pop
import sys
44 a8083063 Iustin Pop
import optparse
45 a8083063 Iustin Pop
import time
46 a8083063 Iustin Pop
47 a8083063 Iustin Pop
from ganeti.utils import RunCmd
48 a8083063 Iustin Pop
from ganeti import constants
49 a8083063 Iustin Pop
50 a8083063 Iustin Pop
USAGE = ("\tlvmstrap.py diskinfo\n"
51 a8083063 Iustin Pop
         "\tlvmstrap.py [--vgname=NAME] { --alldisks | --disks DISKLIST }"
52 a8083063 Iustin Pop
         " create")
53 a8083063 Iustin Pop
54 a8083063 Iustin Pop
verbose_flag = False
55 a8083063 Iustin Pop
56 a8083063 Iustin Pop
57 a8083063 Iustin Pop
class Error(Exception):
58 a8083063 Iustin Pop
  """Generic exception"""
59 a8083063 Iustin Pop
  pass
60 a8083063 Iustin Pop
61 a8083063 Iustin Pop
62 a8083063 Iustin Pop
class ProgrammingError(Error):
63 a8083063 Iustin Pop
  """Exception denoting invalid assumptions in programming.
64 a8083063 Iustin Pop
65 a8083063 Iustin Pop
  This should catch sysfs tree changes, or otherwise incorrect
66 a8083063 Iustin Pop
  assumptions about the contents of the /sys/block/... directories.
67 a8083063 Iustin Pop
  """
68 a8083063 Iustin Pop
  pass
69 a8083063 Iustin Pop
70 a8083063 Iustin Pop
71 a8083063 Iustin Pop
class SysconfigError(Error):
72 a8083063 Iustin Pop
  """Exception denoting invalid system configuration.
73 a8083063 Iustin Pop
74 a8083063 Iustin Pop
  If the system configuration is somehow wrong (e.g. /dev files
75 a8083063 Iustin Pop
  missing, or having mismatched major/minor numbers relative to
76 a8083063 Iustin Pop
  /sys/block devices), this exception will be raised.
77 a8083063 Iustin Pop
78 a8083063 Iustin Pop
  This should usually mean that the installation of the Xen node
79 a8083063 Iustin Pop
  failed in some steps.
80 a8083063 Iustin Pop
  """
81 a8083063 Iustin Pop
  pass
82 a8083063 Iustin Pop
83 a8083063 Iustin Pop
84 a8083063 Iustin Pop
class PrereqError(Error):
85 a8083063 Iustin Pop
  """Exception denoting invalid prerequisites.
86 a8083063 Iustin Pop
87 a8083063 Iustin Pop
  If the node does not meet the requirements for cluster membership, this
88 a8083063 Iustin Pop
  exception will be raised. Things like wrong kernel version, or no
89 a8083063 Iustin Pop
  free disks, etc. belong here.
90 a8083063 Iustin Pop
91 a8083063 Iustin Pop
  This should usually mean that the build steps for the Xen node were
92 a8083063 Iustin Pop
  not followed correctly.
93 a8083063 Iustin Pop
  """
94 a8083063 Iustin Pop
  pass
95 a8083063 Iustin Pop
96 a8083063 Iustin Pop
97 a8083063 Iustin Pop
class OperationalError(Error):
98 a8083063 Iustin Pop
  """Exception denoting actual errors.
99 a8083063 Iustin Pop
100 a8083063 Iustin Pop
  Errors during the bootstrapping are signaled using this exception.
101 a8083063 Iustin Pop
  """
102 a8083063 Iustin Pop
  pass
103 a8083063 Iustin Pop
104 a8083063 Iustin Pop
105 a8083063 Iustin Pop
class ParameterError(Error):
106 a8083063 Iustin Pop
  """Exception denoting invalid input from user.
107 a8083063 Iustin Pop
108 a8083063 Iustin Pop
  Wrong disks given as parameters will be signaled using this
109 a8083063 Iustin Pop
  exception.
110 a8083063 Iustin Pop
  """
111 a8083063 Iustin Pop
  pass
112 a8083063 Iustin Pop
113 a8083063 Iustin Pop
def Usage():
114 a8083063 Iustin Pop
  """Shows program usage information and exits the program."""
115 a8083063 Iustin Pop
116 a8083063 Iustin Pop
  print >> sys.stderr, "Usage:"
117 a8083063 Iustin Pop
  print >> sys.stderr, USAGE
118 a8083063 Iustin Pop
  sys.exit(2)
119 a8083063 Iustin Pop
120 a8083063 Iustin Pop
121 a8083063 Iustin Pop
def ParseOptions():
122 a8083063 Iustin Pop
  """Parses the command line options.
123 a8083063 Iustin Pop
124 a8083063 Iustin Pop
  In case of command line errors, it will show the usage and exit the
125 a8083063 Iustin Pop
  program.
126 a8083063 Iustin Pop
127 a8083063 Iustin Pop
  Returns:
128 a8083063 Iustin Pop
    (options, args), as returned by OptionParser.parse_args
129 a8083063 Iustin Pop
  """
130 a8083063 Iustin Pop
  global verbose_flag
131 a8083063 Iustin Pop
132 a8083063 Iustin Pop
  parser = optparse.OptionParser(usage="\n%s" % USAGE,
133 a8083063 Iustin Pop
                                 version="%%prog (ganeti) %s" %
134 a8083063 Iustin Pop
                                 constants.RELEASE_VERSION)
135 a8083063 Iustin Pop
136 a8083063 Iustin Pop
  parser.add_option("--alldisks", dest="alldisks",
137 a8083063 Iustin Pop
                    help="erase ALL disks", action="store_true",
138 a8083063 Iustin Pop
                    default=False)
139 a8083063 Iustin Pop
  parser.add_option("-d", "--disks", dest="disks",
140 a8083063 Iustin Pop
                    help="Choose disks (e.g. hda,hdg)",
141 a8083063 Iustin Pop
                    metavar="DISKLIST")
142 a8083063 Iustin Pop
  parser.add_option("-v", "--verbose",
143 a8083063 Iustin Pop
                    action="store_true", dest="verbose", default=False,
144 a8083063 Iustin Pop
                    help="print command execution messages to stdout")
145 a8083063 Iustin Pop
  parser.add_option("-g", "--vg-name", type="string",
146 a8083063 Iustin Pop
                    dest="vgname", default="xenvg", metavar="NAME",
147 a8083063 Iustin Pop
                    help="the volume group to be created [default: xenvg]")
148 a8083063 Iustin Pop
149 a8083063 Iustin Pop
150 a8083063 Iustin Pop
  options, args = parser.parse_args()
151 a8083063 Iustin Pop
  if len(args) != 1:
152 a8083063 Iustin Pop
    Usage()
153 a8083063 Iustin Pop
154 a8083063 Iustin Pop
  verbose_flag = options.verbose
155 a8083063 Iustin Pop
156 a8083063 Iustin Pop
  return options, args
157 a8083063 Iustin Pop
158 a8083063 Iustin Pop
159 a8083063 Iustin Pop
def ExecCommand(command):
160 a8083063 Iustin Pop
  """Executes a command.
161 a8083063 Iustin Pop
162 a8083063 Iustin Pop
  This is just a wrapper around commands.getstatusoutput, with the
163 a8083063 Iustin Pop
  difference that if the command line argument -v has been given, it
164 a8083063 Iustin Pop
  will print the command line and the command output on stdout.
165 a8083063 Iustin Pop
166 a8083063 Iustin Pop
  Args:
167 a8083063 Iustin Pop
    the command line
168 a8083063 Iustin Pop
  Returns:
169 a8083063 Iustin Pop
    (status, output) where status is the exit status and output the
170 a8083063 Iustin Pop
      stdout and stderr of the command together
171 a8083063 Iustin Pop
  """
172 a8083063 Iustin Pop
173 a8083063 Iustin Pop
  if verbose_flag:
174 a8083063 Iustin Pop
    print command
175 a8083063 Iustin Pop
  result = RunCmd(command)
176 a8083063 Iustin Pop
  if verbose_flag:
177 a8083063 Iustin Pop
    print result.output
178 a8083063 Iustin Pop
  return result
179 a8083063 Iustin Pop
180 a8083063 Iustin Pop
181 a8083063 Iustin Pop
def CheckPrereq():
182 a8083063 Iustin Pop
  """Check the prerequisites of this program.
183 a8083063 Iustin Pop
184 a8083063 Iustin Pop
  It check that it runs on Linux 2.6, and that /sys is mounted and the
185 a8083063 Iustin Pop
  fact that /sys/block is a directory.
186 a8083063 Iustin Pop
  """
187 a8083063 Iustin Pop
188 a8083063 Iustin Pop
  if os.getuid() != 0:
189 a8083063 Iustin Pop
    raise PrereqError("This tool runs as root only. Really.")
190 a8083063 Iustin Pop
191 a8083063 Iustin Pop
  osname, nodename, release, version, arch = os.uname()
192 a8083063 Iustin Pop
  if osname != 'Linux':
193 a8083063 Iustin Pop
    raise PrereqError("This tool only runs on Linux "
194 a8083063 Iustin Pop
                      "(detected OS: %s)." % osname)
195 a8083063 Iustin Pop
196 a8083063 Iustin Pop
  if not release.startswith("2.6."):
197 a8083063 Iustin Pop
    raise PrereqError("Wrong major kernel version (detected %s, needs "
198 a8083063 Iustin Pop
                      "2.6.*)" % release)
199 a8083063 Iustin Pop
200 a8083063 Iustin Pop
  if not os.path.ismount("/sys"):
201 a8083063 Iustin Pop
    raise PrereqError("Can't find a filesystem mounted at /sys. "
202 a8083063 Iustin Pop
                      "Please mount /sys.")
203 a8083063 Iustin Pop
204 a8083063 Iustin Pop
  if not os.path.isdir("/sys/block"):
205 a8083063 Iustin Pop
    raise SysconfigError("Can't find /sys/block directory. Has the "
206 a8083063 Iustin Pop
                         "layout of /sys changed?")
207 a8083063 Iustin Pop
208 a8083063 Iustin Pop
  if not os.path.ismount("/proc"):
209 a8083063 Iustin Pop
    raise PrereqError("Can't find a filesystem mounted at /proc. "
210 a8083063 Iustin Pop
                      "Please mount /proc.")
211 a8083063 Iustin Pop
212 a8083063 Iustin Pop
  if not os.path.exists("/proc/mounts"):
213 a8083063 Iustin Pop
    raise SysconfigError("Can't find /proc/mounts")
214 a8083063 Iustin Pop
215 a8083063 Iustin Pop
216 a8083063 Iustin Pop
def CheckVGExists(vgname):
217 a8083063 Iustin Pop
  """Checks to see if a volume group exists.
218 a8083063 Iustin Pop
219 a8083063 Iustin Pop
  Args:
220 a8083063 Iustin Pop
    vgname: the volume group name
221 a8083063 Iustin Pop
222 a8083063 Iustin Pop
  Returns:
223 a8083063 Iustin Pop
    a four-tuple (exists, lv_count, vg_size, vg_free), where:
224 a8083063 Iustin Pop
      exists: True if the volume exists, otherwise False; if False,
225 a8083063 Iustin Pop
        all other members of the tuple are None
226 a8083063 Iustin Pop
      lv_count: The number of logical volumes in the volume group
227 a8083063 Iustin Pop
      vg_size: The total size of the volume group (in gibibytes)
228 a8083063 Iustin Pop
      vg_free: The available space in the volume group
229 a8083063 Iustin Pop
  """
230 a8083063 Iustin Pop
231 a8083063 Iustin Pop
  result = ExecCommand("vgs --nohead -o lv_count,vg_size,"
232 a8083063 Iustin Pop
                       "vg_free --nosuffix --units g "
233 a8083063 Iustin Pop
                       "--ignorelockingfailure %s" % vgname)
234 a8083063 Iustin Pop
  if not result.failed:
235 a8083063 Iustin Pop
    try:
236 a8083063 Iustin Pop
      lv_count, vg_size, vg_free = result.stdout.strip().split()
237 a8083063 Iustin Pop
    except ValueError:
238 a8083063 Iustin Pop
      # This means the output of vgdisplay can't be parsed
239 a8083063 Iustin Pop
      raise PrereqError("cannot parse output of vgs (%s)" % result.stdout)
240 a8083063 Iustin Pop
  else:
241 a8083063 Iustin Pop
    lv_count = vg_size = vg_free = None
242 a8083063 Iustin Pop
243 a8083063 Iustin Pop
  return not result.failed, lv_count, vg_size, vg_free
244 a8083063 Iustin Pop
245 a8083063 Iustin Pop
246 a8083063 Iustin Pop
def CheckSysDev(name, devnum):
247 a8083063 Iustin Pop
  """Checks consistency between /sys and /dev trees.
248 a8083063 Iustin Pop
249 a8083063 Iustin Pop
  In /sys/block/<name>/dev and /sys/block/<name>/<part>/dev are the
250 a8083063 Iustin Pop
  kernel-known device numbers. The /dev/<name> block/char devices are
251 a8083063 Iustin Pop
  created by userspace and thus could differ from the kernel
252 a8083063 Iustin Pop
  view. This function checks the consistency between the device number
253 a8083063 Iustin Pop
  read from /sys and the actual device number in /dev.
254 a8083063 Iustin Pop
255 a8083063 Iustin Pop
  Note that since the system could be using udev which removes and
256 a8083063 Iustin Pop
  recreates the device nodes on partition table rescan, we need to do
257 a8083063 Iustin Pop
  some retries here. Since we only do a stat, we can afford to do many
258 a8083063 Iustin Pop
  short retries.
259 a8083063 Iustin Pop
260 a8083063 Iustin Pop
  Args:
261 a8083063 Iustin Pop
   name: the device name, e.g. 'sda'
262 a8083063 Iustin Pop
   devnum: the device number, e.g. 0x803 (2051 in decimal) for sda3
263 a8083063 Iustin Pop
264 a8083063 Iustin Pop
  Returns:
265 a8083063 Iustin Pop
    None; failure of the check is signalled by raising a
266 a8083063 Iustin Pop
      SysconfigError exception
267 a8083063 Iustin Pop
  """
268 a8083063 Iustin Pop
269 a8083063 Iustin Pop
  path = "/dev/%s" % name
270 a8083063 Iustin Pop
  for retries in range(40):
271 a8083063 Iustin Pop
    if os.path.exists(path):
272 a8083063 Iustin Pop
      break
273 a8083063 Iustin Pop
    time.sleep(0.250)
274 a8083063 Iustin Pop
  else:
275 a8083063 Iustin Pop
    raise SysconfigError("the device file %s does not exist, but the block "
276 a8083063 Iustin Pop
                         "device exists in the /sys/block tree" % path)
277 a8083063 Iustin Pop
  rdev = os.stat(path).st_rdev
278 a8083063 Iustin Pop
  if devnum != rdev:
279 a8083063 Iustin Pop
    raise SysconfigError("For device %s, the major:minor in /dev is %04x "
280 a8083063 Iustin Pop
                         "while the major:minor in sysfs is %s" %
281 a8083063 Iustin Pop
                         (path, rdev, devnum))
282 a8083063 Iustin Pop
283 a8083063 Iustin Pop
284 a8083063 Iustin Pop
def ReadDev(syspath):
285 a8083063 Iustin Pop
  """Reads the device number from a sysfs path.
286 a8083063 Iustin Pop
287 a8083063 Iustin Pop
  The device number is given in sysfs under a block device directory
288 a8083063 Iustin Pop
  in a file named 'dev' which contains major:minor (in ASCII). This
289 a8083063 Iustin Pop
  function reads that file and converts the major:minor pair to a dev
290 a8083063 Iustin Pop
  number.
291 a8083063 Iustin Pop
292 a8083063 Iustin Pop
  Args:
293 a8083063 Iustin Pop
    syspath: the path to a block device dir in sysfs, e.g. /sys/block/sda
294 a8083063 Iustin Pop
295 a8083063 Iustin Pop
  Returns:
296 a8083063 Iustin Pop
    the device number
297 a8083063 Iustin Pop
  """
298 a8083063 Iustin Pop
299 a8083063 Iustin Pop
  if not os.path.exists("%s/dev" % syspath):
300 a8083063 Iustin Pop
    raise ProgrammingError("Invalid path passed to ReadDev: %s" % syspath)
301 a8083063 Iustin Pop
  f = open("%s/dev" % syspath)
302 a8083063 Iustin Pop
  data = f.read().strip()
303 a8083063 Iustin Pop
  f.close()
304 a8083063 Iustin Pop
  major, minor = data.split(":", 1)
305 a8083063 Iustin Pop
  major = int(major)
306 a8083063 Iustin Pop
  minor = int(minor)
307 a8083063 Iustin Pop
  dev = os.makedev(major, minor)
308 a8083063 Iustin Pop
  return dev
309 a8083063 Iustin Pop
310 a8083063 Iustin Pop
311 a8083063 Iustin Pop
def ReadSize(syspath):
312 a8083063 Iustin Pop
  """Reads the size from a sysfs path.
313 a8083063 Iustin Pop
314 a8083063 Iustin Pop
  The size is given in sysfs under a block device directory in a file
315 a8083063 Iustin Pop
  named 'size' which contains the number of sectors (in ASCII). This
316 a8083063 Iustin Pop
  function reads that file and converts the number in sectors to the
317 a8083063 Iustin Pop
  size in bytes.
318 a8083063 Iustin Pop
319 a8083063 Iustin Pop
  Args:
320 a8083063 Iustin Pop
    syspath: the path to a block device dir in sysfs, e.g. /sys/block/sda
321 a8083063 Iustin Pop
322 a8083063 Iustin Pop
  Returns:
323 a8083063 Iustin Pop
    the device size in bytes
324 a8083063 Iustin Pop
  """
325 a8083063 Iustin Pop
326 a8083063 Iustin Pop
  if not os.path.exists("%s/size" % syspath):
327 a8083063 Iustin Pop
    raise ProgrammingError("Invalid path passed to ReadSize: %s" % syspath)
328 a8083063 Iustin Pop
  f = open("%s/size" % syspath)
329 a8083063 Iustin Pop
  data = f.read().strip()
330 a8083063 Iustin Pop
  f.close()
331 a8083063 Iustin Pop
  size = 512L * int(data)
332 a8083063 Iustin Pop
  return size
333 a8083063 Iustin Pop
334 a8083063 Iustin Pop
335 a8083063 Iustin Pop
def ReadPV(name):
336 a8083063 Iustin Pop
  """Reads physical volume information.
337 a8083063 Iustin Pop
338 a8083063 Iustin Pop
  This function tries to see if a block device is a physical volume.
339 a8083063 Iustin Pop
340 a8083063 Iustin Pop
  Args:
341 a8083063 Iustin Pop
    dev: the device name (e.g. sda)
342 a8083063 Iustin Pop
  Returns:
343 a8083063 Iustin Pop
    The name of the volume group to which this PV belongs, or
344 a8083063 Iustin Pop
    "" if this PV is not in use, or
345 a8083063 Iustin Pop
    None if this is not a PV
346 a8083063 Iustin Pop
  """
347 a8083063 Iustin Pop
348 a8083063 Iustin Pop
  result = ExecCommand("pvdisplay -c /dev/%s" % name)
349 a8083063 Iustin Pop
  if result.failed:
350 a8083063 Iustin Pop
    return None
351 a8083063 Iustin Pop
  vgname = result.stdout.strip().split(":")[1]
352 a8083063 Iustin Pop
  return vgname
353 a8083063 Iustin Pop
354 a8083063 Iustin Pop
355 a8083063 Iustin Pop
def GetDiskList():
356 a8083063 Iustin Pop
  """Computes the block device list for this system.
357 a8083063 Iustin Pop
358 a8083063 Iustin Pop
  This function examines the /sys/block tree and using information
359 a8083063 Iustin Pop
  therein, computes the status of the block device.
360 a8083063 Iustin Pop
361 a8083063 Iustin Pop
  Returns:
362 a8083063 Iustin Pop
    [(name, size, dev, partitions, inuse), ...]
363 a8083063 Iustin Pop
  where:
364 a8083063 Iustin Pop
    name is the block device name (e.g. sda)
365 a8083063 Iustin Pop
    size the size in bytes
366 a8083063 Iustin Pop
    dev  the device number (e.g. 8704 for hdg)
367 a8083063 Iustin Pop
    partitions is [(name, size, dev), ...] mirroring the disk list data
368 a8083063 Iustin Pop
    inuse is a boolean showing the in-use status of the disk, computed as the
369 a8083063 Iustin Pop
      possibility of re-reading the partition table (the meaning of the
370 a8083063 Iustin Pop
      operation varies with the kernel version, but is usually accurate;
371 a8083063 Iustin Pop
      a mounted disk/partition or swap-area or PV with active LVs on it
372 a8083063 Iustin Pop
      is busy)
373 a8083063 Iustin Pop
  """
374 a8083063 Iustin Pop
375 a8083063 Iustin Pop
  dlist = []
376 a8083063 Iustin Pop
  for name in os.listdir("/sys/block"):
377 a8083063 Iustin Pop
    if (not name.startswith("hd") and
378 a8083063 Iustin Pop
        not name.startswith("sd") and
379 3c9a0742 Michael Hanselmann
        not name.startswith("ubd")):
380 a8083063 Iustin Pop
      continue
381 a8083063 Iustin Pop
382 a8083063 Iustin Pop
    size = ReadSize("/sys/block/%s" % name)
383 a8083063 Iustin Pop
384 a8083063 Iustin Pop
    f = open("/sys/block/%s/removable" % name)
385 a8083063 Iustin Pop
    removable = int(f.read().strip())
386 a8083063 Iustin Pop
    f.close()
387 a8083063 Iustin Pop
388 a8083063 Iustin Pop
    if removable:
389 a8083063 Iustin Pop
      continue
390 a8083063 Iustin Pop
391 a8083063 Iustin Pop
    dev = ReadDev("/sys/block/%s" % name)
392 a8083063 Iustin Pop
    CheckSysDev(name, dev)
393 a8083063 Iustin Pop
    inuse = not CheckReread(name)
394 a8083063 Iustin Pop
    # Enumerate partitions of the block device
395 a8083063 Iustin Pop
    partitions = []
396 a8083063 Iustin Pop
    for partname in os.listdir("/sys/block/%s" % name):
397 a8083063 Iustin Pop
      if not partname.startswith(name):
398 a8083063 Iustin Pop
        continue
399 a8083063 Iustin Pop
      partdev = ReadDev("/sys/block/%s/%s" % (name, partname))
400 a8083063 Iustin Pop
      partsize = ReadSize("/sys/block/%s/%s" % (name, partname))
401 a8083063 Iustin Pop
      CheckSysDev(partname, partdev)
402 a8083063 Iustin Pop
      partitions.append((partname, partsize, partdev))
403 a8083063 Iustin Pop
    partitions.sort()
404 a8083063 Iustin Pop
    dlist.append((name, size, dev, partitions, inuse))
405 a8083063 Iustin Pop
  dlist.sort()
406 a8083063 Iustin Pop
  return dlist
407 a8083063 Iustin Pop
408 a8083063 Iustin Pop
409 a8083063 Iustin Pop
def GetMountInfo():
410 a8083063 Iustin Pop
  """Reads /proc/mounts and computes the mountpoint-devnum mapping.
411 a8083063 Iustin Pop
412 a8083063 Iustin Pop
  This function reads /proc/mounts, finds the mounted filesystems
413 a8083063 Iustin Pop
  (excepting a hard-coded blacklist of network and virtual
414 a8083063 Iustin Pop
  filesystems) and does a stat on these mountpoints. The st_dev number
415 a8083063 Iustin Pop
  of the results is memorised for later matching against the
416 a8083063 Iustin Pop
  /sys/block devices.
417 a8083063 Iustin Pop
418 a8083063 Iustin Pop
  Returns:
419 a8083063 Iustin Pop
   a mountpoint: device number dictionary
420 a8083063 Iustin Pop
  """
421 a8083063 Iustin Pop
422 a8083063 Iustin Pop
  f = open("/proc/mounts", "r")
423 a8083063 Iustin Pop
  mountlines = f.readlines()
424 a8083063 Iustin Pop
  f.close()
425 a8083063 Iustin Pop
  mounts = {}
426 a8083063 Iustin Pop
  for line in mountlines:
427 a8083063 Iustin Pop
    device, mountpoint, fstype, rest = line.split(None, 3)
428 a8083063 Iustin Pop
    # fs type blacklist
429 a8083063 Iustin Pop
    if fstype in ["nfs", "nfs4", "autofs", "tmpfs", "proc", "sysfs"]:
430 a8083063 Iustin Pop
      continue
431 a8083063 Iustin Pop
    try:
432 a8083063 Iustin Pop
      dev = os.stat(mountpoint).st_dev
433 a8083063 Iustin Pop
    except OSError, err:
434 a8083063 Iustin Pop
      # this should be a fairly rare error, since we are blacklisting
435 a8083063 Iustin Pop
      # network filesystems; with this in mind, we'll ignore it,
436 a8083063 Iustin Pop
      # since the rereadpt check catches in-use filesystems,
437 a8083063 Iustin Pop
      # and this is used for disk information only
438 a8083063 Iustin Pop
      print >> sys.stderr, ("Can't stat mountpoint '%s': %s" %
439 a8083063 Iustin Pop
                            (mountpoint, err))
440 a8083063 Iustin Pop
      print >> sys.stderr, "Ignoring."
441 a8083063 Iustin Pop
      continue
442 a8083063 Iustin Pop
    mounts[dev] = mountpoint
443 a8083063 Iustin Pop
  return mounts
444 a8083063 Iustin Pop
445 a8083063 Iustin Pop
446 a8083063 Iustin Pop
def DevInfo(name, dev, mountinfo):
447 a8083063 Iustin Pop
  """Computes miscellaneous informations about a block device.
448 a8083063 Iustin Pop
449 a8083063 Iustin Pop
  Args:
450 a8083063 Iustin Pop
    name: the device name, e.g. sda
451 a8083063 Iustin Pop
452 a8083063 Iustin Pop
  Returns:
453 a8083063 Iustin Pop
    (mpath, whatvg, fileinfo), where
454 a8083063 Iustin Pop
    mpath is the mount path where this device is mounted or None
455 a8083063 Iustin Pop
    whatvg is the result of the ReadPV function
456 a8083063 Iustin Pop
    fileinfo is the output of file -bs on the device
457 a8083063 Iustin Pop
  """
458 a8083063 Iustin Pop
459 a8083063 Iustin Pop
  if dev in mountinfo:
460 a8083063 Iustin Pop
    mpath = mountinfo[dev]
461 a8083063 Iustin Pop
  else:
462 a8083063 Iustin Pop
    mpath = None
463 a8083063 Iustin Pop
464 a8083063 Iustin Pop
  whatvg = ReadPV(name)
465 a8083063 Iustin Pop
466 a8083063 Iustin Pop
  result = ExecCommand("file -bs /dev/%s" % name)
467 a8083063 Iustin Pop
  if result.failed:
468 a8083063 Iustin Pop
    fileinfo = "<error: %s>" % result.stderr
469 a8083063 Iustin Pop
  fileinfo = result.stdout[:45]
470 a8083063 Iustin Pop
  return mpath, whatvg, fileinfo
471 a8083063 Iustin Pop
472 a8083063 Iustin Pop
473 a8083063 Iustin Pop
def ShowDiskInfo():
474 a8083063 Iustin Pop
  """Shows a nicely formatted block device list for this system.
475 a8083063 Iustin Pop
476 a8083063 Iustin Pop
  This function shows the user a table with the informations gathered
477 a8083063 Iustin Pop
  by the other functions defined, in order to help the user make a
478 a8083063 Iustin Pop
  choice about which disks should be allocated to our volume group.
479 a8083063 Iustin Pop
480 a8083063 Iustin Pop
  """
481 a8083063 Iustin Pop
  mounts = GetMountInfo()
482 a8083063 Iustin Pop
  dlist = GetDiskList()
483 a8083063 Iustin Pop
484 a8083063 Iustin Pop
  print "------- Disk information -------"
485 a8083063 Iustin Pop
  print ("%5s %7s %4s %5s %-10s %s" %
486 a8083063 Iustin Pop
         ("Name", "Size[M]", "Used", "Mount", "LVM?", "Info"))
487 a8083063 Iustin Pop
488 a8083063 Iustin Pop
  flatlist = []
489 a8083063 Iustin Pop
  # Flatten the [(disk, [partition,...]), ...] list
490 a8083063 Iustin Pop
  for name, size, dev, parts, inuse in dlist:
491 a8083063 Iustin Pop
    if inuse:
492 a8083063 Iustin Pop
      str_inuse = "yes"
493 a8083063 Iustin Pop
    else:
494 a8083063 Iustin Pop
      str_inuse = "no"
495 a8083063 Iustin Pop
    flatlist.append((name, size, dev, str_inuse))
496 a8083063 Iustin Pop
    for partname, partsize, partdev in parts:
497 a8083063 Iustin Pop
      flatlist.append((partname, partsize, partdev, ""))
498 a8083063 Iustin Pop
499 a8083063 Iustin Pop
  for name, size, dev, in_use in flatlist:
500 a8083063 Iustin Pop
    mp, vgname, fileinfo = DevInfo(name, dev, mounts)
501 a8083063 Iustin Pop
    if mp is None:
502 a8083063 Iustin Pop
      mp = "-"
503 a8083063 Iustin Pop
    if vgname is None:
504 a8083063 Iustin Pop
      lvminfo = "-"
505 a8083063 Iustin Pop
    elif vgname == "":
506 a8083063 Iustin Pop
      lvminfo = "yes,free"
507 a8083063 Iustin Pop
    else:
508 a8083063 Iustin Pop
      lvminfo = "in %s" % vgname
509 a8083063 Iustin Pop
510 a8083063 Iustin Pop
    if len(name) > 3:
511 a8083063 Iustin Pop
      # Indent partitions
512 a8083063 Iustin Pop
      name = " %s" % name
513 a8083063 Iustin Pop
    print ("%-5s %7.2f %-4s %-5s %-10s %s" %
514 a8083063 Iustin Pop
           (name, float(size) / 1024 / 1024, in_use, mp, lvminfo, fileinfo))
515 a8083063 Iustin Pop
516 a8083063 Iustin Pop
517 a8083063 Iustin Pop
def CheckReread(name):
518 a8083063 Iustin Pop
  """Check to see if a block device is in use.
519 a8083063 Iustin Pop
520 a8083063 Iustin Pop
  Uses blockdev to reread the partition table of a block device, and
521 a8083063 Iustin Pop
  thus compute the in-use status. See the discussion in GetDiskList
522 a8083063 Iustin Pop
  about the meaning of 'in use'.
523 a8083063 Iustin Pop
524 a8083063 Iustin Pop
  Returns:
525 a8083063 Iustin Pop
    boolean, the in-use status of the device
526 a8083063 Iustin Pop
  """
527 a8083063 Iustin Pop
528 a8083063 Iustin Pop
  for retries in range(3):
529 a8083063 Iustin Pop
    result = ExecCommand("blockdev --rereadpt /dev/%s" % name)
530 a8083063 Iustin Pop
    if not result.failed:
531 a8083063 Iustin Pop
      break
532 a8083063 Iustin Pop
    time.sleep(2)
533 a8083063 Iustin Pop
534 a8083063 Iustin Pop
  return not result.failed
535 a8083063 Iustin Pop
536 a8083063 Iustin Pop
537 a8083063 Iustin Pop
def WipeDisk(name):
538 a8083063 Iustin Pop
  """Wipes a block device.
539 a8083063 Iustin Pop
540 a8083063 Iustin Pop
  This function wipes a block device, by clearing and re-reading the
541 a8083063 Iustin Pop
  partition table. If not successful, it writes back the old partition
542 a8083063 Iustin Pop
  data, and leaves the cleanup to the user.
543 a8083063 Iustin Pop
544 a8083063 Iustin Pop
  Args:
545 a8083063 Iustin Pop
    the device name (e.g. sda)
546 a8083063 Iustin Pop
  """
547 a8083063 Iustin Pop
548 a8083063 Iustin Pop
  if not CheckReread(name):
549 a8083063 Iustin Pop
    raise OperationalError("CRITICAL: disk %s you selected seems to be in "
550 a8083063 Iustin Pop
                           "use. ABORTING!" % name)
551 a8083063 Iustin Pop
552 a8083063 Iustin Pop
  fd = os.open("/dev/%s" % name, os.O_RDWR | os.O_SYNC)
553 a8083063 Iustin Pop
  olddata = os.read(fd, 512)
554 a8083063 Iustin Pop
  if len(olddata) != 512:
555 a8083063 Iustin Pop
    raise OperationalError("CRITICAL: Can't read partition table information "
556 a8083063 Iustin Pop
                           "from /dev/%s (needed 512 bytes, got %d" %
557 a8083063 Iustin Pop
                           (name, len(olddata)))
558 a8083063 Iustin Pop
  newdata = "\0" * 512
559 a8083063 Iustin Pop
  os.lseek(fd, 0, 0)
560 a8083063 Iustin Pop
  bytes_written = os.write(fd, newdata)
561 a8083063 Iustin Pop
  os.close(fd)
562 a8083063 Iustin Pop
  if bytes_written != 512:
563 a8083063 Iustin Pop
    raise OperationalError("CRITICAL: Can't write partition table information"
564 a8083063 Iustin Pop
                           " to /dev/%s (tried to write 512 bytes, written "
565 a8083063 Iustin Pop
                           "%d. I don't know how to cleanup. Sorry." %
566 a8083063 Iustin Pop
                           (name, bytes_written))
567 a8083063 Iustin Pop
568 a8083063 Iustin Pop
  if not CheckReread(name):
569 a8083063 Iustin Pop
    fd = os.open("/dev/%s" % name, os.O_RDWR | os.O_SYNC)
570 a8083063 Iustin Pop
    os.write(fd, olddata)
571 a8083063 Iustin Pop
    os.close(fd)
572 a8083063 Iustin Pop
    raise OperationalError("CRITICAL: disk %s which I have just wiped cannot "
573 a8083063 Iustin Pop
                           "reread partition table. Most likely, it is "
574 a8083063 Iustin Pop
                           "in use. You have to clean after this yourself. "
575 a8083063 Iustin Pop
                           "I tried to restore the old partition table, "
576 a8083063 Iustin Pop
                           "but I cannot guarantee nothing has broken." %
577 a8083063 Iustin Pop
                           name)
578 a8083063 Iustin Pop
579 a8083063 Iustin Pop
580 a8083063 Iustin Pop
def PartitionDisk(name):
581 a8083063 Iustin Pop
  """Partitions a disk.
582 a8083063 Iustin Pop
583 a8083063 Iustin Pop
  This function creates a single partition spanning the entire disk,
584 a8083063 Iustin Pop
  by means of fdisk.
585 a8083063 Iustin Pop
586 a8083063 Iustin Pop
  Args:
587 a8083063 Iustin Pop
    the device name, e.g. sda
588 a8083063 Iustin Pop
  """
589 a8083063 Iustin Pop
  result = ExecCommand(
590 a8083063 Iustin Pop
    'echo ,,8e, | sfdisk /dev/%s' % name)
591 a8083063 Iustin Pop
  if result.failed:
592 a8083063 Iustin Pop
    raise OperationalError("CRITICAL: disk %s which I have just partitioned "
593 a8083063 Iustin Pop
                           "cannot reread its partition table, or there "
594 a8083063 Iustin Pop
                           "is some other sfdisk error. Likely, it is in "
595 a8083063 Iustin Pop
                           "use. You have to clean this yourself. Error "
596 a8083063 Iustin Pop
                           "message from sfdisk: %s" %
597 a8083063 Iustin Pop
                           (name, result.output))
598 a8083063 Iustin Pop
599 a8083063 Iustin Pop
600 a8083063 Iustin Pop
def CreatePVOnDisk(name):
601 a8083063 Iustin Pop
  """Creates a physical volume on a block device.
602 a8083063 Iustin Pop
603 a8083063 Iustin Pop
  This function creates a physical volume on a block device, overriding
604 a8083063 Iustin Pop
  all warnings. So it can wipe existing PVs and PVs which are in a VG.
605 a8083063 Iustin Pop
606 a8083063 Iustin Pop
  Args:
607 a8083063 Iustin Pop
    the device name, e.g. sda
608 a8083063 Iustin Pop
609 a8083063 Iustin Pop
  """
610 a8083063 Iustin Pop
  result = ExecCommand("pvcreate -yff /dev/%s1 " % name)
611 a8083063 Iustin Pop
  if result.failed:
612 a8083063 Iustin Pop
    raise OperationalError("I cannot create a physical volume on "
613 a8083063 Iustin Pop
                           "partition /dev/%s1. Error message: %s. "
614 a8083063 Iustin Pop
                           "Please clean up yourself." %
615 a8083063 Iustin Pop
                           (name, result.output))
616 a8083063 Iustin Pop
617 a8083063 Iustin Pop
618 a8083063 Iustin Pop
def CreateVG(vgname, disks):
619 a8083063 Iustin Pop
  """Creates the volume group.
620 a8083063 Iustin Pop
621 a8083063 Iustin Pop
  This function creates a volume group named `vgname` on the disks
622 a8083063 Iustin Pop
  given as parameters. The physical extent size is set to 64MB.
623 a8083063 Iustin Pop
624 a8083063 Iustin Pop
  Args:
625 a8083063 Iustin Pop
    disks: a list of disk names, e.g. ['sda','sdb']
626 a8083063 Iustin Pop
627 a8083063 Iustin Pop
  """
628 a8083063 Iustin Pop
  pnames = ["'/dev/%s1'" % disk for disk in disks]
629 a8083063 Iustin Pop
  result = ExecCommand("vgcreate -s 64MB '%s' %s" % (vgname, " ".join(pnames)))
630 a8083063 Iustin Pop
  if result.failed:
631 a8083063 Iustin Pop
    raise OperationalError("I cannot create the volume group %s from "
632 a8083063 Iustin Pop
                           "disks %s. Error message: %s. Please clean up "
633 a8083063 Iustin Pop
                           "yourself." %
634 a8083063 Iustin Pop
                           (vgname, " ".join(disks), result.output))
635 a8083063 Iustin Pop
636 a8083063 Iustin Pop
637 a8083063 Iustin Pop
def ValidateDiskList(options):
638 a8083063 Iustin Pop
  """Validates or computes the disk list for create.
639 a8083063 Iustin Pop
640 a8083063 Iustin Pop
  This function either computes the available disk list (if the user
641 a8083063 Iustin Pop
  gave --alldisks option), or validates the user-given disk list (by
642 a8083063 Iustin Pop
  using the --disks option) such that all given disks are present and
643 a8083063 Iustin Pop
  not in use.
644 a8083063 Iustin Pop
645 a8083063 Iustin Pop
  Args:
646 a8083063 Iustin Pop
    the options returned from OptParser.parse_options
647 a8083063 Iustin Pop
648 a8083063 Iustin Pop
  Returns:
649 a8083063 Iustin Pop
    a list of disk names, e.g. ['sda', 'sdb']
650 a8083063 Iustin Pop
  """
651 a8083063 Iustin Pop
652 a8083063 Iustin Pop
  sysdisks = GetDiskList()
653 a8083063 Iustin Pop
  if not sysdisks:
654 a8083063 Iustin Pop
    raise PrereqError("no disks found (I looked for "
655 a8083063 Iustin Pop
                      "non-removable block devices).")
656 a8083063 Iustin Pop
  sysd_free = []
657 a8083063 Iustin Pop
  sysd_used = []
658 a8083063 Iustin Pop
  for name, size, dev, part, used in sysdisks:
659 a8083063 Iustin Pop
    if used:
660 a8083063 Iustin Pop
      sysd_used.append(name)
661 a8083063 Iustin Pop
    else:
662 a8083063 Iustin Pop
      sysd_free.append(name)
663 a8083063 Iustin Pop
664 a8083063 Iustin Pop
  if not sysd_free:
665 a8083063 Iustin Pop
    raise PrereqError("no free disks found! (%d in-use disks)" %
666 a8083063 Iustin Pop
                      len(sysd_used))
667 a8083063 Iustin Pop
  if options.alldisks:
668 a8083063 Iustin Pop
    disklist = sysd_free
669 a8083063 Iustin Pop
  elif options.disks:
670 a8083063 Iustin Pop
    disklist = options.disks.split(",")
671 a8083063 Iustin Pop
    for name in disklist:
672 a8083063 Iustin Pop
      if name in sysd_used:
673 a8083063 Iustin Pop
        raise ParameterError("disk %s is in use, cannot wipe!" % name)
674 a8083063 Iustin Pop
      if name not in sysd_free:
675 a8083063 Iustin Pop
        raise ParameterError("cannot find disk %s!" % name)
676 a8083063 Iustin Pop
  else:
677 a8083063 Iustin Pop
    raise ParameterError("Please use either --alldisks or --disks!")
678 a8083063 Iustin Pop
679 a8083063 Iustin Pop
  return disklist
680 a8083063 Iustin Pop
681 a8083063 Iustin Pop
def BootStrap():
682 a8083063 Iustin Pop
  """Actual main routine."""
683 a8083063 Iustin Pop
684 a8083063 Iustin Pop
  CheckPrereq()
685 a8083063 Iustin Pop
686 a8083063 Iustin Pop
  options, args = ParseOptions()
687 a8083063 Iustin Pop
  vgname = options.vgname
688 a8083063 Iustin Pop
  command = args.pop(0)
689 a8083063 Iustin Pop
  if command == "diskinfo":
690 a8083063 Iustin Pop
    ShowDiskInfo()
691 a8083063 Iustin Pop
    return
692 a8083063 Iustin Pop
  if command != "create":
693 a8083063 Iustin Pop
    Usage()
694 a8083063 Iustin Pop
695 a8083063 Iustin Pop
  exists, lv_count, vg_size, vg_free = CheckVGExists(vgname)
696 a8083063 Iustin Pop
  if exists:
697 a8083063 Iustin Pop
    raise PrereqError("It seems volume group '%s' already exists:\n"
698 a8083063 Iustin Pop
                      "  LV count: %s, size: %s, free: %s." %
699 a8083063 Iustin Pop
                      (vgname, lv_count, vg_size, vg_free))
700 a8083063 Iustin Pop
701 a8083063 Iustin Pop
702 a8083063 Iustin Pop
  disklist = ValidateDiskList(options)
703 a8083063 Iustin Pop
704 a8083063 Iustin Pop
  for disk in disklist:
705 a8083063 Iustin Pop
    WipeDisk(disk)
706 a8083063 Iustin Pop
    PartitionDisk(disk)
707 a8083063 Iustin Pop
  for disk in disklist:
708 a8083063 Iustin Pop
    CreatePVOnDisk(disk)
709 a8083063 Iustin Pop
  CreateVG(vgname, disklist)
710 a8083063 Iustin Pop
711 a8083063 Iustin Pop
  status, lv_count, size, free = CheckVGExists(vgname)
712 a8083063 Iustin Pop
  if status:
713 a8083063 Iustin Pop
    print "Done! %s: size %s GiB, disks: %s" % (vgname, size,
714 a8083063 Iustin Pop
                                                ",".join(disklist))
715 a8083063 Iustin Pop
  else:
716 a8083063 Iustin Pop
    raise OperationalError("Although everything seemed ok, the volume "
717 a8083063 Iustin Pop
                           "group did not get created.")
718 a8083063 Iustin Pop
719 a8083063 Iustin Pop
720 a8083063 Iustin Pop
def main():
721 a8083063 Iustin Pop
  """application entry point.
722 a8083063 Iustin Pop
723 a8083063 Iustin Pop
  This is just a wrapper over BootStrap, to handle our own exceptions.
724 a8083063 Iustin Pop
  """
725 a8083063 Iustin Pop
726 a8083063 Iustin Pop
  try:
727 a8083063 Iustin Pop
    BootStrap()
728 a8083063 Iustin Pop
  except PrereqError, err:
729 a8083063 Iustin Pop
    print >> sys.stderr, "The prerequisites for running this tool are not met."
730 a8083063 Iustin Pop
    print >> sys.stderr, ("Please make sure you followed all the steps in "
731 a8083063 Iustin Pop
                          "the build document.")
732 a8083063 Iustin Pop
    print >> sys.stderr, "Description: %s" % str(err)
733 a8083063 Iustin Pop
    sys.exit(1)
734 a8083063 Iustin Pop
  except SysconfigError, err:
735 a8083063 Iustin Pop
    print >> sys.stderr, ("This system's configuration seems wrong, at "
736 a8083063 Iustin Pop
                          "least is not what I expect.")
737 a8083063 Iustin Pop
    print >> sys.stderr, ("Please check that the installation didn't fail "
738 a8083063 Iustin Pop
                          "at some step.")
739 a8083063 Iustin Pop
    print >> sys.stderr, "Description: %s" % str(err)
740 a8083063 Iustin Pop
    sys.exit(1)
741 a8083063 Iustin Pop
  except ParameterError, err:
742 a8083063 Iustin Pop
    print >> sys.stderr, ("Some parameters you gave to the program or the "
743 a8083063 Iustin Pop
                          "invocation is wrong. ")
744 a8083063 Iustin Pop
    print >> sys.stderr, "Description: %s" % str(err)
745 a8083063 Iustin Pop
    Usage()
746 a8083063 Iustin Pop
  except OperationalError, err:
747 a8083063 Iustin Pop
    print >> sys.stderr, ("A serious error has happened while modifying "
748 a8083063 Iustin Pop
                          "the system's configuration.")
749 a8083063 Iustin Pop
    print >> sys.stderr, ("Please review the error message below and make "
750 a8083063 Iustin Pop
                          "sure you clean up yourself.")
751 a8083063 Iustin Pop
    print >> sys.stderr, ("It is most likely that the system configuration "
752 a8083063 Iustin Pop
                          "has been partially altered.")
753 a8083063 Iustin Pop
    print >> sys.stderr, str(err)
754 a8083063 Iustin Pop
    sys.exit(1)
755 a8083063 Iustin Pop
  except ProgrammingError, err:
756 a8083063 Iustin Pop
    print >> sys.stderr, ("Internal application error. Please signal this "
757 a8083063 Iustin Pop
                          "to xencluster-team.")
758 a8083063 Iustin Pop
    print >> sys.stderr, "Error description: %s" % str(err)
759 a8083063 Iustin Pop
    sys.exit(1)
760 a8083063 Iustin Pop
  except Error, err:
761 a8083063 Iustin Pop
    print >> sys.stderr, "Unhandled application error: %s" % err
762 a8083063 Iustin Pop
    sys.exit(1)
763 a8083063 Iustin Pop
  except (IOError, OSError), err:
764 a8083063 Iustin Pop
    print >> sys.stderr, "I/O error detected, please report."
765 a8083063 Iustin Pop
    print >> sys.stderr, "Description: %s" % str(err)
766 a8083063 Iustin Pop
    sys.exit(1)
767 a8083063 Iustin Pop
768 a8083063 Iustin Pop
769 a8083063 Iustin Pop
if __name__ == "__main__":
770 a8083063 Iustin Pop
  main()