]> git.ipfire.org Git - ipfire-3.x.git/blame - src/pomona/fsset.py
Added some lines for ext4 on installer.
[ipfire-3.x.git] / src / pomona / fsset.py
CommitLineData
99237823
MT
1#
2# fsset.py: filesystem management
3#
4# Matt Wilson <msw@redhat.com>
5#
6# Copyright 2001-2006 Red Hat, Inc.
7#
8# This software may be freely redistributed under the terms of the GNU
9# library public license.
10#
11# You should have received a copy of the GNU Library 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#
15
16import string
17import isys
18import inutil
19import os
20import resource
21import posix
22import stat
23import errno
24import parted
25import sys
26import struct
6a9a6ae9 27import time
99237823
MT
28import partitioning
29import partedUtils
30import types
69395171 31import math
99237823
MT
32from flags import flags
33
62c1bebc
MT
34import gettext
35_ = lambda x: gettext.ldgettext("pomona", x)
36N_ = lambda x: x
99237823
MT
37
38import logging
39log = logging.getLogger("pomona")
40
41class BadBlocksError(Exception):
082638e9 42 pass
99237823
MT
43
44class SuspendError(Exception):
082638e9 45 pass
99237823
MT
46
47class OldSwapError(Exception):
082638e9 48 pass
99237823 49
69395171
MT
50class ResizeError(Exception):
51 pass
52
99237823
MT
53defaultMountPoints = ['/', '/boot', '/home', '/tmp', '/usr', '/var', '/opt']
54
55fileSystemTypes = {}
56
57def fileSystemTypeGetDefault():
f6099fef
MT
58 if fileSystemTypeGet('ext4').isSupported():
59 return fileSystemTypeGet('ext4')
60 elif fileSystemTypeGet('ext3').isSupported():
082638e9
MT
61 return fileSystemTypeGet('ext3')
62 elif fileSystemTypeGet('ext2').isSupported():
63 return fileSystemTypeGet('ext2')
64 else:
f6099fef 65 raise ValueError, "You have neither ext4, ext3 or ext2 support in your kernel!"
99237823
MT
66
67def fileSystemTypeGet(key):
082638e9 68 return fileSystemTypes[key]
99237823
MT
69
70def fileSystemTypeRegister(klass):
082638e9 71 fileSystemTypes[klass.getName()] = klass
99237823
MT
72
73def fileSystemTypeGetTypes():
082638e9 74 return fileSystemTypes.copy()
99237823
MT
75
76def getUsableLinuxFs():
082638e9
MT
77 rc = []
78 for fsType in fileSystemTypes.keys():
79 if fileSystemTypes[fsType].isMountable() and \
80 fileSystemTypes[fsType].isLinuxNativeFS():
81 rc.append(fsType)
82
83 # make sure the default is first in the list, kind of ugly
84 default = fileSystemTypeGetDefault()
85 defaultName = default.getName()
86 if defaultName in rc:
87 del rc[rc.index(defaultName)]
88 rc.insert(0, defaultName)
89 return rc
99237823
MT
90
91def devify(device):
082638e9
MT
92 if device in ["proc", "devpts", "sysfs", "tmpfs"]:
93 return device
94 elif device == "sys":
95 return "sysfs"
96 elif device == "shm":
97 return "tmpfs"
98 elif device != "none" and device[0] != '/':
99 return "/dev/" + device
100 else:
101 return device
99237823
MT
102
103class LabelFactory:
082638e9
MT
104 def __init__(self):
105 self.labels = None
106
107 def createLabel(self, mountpoint, maxLabelChars):
108 if self.labels == None:
109 self.labels = {}
110 diskset = partedUtils.DiskSet()
111 diskset.openDevices()
112 labels = diskset.getLabels()
113 del diskset
114 self.reserveLabels(labels)
115
116 if len(mountpoint) > maxLabelChars:
117 mountpoint = mountpoint[0:maxLabelChars]
118 count = 0
119 while self.labels.has_key(mountpoint):
120 count = count + 1
121 s = "%s" % count
122 if (len(mountpoint) + len(s)) <= maxLabelChars:
123 mountpoint = mountpoint + s
124 else:
125 strip = len(mountpoint) + len(s) - maxLabelChars
126 mountpoint = mountpoint[0:len(mountpoint) - strip] + s
127 self.labels[mountpoint] = 1
128
129 return mountpoint
130
131 def reserveLabels(self, labels):
132 if self.labels == None:
133 self.labels = {}
134 for device, label in labels.items():
135 self.labels[label] = 1
136
137 def isLabelReserved(self, label):
138 if self.labels == None:
139 return False
140 elif self.labels.has_key(label):
141 return True
142 else:
143 return False
99237823
MT
144
145labelFactory = LabelFactory()
146
147class FileSystemType:
082638e9 148 kernelFilesystems = {}
d593e226
MT
149 lostAndFoundContext = None
150
082638e9
MT
151 def __init__(self):
152 self.deviceArguments = {}
153 self.formattable = 0
154 self.checked = 0
155 self.name = ""
156 self.linuxnativefs = 0
157 self.partedFileSystemType = None
158 self.partedPartitionFlags = []
159 self.maxSizeMB = 8 * 1024 * 1024
160 self.supported = -1
161 self.defaultOptions = "defaults"
162 self.migratetofs = None
163 self.extraFormatArgs = []
164 self.maxLabelChars = 16
d593e226
MT
165 self.resizable = False
166 self.supportsFsProfiles = False
167 self.fsProfileSpecifier = None
168 self.fsprofile = None
169 self.bootable = False
170
171 def createLabel(self, mountpoint, maxLabelChars, kslabel = None):
172 # If a label was specified in the kickstart file, return that as the
173 # label.
174 if kslabel:
175 return kslabel
176
177 if len(mountpoint) > maxLabelChars:
178 return mountpoint[0:maxLabelChars]
179 else:
180 return mountpoint
181
182 def isBootable(self):
183 return self.bootable
184
185 def isResizable(self):
186 return self.resizable
187 def resize(self, entry, size, progress, chroot='/'):
188 pass
189 def getMinimumSize(self, device):
190 log.warning("Unable to determinine minimal size for %s", device)
191 return 1
082638e9
MT
192
193 def isKernelFS(self):
194 """Returns True if this is an in-kernel pseudo-filesystem."""
195 return False
196
197 def mount(self, device, mountpoint, readOnly=0, bindMount=0,
198 instroot=""):
199 if not self.isMountable():
200 return
201 inutil.mkdirChain("%s/%s" %(instroot, mountpoint))
6a9a6ae9
MT
202 log.debug("mounting %s on %s/%s as %s" %(device, instroot,
203 mountpoint, self.getMountName()))
082638e9 204 isys.mount(device, "%s/%s" %(instroot, mountpoint),
6a9a6ae9
MT
205 fstype = self.getMountName(),
206 readOnly = readOnly, bindMount = bindMount,
207 options = self.defaultOptions)
082638e9
MT
208
209 def umount(self, device, path):
210 isys.umount(path, removeDir = 0)
211
212 def getName(self, quoted = 0):
213 """Return the name of the filesystem. Set quoted to 1 if this
214 should be quoted (ie, it's not for display)."""
215 if quoted:
216 if self.name.find(" ") != -1:
217 return "\"%s\"" %(self.name,)
218 return self.name
219
6a9a6ae9
MT
220 def getMountName(self, quoted = 0):
221 return self.getName(quoted)
222
082638e9
MT
223 def registerDeviceArgumentFunction(self, klass, function):
224 self.deviceArguments[klass] = function
225
082638e9
MT
226 def formatDevice(self, entry, progress, chroot='/'):
227 if self.isFormattable():
228 raise RuntimeError, "formatDevice method not defined"
229
230 def migrateFileSystem(self, device, message, chroot='/'):
231 if self.isMigratable():
232 raise RuntimeError, "migrateFileSystem method not defined"
233
234 def labelDevice(self, entry, chroot):
235 pass
236
237 def clobberDevice(self, entry, chroot):
238 pass
239
240 def isFormattable(self):
241 return self.formattable
242
243 def isLinuxNativeFS(self):
244 return self.linuxnativefs
245
d593e226
MT
246 def setFsProfile(self, fsprofile=None):
247 if not self.supportsFsProfiles:
248 raise RuntimeError, "%s does not support profiles" % (self,)
249 self.fsprofile = fsprofile
250
251 def getFsProfileArgs(self):
252 if not self.supportsFsProfiles:
253 raise RuntimeError, "%s does not support profiles" % (self,)
254 args = None
255 if self.fsprofile:
256 args = []
257 if self.fsProfileSpecifier:
258 args.extend(self.fsProfileSpecifier)
259 args.extend(self.fsprofile)
260 return args
261
082638e9
MT
262 def readProcFilesystems(self):
263 f = open("/proc/filesystems", 'r')
264 if not f:
265 pass
266 lines = f.readlines()
267 for line in lines:
268 fields = string.split(line)
269 if fields[0] == "nodev":
270 fsystem = fields[1]
271 else:
272 fsystem = fields[0]
273 FileSystemType.kernelFilesystems[fsystem] = None
274
275 def isMountable(self):
276 if not FileSystemType.kernelFilesystems:
277 self.readProcFilesystems()
278
d593e226 279 return FileSystemType.kernelFilesystems.has_key(self.getMountName()) or self.getName() == "auto"
082638e9
MT
280
281 def isSupported(self):
282 if self.supported == -1:
283 return self.isMountable()
284 return self.supported
285
286 def isChecked(self):
287 return self.checked
288
289 def getDeviceArgs(self, device):
290 deviceArgsFunction = self.deviceArguments.get(device.__class__)
291 if not deviceArgsFunction:
292 return []
293 return deviceArgsFunction(device)
294
295 def getPartedFileSystemType(self):
296 return self.partedFileSystemType
297
298 def getPartedPartitionFlags(self):
299 return self.partedPartitionFlags
300
301 # note that this returns the maximum size of a filesystem in megabytes
302 def getMaxSizeMB(self):
303 return self.maxSizeMB
304
305 def getDefaultOptions(self, mountpoint):
306 return self.defaultOptions
307
308 def getMigratableFSTargets(self):
309 retval = []
310 if not self.migratetofs:
311 return retval
312
313 for fs in self.migratetofs:
314 if fileSystemTypeGet(fs).isSupported():
315 retval.append(fs)
316
317 return retval
318
319 def isMigratable(self):
320 if len(self.getMigratableFSTargets()) > 0:
321 return 1
322 else:
323 return 0
99237823
MT
324
325
326class reiserfsFileSystem(FileSystemType):
082638e9
MT
327 def __init__(self):
328 FileSystemType.__init__(self)
329 self.partedFileSystemType = parted.file_system_type_get("reiserfs")
330 self.formattable = 1
331 self.checked = 1
332 self.linuxnativefs = 1
333 self.supported = -1
334 self.name = "reiserfs"
082638e9
MT
335
336 self.maxSizeMB = 8 * 1024 * 1024
337
338 def formatDevice(self, entry, progress, chroot='/'):
339 devicePath = entry.device.setupDevice(chroot)
340 p = os.pipe()
341 os.write(p[1], "y\n")
342 os.close(p[1])
343
344 rc = inutil.execWithRedirect("mkreiserfs",
d8ea2283
MT
345 [devicePath],
346 stdin = p[0],
347 stdout = "/dev/tty5",
348 stderr = "/dev/tty5", searchPath = 1)
082638e9
MT
349
350 if rc:
351 raise SystemError
352
353 def labelDevice(self, entry, chroot):
354 devicePath = entry.device.setupDevice(chroot)
355 label = labelFactory.createLabel(entry.mountpoint, self.maxLabelChars)
356 rc = inutil.execWithRedirect("reiserfstune",
d8ea2283
MT
357 ["--label", label, devicePath],
358 stdout = "/dev/tty5",
359 stderr = "/dev/tty5", searchPath = 1)
082638e9
MT
360 if rc:
361 raise SystemError
362 entry.setLabel(label)
363
99237823
MT
364fileSystemTypeRegister(reiserfsFileSystem())
365
366class xfsFileSystem(FileSystemType):
082638e9
MT
367 def __init__(self):
368 FileSystemType.__init__(self)
369 self.partedFileSystemType = parted.file_system_type_get("xfs")
370 self.formattable = 1
371 self.checked = 1
372 self.linuxnativefs = 1
373 self.name = "xfs"
374 self.maxSizeMB = 16 * 1024 * 1024
375 self.maxLabelChars = 12
376 self.supported = -1
082638e9
MT
377
378 def formatDevice(self, entry, progress, chroot='/'):
379 devicePath = entry.device.setupDevice(chroot)
380
381 rc = inutil.execWithRedirect("mkfs.xfs",
d8ea2283
MT
382 ["-f", "-l", "internal",
383 "-i", "attr=2", devicePath],
384 stdout = "/dev/tty5",
385 stderr = "/dev/tty5", searchPath = 1)
082638e9
MT
386
387 if rc:
388 raise SystemError
389
390 def labelDevice(self, entry, chroot):
391 devicePath = entry.device.setupDevice(chroot)
392 label = labelFactory.createLabel(entry.mountpoint, self.maxLabelChars)
393 db_cmd = "label " + label
394 rc = inutil.execWithRedirect("xfs_db",
d8ea2283
MT
395 ["-x", "-c", db_cmd, devicePath],
396 stdout = "/dev/tty5",
397 stderr = "/dev/tty5", searchPath = 1)
082638e9
MT
398 if rc:
399 raise SystemError
400 entry.setLabel(label)
401
99237823
MT
402fileSystemTypeRegister(xfsFileSystem())
403
404class extFileSystem(FileSystemType):
082638e9
MT
405 def __init__(self):
406 FileSystemType.__init__(self)
407 self.partedFileSystemType = None
408 self.formattable = 1
409 self.checked = 1
410 self.linuxnativefs = 1
411 self.maxSizeMB = 8 * 1024 * 1024
73fb39f7
MT
412 self.supportsFsProfiles = True
413 self.fsProfileSpecifier = "-T"
414 self.resizable = True
415 self.bootable = True
416
417 def resize(self, entry, size, progress, chroot='/'):
418 devicePath = entry.device.setupDevice(chroot)
419
420 log.info("checking %s prior to resize" %(devicePath,))
421 w = None
422 if progress:
423 w = progress(_("Checking"),
424 _("Checking filesystem on %s...") %(devicePath),
425 100, pulse = True)
426
ec150b24 427 rc = inutil.execWithPulseProgress("e2fsck", ["-f", "-p", "-C", "0", devicePath],
73fb39f7
MT
428 stdout="/tmp/resize.out",
429 stderr="/tmp/resize.out",
430 progress = w)
431 if rc >= 4:
432 raise ResizeError, ("Check of %s failed" %(devicePath,), devicePath)
433 if progress:
434 w.pop()
435 w = progress(_("Resizing"),
436 _("Resizing filesystem on %s...") %(devicePath),
437 100, pulse = True)
438
439 log.info("resizing %s" %(devicePath,))
ec150b24 440 rc = inutil.execWithPulseProgress("resize2fs",
73fb39f7
MT
441 ["-p", devicePath, "%sM" %(size,)],
442 stdout="/tmp/resize.out",
443 stderr="/tmp/resize.out",
444 progress = w)
445 if progress:
446 w.pop()
447 if rc:
448 raise ResizeError, ("Resize of %s failed" %(devicePath,), devicePath)
449
450 def getMinimumSize(self, device):
451 """Return the minimum filesystem size in megabytes"""
452 devicePath = "/dev/%s" % (device,)
453
454 # FIXME: it'd be nice if we didn't have to parse this out ourselves
ec150b24 455 buf = inutil.execWithCapture("dumpe2fs",
73fb39f7
MT
456 ["-h", devicePath],
457 stderr = "/dev/tty5")
458 blocks = free = bs = 0
459 for l in buf.split("\n"):
460 if l.startswith("Free blocks"):
461 try:
462 free = l.split()[2]
463 free = int(free)
464 except Exception, e:
465 log.warning("error determining free blocks on %s: %s" %(devicePath, e))
466 free = 0
467 elif l.startswith("Block size"):
468 try:
469 bs = l.split()[2]
470 bs = int(bs)
471 except Exception, e:
472 log.warning("error determining block size of %s: %s" %(devicePath, e))
473 bs = 0
474 elif l.startswith("Block count"):
475 try:
476 blocks = l.split()[2]
477 blocks = int(blocks)
478 except Exception, e:
479 log.warning("error determining block count of %s: %s" %(devicePath, e))
480 blocks = 0
481
482 if free == 0 or bs == 0:
483 log.warning("Unable to determinine minimal size for %s", devicePath)
484 return 1
485
486 used = math.ceil((blocks - free) * bs / 1024.0 / 1024.0)
487 log.info("used size of %s is %s" %(devicePath, used))
488 # FIXME: should we bump this beyond the absolute minimum?
489 return used
082638e9
MT
490
491 def labelDevice(self, entry, chroot):
492 devicePath = entry.device.setupDevice(chroot)
73fb39f7
MT
493 label = self.createLabel(entry.mountpoint, self.maxLabelChars,
494 kslabel = entry.label)
082638e9 495
ec150b24 496 rc = inutil.execWithRedirect("e2label",
73fb39f7
MT
497 [devicePath, label],
498 stdout = "/dev/tty5",
499 stderr = "/dev/tty5", searchPath = 1)
082638e9
MT
500 if rc:
501 raise SystemError
502 entry.setLabel(label)
503
504 def formatDevice(self, entry, progress, chroot='/'):
505 devicePath = entry.device.setupDevice(chroot)
506 devArgs = self.getDeviceArgs(entry.device)
73fb39f7 507 args = [ "mke2fs", devicePath ]
082638e9 508
73fb39f7
MT
509 fsProfileArgs = self.getFsProfileArgs()
510 if fsProfileArgs:
511 args.extend(fsProfileArgs)
082638e9
MT
512 args.extend(devArgs)
513 args.extend(self.extraFormatArgs)
514
515 log.info("Format command: %s\n" % str(args))
516
517 rc = ext2FormatFilesystem(args, "/dev/tty5",
d8ea2283
MT
518 progress,
519 entry.mountpoint)
082638e9
MT
520 if rc:
521 raise SystemError
522
523 def clobberDevice(self, entry, chroot):
524 device = entry.device.setupDevice(chroot)
525 isys.ext2Clobber(device)
526
527 # this is only for ext3 filesystems, but migration is a method
73fb39f7 528 # of the ext2 fstype, so it needs to be here. FIXME should be moved
082638e9
MT
529 def setExt3Options(self, entry, message, chroot='/'):
530 devicePath = entry.device.setupDevice(chroot)
531
532 # if no journal, don't turn off the fsck
533 if not isys.ext2HasJournal(devicePath):
534 return
535
ec150b24 536 rc = inutil.execWithRedirect("tune2fs",
73fb39f7
MT
537 ["-c0", "-i0",
538 "-ouser_xattr,acl", devicePath],
539 stdout = "/dev/tty5",
540 stderr = "/dev/tty5", searchPath = 1)
99237823
MT
541
542class ext2FileSystem(extFileSystem):
082638e9
MT
543 def __init__(self):
544 extFileSystem.__init__(self)
545 self.name = "ext2"
546 self.partedFileSystemType = parted.file_system_type_get("ext2")
547 self.migratetofs = ['ext3']
548
549 def migrateFileSystem(self, entry, message, chroot='/'):
550 devicePath = entry.device.setupDevice(chroot)
551
552 if not entry.fsystem or not entry.origfsystem:
553 raise RuntimeError, ("Trying to migrate fs w/o fsystem or "
d8ea2283 554 "origfsystem set")
082638e9 555 if entry.fsystem.getName() != "ext3":
73fb39f7
MT
556 raise RuntimeError, ("Trying to migrate ext2 to something other "
557 "than ext3")
082638e9
MT
558
559 # if journal already exists skip
560 if isys.ext2HasJournal(devicePath):
561 log.info("Skipping migration of %s, has a journal already.\n" % devicePath)
562 return
563
ec150b24 564 rc = inutil.execWithRedirect("tune2fs",
73fb39f7
MT
565 ["-j", devicePath ],
566 stdout = "/dev/tty5",
567 stderr = "/dev/tty5", searchPath = 1)
082638e9
MT
568
569 if rc:
570 raise SystemError
571
572 # XXX this should never happen, but appears to have done
573 # so several times based on reports in bugzilla.
574 # At least we can avoid leaving them with a system which won't boot
575 if not isys.ext2HasJournal(devicePath):
576 log.warning("Migration of %s attempted but no journal exists after "
d8ea2283 577 "running tune2fs.\n" % (devicePath))
082638e9
MT
578 if message:
579 rc = message(_("Error"),
73fb39f7
MT
580 _("An error occurred migrating %s to ext3. It is "
581 "possible to continue without migrating this "
582 "file system if desired.\n\n"
583 "Would you like to continue without migrating %s?")
d8ea2283 584 % (devicePath, devicePath), type = "yesno")
082638e9
MT
585 if rc == 0:
586 sys.exit(0)
73fb39f7 587 entry.fsystem = entry.origfsystem
84b042fd
MT
588 else:
589 extFileSystem.setExt3Options(self, entry, message, chroot)
99237823 590
73fb39f7 591
99237823
MT
592fileSystemTypeRegister(ext2FileSystem())
593
594class ext3FileSystem(extFileSystem):
082638e9
MT
595 def __init__(self):
596 extFileSystem.__init__(self)
597 self.name = "ext3"
73fb39f7 598 self.extraFormatArgs = [ "-t", "ext3" ]
082638e9 599 self.partedFileSystemType = parted.file_system_type_get("ext3")
73fb39f7 600 self.migratetofs = ['ext4dev']
99237823 601
082638e9
MT
602 def formatDevice(self, entry, progress, chroot='/'):
603 extFileSystem.formatDevice(self, entry, progress, chroot)
604 extFileSystem.setExt3Options(self, entry, progress, chroot)
99237823 605
73fb39f7
MT
606 def migrateFileSystem(self, entry, message, chroot='/'):
607 devicePath = entry.device.setupDevice(chroot)
608
609 if not entry.fsystem or not entry.origfsystem:
610 raise RuntimeError, ("Trying to migrate fs w/o fsystem or "
611 "origfsystem set")
612 if entry.fsystem.getName() != "ext4dev":
613 raise RuntimeError, ("Trying to migrate ext3 to something other "
614 "than ext4")
615
616 # This is only needed as long as ext4 is actually "ext4dev"
ec150b24 617 rc = inutil.execWithRedirect("tune2fs",
73fb39f7
MT
618 ["-E", "test_fs", devicePath ],
619 stdout = "/dev/tty5",
620 stderr = "/dev/tty5", searchPath = 1)
621 if rc:
622 raise SystemError
623
99237823
MT
624fileSystemTypeRegister(ext3FileSystem())
625
73fb39f7
MT
626class ext4FileSystem(extFileSystem):
627 def __init__(self):
628 extFileSystem.__init__(self)
f6099fef 629 self.name = "ext4"
73fb39f7 630 self.partedFileSystemType = parted.file_system_type_get("ext3")
f6099fef 631 self.extraFormatArgs = [ "-t", "ext4" ]
73fb39f7
MT
632 self.bootable = False
633
634 def formatDevice(self, entry, progress, chroot='/'):
635 extFileSystem.formatDevice(self, entry, progress, chroot)
636 extFileSystem.setExt3Options(self, entry, progress, chroot)
637
638fileSystemTypeRegister(ext4FileSystem())
639
99237823 640class swapFileSystem(FileSystemType):
082638e9
MT
641 enabledSwaps = {}
642
643 def __init__(self):
644 FileSystemType.__init__(self)
645 self.partedFileSystemType = parted.file_system_type_get("linux-swap")
646 self.formattable = 1
647 self.name = "swap"
648 self.maxSizeMB = 8 * 1024 * 1024
649 self.linuxnativefs = 1
650 self.supported = 1
651 self.maxLabelChars = 15
652
653 def mount(self, device, mountpoint, readOnly=0, bindMount=0, instroot = None):
654 pagesize = resource.getpagesize()
655 buf = None
656 if pagesize > 2048:
657 num = pagesize
658 else:
659 num = 2048
660 try:
661 fd = os.open(device, os.O_RDONLY)
662 buf = os.read(fd, num)
663 except:
664 pass
665 finally:
666 try:
667 os.close(fd)
668 except:
669 pass
670
671 if buf is not None and len(buf) == pagesize:
672 sig = buf[pagesize - 10:]
673 if sig == 'SWAP-SPACE':
674 raise OldSwapError
675 if sig == 'S1SUSPEND\x00' or sig == 'S2SUSPEND\x00':
676 raise SuspendError
677
678 isys.swapon(device)
679
680 def umount(self, device, path):
681 # unfortunately, turning off swap is bad.
682 raise RuntimeError, "unable to turn off swap"
683
684 def formatDevice(self, entry, progress, chroot='/'):
685 file = entry.device.setupDevice(chroot)
686 rc = inutil.execWithRedirect("mkswap",
d8ea2283
MT
687 ["-v1", file],
688 stdout = "/dev/tty5",
689 stderr = "/dev/tty5",
690 searchPath = 1)
082638e9
MT
691 if rc:
692 raise SystemError
693
694 def labelDevice(self, entry, chroot):
695 file = entry.device.setupDevice(chroot)
696 devName = entry.device.getDevice()
697 # we'll keep the SWAP-* naming for all devs but Compaq SMART2
698 # nodes (#176074)
699 if devName[0:6] == "cciss/":
700 swapLabel = "SW-%s" % (devName)
701 elif devName.startswith("mapper/"):
702 swapLabel = "SWAP-%s" % (devName[7:],)
703 else:
704 swapLabel = "SWAP-%s" % (devName)
705 label = labelFactory.createLabel(swapLabel, self.maxLabelChars)
706 rc = inutil.execWithRedirect("mkswap",
d8ea2283
MT
707 ["-v1", "-L", label, file],
708 stdout = "/dev/tty5",
709 stderr = "/dev/tty5",
710 searchPath = 1)
082638e9
MT
711 if rc:
712 raise SystemError
713 entry.setLabel(label)
714
715 def clobberDevice(self, entry, chroot):
716 pagesize = resource.getpagesize()
717 dev = entry.device.setupDevice(chroot)
718 try:
719 fd = os.open(dev, os.O_RDWR)
720 buf = "\0x00" * pagesize
721 os.write(fd, buf)
722 except:
723 pass
724 finally:
725 try:
726 os.close(fd)
727 except:
728 pass
99237823
MT
729
730fileSystemTypeRegister(swapFileSystem())
731
732class FATFileSystem(FileSystemType):
082638e9
MT
733 def __init__(self):
734 FileSystemType.__init__(self)
735 self.partedFileSystemType = parted.file_system_type_get("fat32")
84b042fd 736 self.formattable = 0
082638e9
MT
737 self.checked = 0
738 self.maxSizeMB = 1024 * 1024
739 self.name = "vfat"
082638e9 740
99237823
MT
741fileSystemTypeRegister(FATFileSystem())
742
743class NTFSFileSystem(FileSystemType):
082638e9
MT
744 def __init__(self):
745 FileSystemType.__init__(self)
746 self.partedFileSystemType = parted.file_system_type_get("ntfs")
747 self.formattable = 0
748 self.checked = 0
749 self.name = "ntfs"
99237823
MT
750
751fileSystemTypeRegister(NTFSFileSystem())
752
753class ForeignFileSystem(FileSystemType):
082638e9
MT
754 def __init__(self):
755 FileSystemType.__init__(self)
756 self.formattable = 0
757 self.checked = 0
758 self.name = "foreign"
99237823 759
082638e9
MT
760 def formatDevice(self, entry, progress, chroot='/'):
761 return
99237823
MT
762
763fileSystemTypeRegister(ForeignFileSystem())
764
765class PsudoFileSystem(FileSystemType):
082638e9
MT
766 def __init__(self, name):
767 FileSystemType.__init__(self)
768 self.formattable = 0
769 self.checked = 0
770 self.name = name
771 self.supported = 0
99237823 772
082638e9
MT
773 def isKernelFS(self):
774 return True
99237823
MT
775
776class ProcFileSystem(PsudoFileSystem):
082638e9
MT
777 def __init__(self):
778 PsudoFileSystem.__init__(self, "proc")
99237823
MT
779
780fileSystemTypeRegister(ProcFileSystem())
781
782class SysfsFileSystem(PsudoFileSystem):
082638e9
MT
783 def __init__(self):
784 PsudoFileSystem.__init__(self, "sysfs")
99237823
MT
785
786fileSystemTypeRegister(SysfsFileSystem())
787
788class DevptsFileSystem(PsudoFileSystem):
082638e9
MT
789 def __init__(self):
790 PsudoFileSystem.__init__(self, "devpts")
791 self.defaultOptions = "gid=5,mode=620"
99237823 792
082638e9
MT
793 def isMountable(self):
794 return 0
99237823
MT
795
796fileSystemTypeRegister(DevptsFileSystem())
797
798class DevshmFileSystem(PsudoFileSystem):
082638e9
MT
799 def __init__(self):
800 PsudoFileSystem.__init__(self, "tmpfs")
801
802 def isMountable(self):
803 return 0
99237823 804
99237823
MT
805fileSystemTypeRegister(DevshmFileSystem())
806
807class AutoFileSystem(PsudoFileSystem):
082638e9
MT
808 def __init__(self):
809 PsudoFileSystem.__init__(self, "auto")
810
811 def mount(self, device, mountpoint, readOnly=0, bindMount=0, instroot = None):
812 errNum = 0
813 errMsg = "cannot mount auto filesystem on %s of this type" % device
814
815 if not self.isMountable():
816 return
817 inutil.mkdirChain("%s/%s" %(instroot, mountpoint))
082638e9
MT
818 for fs in getFStoTry (device):
819 try:
820 isys.mount (device, mountpoint, fstype = fs, readOnly = readOnly,
821 bindMount = bindMount)
822 return
823 except SystemError, (num, msg):
824 errNum = num
825 errMsg = msg
826 continue
827
828 raise SystemError (errNum, errMsg)
829
830 def umount(self, device, path):
831 isys.umount(path, removeDir = 0)
99237823
MT
832
833fileSystemTypeRegister(AutoFileSystem())
834
835class BindFileSystem(PsudoFileSystem):
082638e9
MT
836 def __init__(self):
837 PsudoFileSystem.__init__(self, "bind")
838
839 def isMountable(self):
840 return 1
99237823 841
99237823
MT
842fileSystemTypeRegister(BindFileSystem())
843
844class FileSystemSet:
082638e9
MT
845 def __init__(self):
846 self.messageWindow = None
847 self.progressWindow = None
848 self.waitWindow = None
849 self.mountcount = 0
850 self.migratedfs = 0
851 self.reset()
852 self.volumesCreated = 0
853
854 def isActive(self):
855 return self.mountcount != 0
856
857 def registerMessageWindow(self, method):
858 self.messageWindow = method
859
860 def registerProgressWindow(self, method):
861 self.progressWindow = method
862
863 def registerWaitWindow(self, method):
864 self.waitWindow = method
865
866 def reset (self):
867 self.entries = []
868 proc = FileSystemSetEntry(Device(device="proc"), '/proc',
869 fileSystemTypeGet("proc"))
870 self.add(proc)
871 sys = FileSystemSetEntry(Device(device="sys"), '/sys',
872 fileSystemTypeGet("sysfs"))
873 self.add(sys)
874 pts = FileSystemSetEntry(Device(device="devpts"), '/dev/pts',
875 fileSystemTypeGet("devpts"), "gid=5,mode=620")
876 self.add(pts)
877 shm = FileSystemSetEntry(Device(device="shm"), '/dev/shm',
878 fileSystemTypeGet("tmpfs"))
879 self.add(shm)
880
881 def verify (self):
882 for entry in self.entries:
883 if type(entry.__dict__) != type({}):
884 raise RuntimeError, "fsset internals inconsistent"
885
886 def add (self, newEntry):
887 # Should object A be sorted after object B? Take mountpoints and
888 # device names into account so bind mounts are sorted correctly.
889 def comesAfter(a, b):
890 mntA = a.mountpoint
891 mntB = b.mountpoint
892 devA = a.device.getDevice()
893 devB = b.device.getDevice()
894
895 if not mntB or not devB:
896 return True
897 if not mntA or not devA:
898 return False
899
900 if (mntA.startswith(mntB) and mntA != mntB) or (devA.startswith(mntB) and devA != devB):
901 return True
902 else:
903 return False
904
905 # Remove preexisting duplicate entries - pseudo filesystems are
906 # duplicate if they have the same filesystem type as an existing one.
907 # Otherwise, they have to have the same device and mount point
908 # (required to check for bind mounts).
909 for existing in self.entries:
910 if (isinstance (newEntry.fsystem, PsudoFileSystem) and existing.fsystem.getName() == newEntry.fsystem.getName()) or (existing.device.getDevice() == newEntry.device.getDevice() and existing.mountpoint == newEntry.mountpoint):
911 self.remove(existing)
912
913 ### debuggin'
914 #log.info ("fsset at %s\n"
d8ea2283
MT
915 # "adding entry for %s\n"
916 # "entry object %s, class __dict__ is %s",
917 # self, entry.mountpoint, entry,
918 # isys.printObject(entry.__dict__))
082638e9
MT
919
920 insertAt = 0
921
922 # Special case for /.
923 if newEntry.mountpoint == "/":
924 self.entries.insert(insertAt, newEntry)
925 return
926
927 # doesn't matter where these get added, so just put them at the end
928 if not newEntry.mountpoint or not newEntry.mountpoint.startswith("/") or self.entries == []:
929 self.entries.append(newEntry)
930 return
931
932 for entry in self.entries:
933 if comesAfter(newEntry, entry):
934 insertAt = self.entries.index(entry)+1
935
936 self.entries.insert(insertAt, newEntry)
937
938 def remove (self, entry):
939 self.entries.remove(entry)
940
941 def getEntryByMountPoint(self, mount):
942 for entry in self.entries:
943 if entry.mountpoint == mount:
944 return entry
945 return None
946
947 def getEntryByDeviceName(self, dev):
948 for entry in self.entries:
949 if entry.device.getDevice() == dev:
950 return entry
951 return None
952
953 def copy(self):
954 new = FileSystemSet()
955 for entry in self.entries:
956 new.add(entry)
957 return new
958
6a9a6ae9 959 def fstab (self):
082638e9 960 format = "%-23s %-23s %-7s %-15s %d %d\n"
6a9a6ae9
MT
961 fstab = """
962#
963# /etc/fstab
964# Created by pomona on %s
965#
966# Accessible filesystems, by reference, are maintained under '/dev/disk'
967# See man pages fstab(5), findfs(8), mount(8) and/or vol_id(8) for more info
968#
969""" % time.asctime()
970
082638e9
MT
971 for entry in self.entries:
972 if entry.mountpoint:
6a9a6ae9
MT
973 if entry.getUuid() and entry.device.doLabel is not None:
974 device = "UUID=%s" %(entry.getUuid(),)
975 elif entry.getLabel() and entry.device.doLabel is not None:
082638e9
MT
976 device = "LABEL=%s" % (entry.getLabel(),)
977 else:
978 device = devify(entry.device.getDevice())
979 fstab = fstab + entry.device.getComment()
980 fstab = fstab + format % (device, entry.mountpoint,
6a9a6ae9
MT
981 entry.fsystem.getMountName(),
982 entry.getOptions(), entry.fsck,
d8ea2283 983 entry.order)
082638e9
MT
984 return fstab
985
986 def mtab(self):
987 format = "%s %s %s %s 0 0\n"
988 mtab = ""
989 for entry in self.entries:
990 if not entry.isMounted():
991 continue
992 if entry.mountpoint:
993 # swap doesn't end up in the mtab
994 if entry.fsystem.getName() == "swap":
995 continue
996 if entry.options:
997 options = "rw," + entry.options
998 else:
999 options = "rw"
1000 mtab = mtab + format % (devify(entry.device.getDevice()),
d8ea2283
MT
1001 entry.mountpoint,
1002 entry.fsystem.getName(),
1003 options)
082638e9
MT
1004 return mtab
1005
1006
1007 def write(self, prefix):
1008 f = open(prefix + "/etc/fstab", "w")
1009 f.write(self.fstab())
1010 f.close()
1011
1012 # touch mtab
1013 open(prefix + "/etc/mtab", "w+")
1014 f.close()
1015
1016 ## XXX
1017 def mkDevRoot(self, instPath):
1018 root = self.getEntryByMountPoint("/")
1019 dev = "%s/dev/%s" % (instPath, root.device.getDevice())
1020 rdev = os.stat(dev).st_rdev
1021
1022 #if not os.path.exists("%s/dev/root" %(instPath,)):
1023 # os.mknod("%s/dev/root" % (instPath,), stat.S_IFBLK | 0600, rdev)
1024
1025 # return the "boot" device
1026 def getBootDev(self):
1027 mntDict = {}
1028 bootDev = None
1029 for entry in self.entries:
1030 mntDict[entry.mountpoint] = entry.device
1031
1032 if mntDict.has_key("/boot"):
1033 bootDev = mntDict['/boot']
1034 elif mntDict.has_key("/"):
1035 bootDev = mntDict['/']
1036
1037 return bootDev
1038
1039 def bootloaderChoices(self, diskSet, bl):
1040 ret = {}
1041 bootDev = self.getBootDev()
1042
1043 if bootDev is None:
1044 log.warning("no boot device set")
1045 return ret
1046
1047 ret['boot'] = (bootDev.device, N_("First sector of boot partition"))
1048 ret['mbr'] = (bl.drivelist[0], N_("Master Boot Record (MBR)"))
1049 return ret
1050
1051 # set active partition on disks
1052 # if an active partition is set, leave it alone; if none set
1053 # set either our boot partition or the first partition on the drive active
1054 def setActive(self, diskset):
1055 dev = self.getBootDev()
1056
1057 if dev is None:
1058 return
1059
1060 bootDev = dev.device
1061
1062 for drive in diskset.disks.keys():
1063 foundActive = 0
1064 bootPart = None
1065 disk = diskset.disks[drive]
1066 part = disk.next_partition()
1067 while part:
1068 if not part.is_active():
1069 part = disk.next_partition(part)
1070 continue
1071
1072 if not part.is_flag_available(parted.PARTITION_BOOT):
1073 foundActive = 1
1074 part = None
1075 continue
1076
1077 if part.get_flag(parted.PARTITION_BOOT):
1078 foundActive = 1
1079 part = None
1080 continue
1081
1082 if not bootPart:
1083 bootPart = part
1084
1085 if partedUtils.get_partition_name(part) == bootDev:
1086 bootPart = part
1087
1088 part = disk.next_partition(part)
1089
1090 if bootPart and not foundActive:
1091 bootPart.set_flag(parted.PARTITION_BOOT, 1)
1092
1093 if bootPart:
1094 del bootPart
1095
1096 def formatSwap(self, chroot, forceFormat=False):
1097 formatted = []
1098 notformatted = []
1099
1100 for entry in self.entries:
1101 if (not entry.fsystem or not entry.fsystem.getName() == "swap" or
1102 entry.isMounted()):
1103 continue
1104 if not entry.getFormat():
1105 if not forceFormat:
1106 notformatted.append(entry)
1107 continue
1108 try:
1109 self.formatEntry(entry, chroot)
1110 formatted.append(entry)
1111 except SystemError:
1112 if self.messageWindow:
1113 self.messageWindow(_("Error"),
d8ea2283
MT
1114 _("An error occurred trying to "
1115 "initialize swap on device %s. This "
1116 "problem is serious, and the install "
1117 "cannot continue.\n\n"
1118 "Press <Enter> to reboot your system.")
1119 % (entry.device.getDevice(),))
082638e9
MT
1120 sys.exit(0)
1121
1122 for entry in formatted:
1123 try:
1124 self.labelEntry(entry, chroot)
1125 except SystemError:
1126 # should be OK, fall back to by device
1127 pass
1128
1129 # find if there's a label on the ones we're not formatting
1130 for entry in notformatted:
1131 dev = entry.device.getDevice()
1132 if not dev or dev == "none":
1133 continue
1134 try:
1135 label = isys.readFSLabel(dev)
1136 except:
1137 continue
1138 if label:
1139 entry.setLabel(label)
1140
1141 def turnOnSwap(self, chroot, upgrading=False):
1142 def swapErrorDialog (msg, format_button_text, entry):
1143 buttons = [_("Skip"), format_button_text, _("Reboot")]
1144 ret = self.messageWindow(_("Error"), msg, type="custom",
1145 custom_buttons=buttons,
1146 custom_icon="warning")
1147 if ret == 0:
1148 self.entries.remove(entry)
1149 elif ret == 1:
1150 self.formatEntry(entry, chroot)
1151 entry.mount(chroot)
1152 self.mountcount = self.mountcount + 1
1153 else:
1154 sys.exit(0)
1155
1156 for entry in self.entries:
1157 if (entry.fsystem and entry.fsystem.getName() == "swap"
1158 and not entry.isMounted()):
1159 try:
1160 entry.mount(chroot)
1161 self.mountcount = self.mountcount + 1
1162 except OldSwapError:
1163 if self.messageWindow:
1164 msg = _("The swap device:\n\n /dev/%s\n\n"
d8ea2283
MT
1165 "is a version 0 Linux swap partition. If you "
1166 "want to use this device, you must reformat as "
1167 "a version 1 Linux swap partition. If you skip "
1168 "it, the installer will ignore it during the "
1169 "installation.") % (entry.device.getDevice())
082638e9
MT
1170
1171 swapErrorDialog(msg, _("Reformat"), entry)
1172 except SuspendError:
1173 if self.messageWindow:
1174 if upgrading:
1175 msg = _("The swap device:\n\n /dev/%s\n\n"
d8ea2283
MT
1176 "in your /etc/fstab file is currently in "
1177 "use as a software suspend partition, "
1178 "which means your system is hibernating. "
1179 "To perform an upgrade, please shut down "
1180 "your system rather than hibernating it.") \
1181 % (entry.device.getDevice())
082638e9
MT
1182 else:
1183 msg = _("The swap device:\n\n /dev/%s\n\n"
d8ea2283
MT
1184 "in your /etc/fstab file is currently in "
1185 "use as a software suspend partition, "
1186 "which means your system is hibernating. "
1187 "If you are performing a new install, "
1188 "make sure the installer is set "
1189 "to format all swap partitions.") \
1190 % (entry.device.getDevice())
082638e9
MT
1191
1192 # choose your own adventure swap partitions...
1193 msg = msg + _("\n\nChoose Skip if you want the "
d8ea2283
MT
1194 "installer to ignore this partition during "
1195 "the upgrade. Choose Format to reformat "
1196 "the partition as swap space. Choose Reboot "
1197 "to restart the system.")
082638e9
MT
1198
1199 swapErrorDialog(msg, _("Format"), entry)
1200 else:
1201 sys.exit(0)
1202
1203 except SystemError, (num, msg):
1204 if self.messageWindow:
1205 if upgrading:
1206 self.messageWindow(_("Error"),
d8ea2283
MT
1207 _("Error enabling swap device "
1208 "%s: %s\n\n"
1209 "The /etc/fstab on your "
1210 "upgrade partition does not "
1211 "reference a valid swap "
1212 "partition.\n\n"
1213 "Press OK to reboot your "
1214 "system.")
1215 % (entry.device.getDevice(), msg))
082638e9
MT
1216 else:
1217 self.messageWindow(_("Error"),
d8ea2283
MT
1218 _("Error enabling swap device "
1219 "%s: %s\n\n"
1220 "This most likely means this "
1221 "swap partition has not been "
1222 "initialized.\n\n"
1223 "Press OK to reboot your "
1224 "system.")
1225 % (entry.device.getDevice(), msg))
082638e9
MT
1226 sys.exit(0)
1227
1228 def labelEntry(self, entry, chroot):
1229 label = entry.device.getLabel()
1230 if label:
1231 entry.setLabel(label)
1232 if labelFactory.isLabelReserved(label):
1233 entry.device.doLabel = 1
1234 if entry.device.doLabel is not None:
1235 entry.fsystem.labelDevice(entry, chroot)
1236
1237 def formatEntry(self, entry, chroot):
1238 if entry.mountpoint:
1239 log.info("formatting %s as %s" %(entry.mountpoint, entry.fsystem.name))
1240 entry.fsystem.clobberDevice(entry, chroot)
1241 entry.fsystem.formatDevice(entry, self.progressWindow, chroot)
1242
1243 def badblocksEntry(self, entry, chroot):
1244 entry.fsystem.badblocksDevice(entry, self.progressWindow, chroot)
1245
1246 def getMigratableEntries(self):
1247 retval = []
1248 for entry in self.entries:
1249 if entry.origfsystem and entry.origfsystem.isMigratable():
1250 retval.append(entry)
1251
1252 return retval
1253
1254 def formattablePartitions(self):
1255 list = []
1256 for entry in self.entries:
1257 if entry.fsystem.isFormattable():
1258 list.append (entry)
1259 return list
1260
1261 def checkBadblocks(self, chroot='/'):
1262 for entry in self.entries:
1263 if (not entry.fsystem.isFormattable() or not entry.getBadblocks()
1264 or entry.isMounted()):
1265 continue
1266 try:
1267 self.badblocksEntry(entry, chroot)
1268 except BadBlocksError:
1269 log.error("Bad blocks detected on device %s",entry.device.getDevice())
1270 if self.messageWindow:
1271 self.messageWindow(_("Error"),
d8ea2283
MT
1272 _("Bad blocks have been detected on "
1273 "device /dev/%s. We do "
1274 "not recommend you use this device."
1275 "\n\n"
1276 "Press <Enter> to reboot your system")
1277 % (entry.device.getDevice(),))
082638e9
MT
1278 sys.exit(0)
1279
1280 except SystemError:
1281 if self.messageWindow:
1282 self.messageWindow(_("Error"),
d8ea2283
MT
1283 _("An error occurred searching for "
1284 "bad blocks on %s. This problem is "
1285 "serious, and the install cannot "
1286 "continue.\n\n"
1287 "Press <Enter> to reboot your system.")
1288 % (entry.device.getDevice(),))
082638e9
MT
1289 sys.exit(0)
1290
1291 def makeFilesystems(self, chroot='/'):
1292 formatted = []
1293 notformatted = []
1294 for entry in self.entries:
1295 if (not entry.fsystem.isFormattable() or not entry.getFormat()
1296 or entry.isMounted()):
1297 notformatted.append(entry)
1298 continue
1299 try:
1300 self.formatEntry(entry, chroot)
1301 formatted.append(entry)
1302 except SystemError:
1303 if self.messageWindow:
1304 self.messageWindow(_("Error"),
d8ea2283
MT
1305 _("An error occurred trying to "
1306 "format %s. This problem is "
1307 "serious, and the install cannot "
1308 "continue.\n\n"
1309 "Press <Enter> to reboot your system.")
1310 % (entry.device.getDevice(),))
082638e9
MT
1311 sys.exit(0)
1312
1313 for entry in formatted:
1314 try:
1315 self.labelEntry(entry, chroot)
1316 except SystemError:
1317 # should be OK, we'll still use the device name to mount.
1318 pass
1319
1320 # go through and have labels for the ones we don't format
1321 for entry in notformatted:
1322 dev = entry.device.getDevice()
1323 if not dev or dev == "none":
1324 continue
1325 if not entry.mountpoint or entry.mountpoint == "swap":
1326 continue
1327 try:
1328 label = isys.readFSLabel(dev)
1329 except:
1330 continue
1331 if label:
1332 entry.setLabel(label)
1333 else:
1334 self.labelEntry(entry, chroot)
1335
1336 def haveMigratedFilesystems(self):
1337 return self.migratedfs
1338
1339 def migrateFilesystems(self, chroot='/'):
1340 if self.migratedfs:
1341 return
1342
1343 for entry in self.entries:
1344 if not entry.origfsystem:
1345 continue
1346
1347 if not entry.origfsystem.isMigratable() or not entry.getMigrate():
1348 continue
1349 try:
1350 entry.origfsystem.migrateFileSystem(entry, self.messageWindow, chroot)
1351 except SystemError:
1352 if self.messageWindow:
1353 self.messageWindow(_("Error"),
d8ea2283
MT
1354 _("An error occurred trying to "
1355 "migrate %s. This problem is "
1356 "serious, and the install cannot "
1357 "continue.\n\n"
1358 "Press <Enter> to reboot your system.")
1359 % (entry.device.getDevice(),))
082638e9
MT
1360 sys.exit(0)
1361
1362 self.migratedfs = 1
1363
1364 def mountFilesystems(self, pomona, raiseErrors = 0, readOnly = 0):
1365 #protected = pomona.method.protectedPartitions()
1366 protected = []
1367
1368 for entry in self.entries:
1369 # Don't try to mount a protected partition, since it will already
1370 # have been mounted as the installation source.
1371 if not entry.fsystem.isMountable() or (protected and entry.device.getDevice() in protected):
1372 continue
1373
1374 try:
1375 log.info("trying to mount %s on %s" %(entry.device.getDevice(), entry.mountpoint))
1376 entry.mount(pomona.rootPath, readOnly = readOnly)
1377 self.mountcount = self.mountcount + 1
1378 except OSError, (num, msg):
1379 if self.messageWindow:
1380 if num == errno.EEXIST:
1381 self.messageWindow(_("Invalid mount point"),
d8ea2283
MT
1382 _("An error occurred when trying "
1383 "to create %s. Some element of "
1384 "this path is not a directory. "
1385 "This is a fatal error and the "
1386 "install cannot continue.\n\n"
1387 "Press <Enter> to reboot your "
1388 "system.") % (entry.mountpoint,))
082638e9
MT
1389 else:
1390 self.messageWindow(_("Invalid mount point"),
d8ea2283
MT
1391 _("An error occurred when trying "
1392 "to create %s: %s. This is "
1393 "a fatal error and the install "
1394 "cannot continue.\n\n"
1395 "Press <Enter> to reboot your "
1396 "system.") % (entry.mountpoint, msg))
082638e9
MT
1397 sys.exit(0)
1398 except SystemError, (num, msg):
1399 if raiseErrors:
1400 raise SystemError, (num, msg)
1401
1402 if self.messageWindow:
1403 if not entry.fsystem.isLinuxNativeFS():
1404 ret = self.messageWindow(_("Unable to mount filesystem"),
d8ea2283
MT
1405 _("An error occurred mounting "
1406 "device %s as %s. You may "
1407 "continue installation, but "
1408 "there may be problems.")
1409 % (entry.device.getDevice(),
1410 entry.mountpoint),
1411 type="custom", custom_icon="warning",
1412 custom_buttons=[_("_Reboot"), _("_Continue")])
082638e9
MT
1413
1414 if ret == 0:
1415 sys.exit(0)
1416 else:
1417 continue
1418 else:
1419 if pomona.id.getUpgrade() and not entry.getLabel():
1420 errStr = _("Error mounting device %s as %s: "
d8ea2283
MT
1421 "%s\n\n"
1422 "Devices in /etc/fstab should be "
1423 "specified by label, not by device name."
1424 "\n\n"
1425 "Press OK to reboot your system.") % (entry.device.getDevice(), entry.mountpoint, msg)
082638e9
MT
1426 else:
1427 errStr = _("Error mounting device %s as %s: "
d8ea2283
MT
1428 "%s\n\n"
1429 "This most likely means this "
1430 "partition has not been formatted."
1431 "\n\n"
1432 "Press OK to reboot your system.") % (entry.device.getDevice(), entry.mountpoint, msg)
082638e9
MT
1433
1434 self.messageWindow(_("Error"), errStr)
1435
1436 sys.exit(0)
1437
1438 def filesystemSpace(self, chroot='/'):
1439 space = []
1440 for entry in self.entries:
1441 if not entry.isMounted():
1442 continue
1443 # we can't put swap files on swap partitions; that's nonsense
1444 if entry.mountpoint == "swap":
1445 continue
1446 path = "%s/%s" % (chroot, entry.mountpoint)
1447 try:
69395171 1448 space.append((entry.mountpoint, isys.pathSpaceAvailable(path)))
082638e9
MT
1449 except SystemError:
1450 log.error("failed to get space available in filesystemSpace() for %s" %(entry.mountpoint,))
1451
1452 def spaceSort(a, b):
1453 (m1, s1) = a
1454 (m2, s2) = b
1455
1456 if (s1 > s2):
1457 return -1
1458 elif s1 < s2:
1459 return 1
1460 return 0
1461
1462 space.sort(spaceSort)
1463 return space
1464
1465 def hasDirtyFilesystems(self, mountpoint):
1466 ret = []
1467
1468 for entry in self.entries:
1469 # XXX - multifsify, virtualize isdirty per fstype
1470 if entry.fsystem.getName() != "ext2": continue
1471 if entry.getFormat(): continue
1472 if isinstance(entry.device.getDevice(), BindMountDevice): continue
1473
1474 try:
1475 if isys.ext2IsDirty(entry.device.getDevice()):
1476 log.info("%s is a dirty ext2 partition" % entry.device.getDevice())
1477 ret.append(entry.device.getDevice())
1478 except Exception, e:
1479 log.error("got an exception checking %s for being dirty, hoping it's not" %(entry.device.getDevice(),))
1480
1481 return ret
1482
1483 def umountFilesystems(self, instPath, ignoreErrors = 0, swapoff = True):
1484 # XXX remove special case
1485 try:
1486 isys.umount(instPath + '/proc/bus/usb', removeDir = 0)
1487 log.info("Umount USB OK")
1488 except:
d8ea2283 1489# log.error("Umount USB Fail")
082638e9
MT
1490 pass
1491
1492 # take a slice so we don't modify self.entries
1493 reverse = self.entries[:]
1494 reverse.reverse()
1495
1496 for entry in reverse:
1497 if entry.mountpoint == "swap" and not swapoff:
1498 continue
1499 entry.umount(instPath)
99237823
MT
1500
1501class FileSystemSetEntry:
082638e9 1502 def __init__ (self, device, mountpoint,
d8ea2283
MT
1503 fsystem=None, options=None,
1504 origfsystem=None, migrate=0,
1505 order=-1, fsck=-1, format=0,
69395171 1506 badblocks = 0, bytesPerInode=4096, fsprofile=None):
082638e9
MT
1507 if not fsystem:
1508 fsystem = fileSystemTypeGet("ext2")
1509 self.device = device
1510 self.mountpoint = mountpoint
1511 self.fsystem = fsystem
1512 self.origfsystem = origfsystem
1513 self.migrate = migrate
1514 if options:
1515 self.options = options
1516 else:
1517 self.options = fsystem.getDefaultOptions(mountpoint)
1518 self.options += device.getDeviceOptions()
1519 self.mountcount = 0
1520 self.label = None
1521 if fsck == -1:
1522 self.fsck = fsystem.isChecked()
1523 else:
1524 self.fsck = fsck
1525 if order == -1:
1526 if mountpoint == '/':
1527 self.order = 1
1528 elif self.fsck:
1529 self.order = 2
1530 else:
1531 self.order = 0
1532 else:
1533 self.order = order
1534 if format and not fsystem.isFormattable():
1535 raise RuntimeError, ("file system type %s is not formattable, "
d8ea2283
MT
1536 "but has been added to fsset with format "
1537 "flag on" % fsystem.getName())
082638e9
MT
1538 self.format = format
1539 self.badblocks = badblocks
1540 self.bytesPerInode = bytesPerInode
69395171 1541 self.fsprofile = fsprofile
082638e9
MT
1542
1543 def mount(self, chroot='/', devPrefix='/dev', readOnly = 0):
1544 device = self.device.setupDevice(chroot, devPrefix=devPrefix)
1545
1546 # FIXME: we really should migrate before turnOnFilesystems.
1547 # but it's too late now
1548 if (self.migrate == 1) and (self.origfsystem is not None):
1549 self.origfsystem.mount(device, "%s" % (self.mountpoint,),
d8ea2283
MT
1550 readOnly = readOnly,
1551 bindMount = isinstance(self.device,
1552 BindMountDevice),
1553 instroot = chroot)
082638e9
MT
1554 else:
1555 self.fsystem.mount(device, "%s" % (self.mountpoint,),
d8ea2283
MT
1556 readOnly = readOnly,
1557 bindMount = isinstance(self.device,
1558 BindMountDevice),
1559 instroot = chroot)
082638e9
MT
1560
1561 self.mountcount = self.mountcount + 1
1562
1563 def umount(self, chroot='/'):
1564 if self.mountcount > 0:
1565 try:
1566 self.fsystem.umount(self.device, "%s/%s" % (chroot, self.mountpoint))
1567 self.mountcount = self.mountcount - 1
1568 except RuntimeError:
1569 pass
1570
1571 def setFileSystemType(self, fstype):
1572 self.fsystem = fstype
1573
1574 def setBadblocks(self, state):
1575 self.badblocks = state
1576
1577 def getBadblocks(self):
1578 return self.badblocks
1579
1580 def getMountPoint(self):
1581 return self.mountpoint
1582
6a9a6ae9
MT
1583 def getOptions(self):
1584 options = self.options
1585 if not options:
1586 options = self.fsystem.getDefaultOptions(self.mountpoint)
1587 return options + self.device.getDeviceOptions()
1588
082638e9
MT
1589 def setFormat (self, state):
1590 if self.migrate and state:
1591 raise ValueError, "Trying to set format bit on when migrate is set!"
1592 self.format = state
1593
1594 def getFormat (self):
1595 return self.format
1596
1597 def setMigrate (self, state):
1598 if self.format and state:
1599 raise ValueError, "Trying to set migrate bit on when format is set!"
1600 self.migrate = state
1601
1602 def getMigrate (self):
1603 return self.migrate
1604
1605 def isMounted (self):
1606 return self.mountcount > 0
1607
1608 def getLabel (self):
1609 return self.label
1610
6a9a6ae9
MT
1611 def getUuid (self):
1612 return isys.readFSUuid(self.device.getDevice())
1613
082638e9
MT
1614 def setLabel (self, label):
1615 self.label = label
1616
1617 def __str__(self):
1618 if not self.mountpoint:
1619 mntpt = "None"
1620 else:
1621 mntpt = self.mountpoint
1622
1623 str = ("fsentry -- device: %(device)s mountpoint: %(mountpoint)s\n"
d8ea2283
MT
1624 " fsystem: %(fsystem)s format: %(format)s\n"
1625 " ismounted: %(mounted)s options: '%(options)s'\n"
6a9a6ae9
MT
1626 " label: %(label)s fsprofile: %(fsprofile)s\n"%
1627 {"device": self.device.getDevice(), "mountpoint": mntpt,
1628 "fsystem": self.fsystem.getName(), "format": self.format,
1629 "mounted": self.mountcount, "options": self.getOptions(),
1630 "label": self.label, "fsprofile": self.fsprofile})
082638e9
MT
1631 return str
1632
99237823
MT
1633
1634class Device:
082638e9
MT
1635 def __init__(self, device = "none"):
1636 self.device = device
1637 self.label = None
1638 self.isSetup = 0
1639 self.doLabel = 1
1640 self.deviceOptions = ""
99237823 1641
082638e9
MT
1642 def getComment (self):
1643 return ""
99237823 1644
082638e9
MT
1645 def getDevice (self, asBoot = 0):
1646 return self.device
99237823 1647
082638e9
MT
1648 def setupDevice (self, chroot='/', devPrefix='/dev'):
1649 return self.device
99237823 1650
082638e9
MT
1651 def cleanupDevice (self, chroot, devPrefix='/dev'):
1652 pass
99237823 1653
082638e9
MT
1654 def solidify (self):
1655 pass
99237823 1656
082638e9
MT
1657 def getName(self):
1658 return self.__class__.__name__
99237823 1659
082638e9
MT
1660 def getLabel(self):
1661 try:
69395171 1662 return isys.readFSLabel(self.setupDevice())
082638e9
MT
1663 except:
1664 return ""
99237823 1665
082638e9
MT
1666 def setAsNetdev(self):
1667 """Ensure we're set up so that _netdev is in our device options."""
1668 if "_netdev" not in self.deviceOptions:
1669 self.deviceOptions += ",_netdev"
99237823 1670
082638e9
MT
1671 def isNetdev(self):
1672 """Check to see if we're set as a netdev"""
1673 if "_netdev" in self.deviceOptions:
1674 return True
1675 return False
99237823 1676
082638e9
MT
1677 def getDeviceOptions(self):
1678 return self.deviceOptions
99237823
MT
1679
1680class DevDevice(Device):
082638e9
MT
1681 """ Device with a device node rooted in /dev that we just always use
1682 the pre-created device node for."""
1683 def __init__(self, dev):
1684 Device.__init__(self)
1685 self.device = dev
99237823 1686
082638e9
MT
1687 def getDevice(self, asBoot = 0):
1688 return self.device
99237823 1689
082638e9
MT
1690 def setupDevice(self, chroot='/', devPrefix='/dev'):
1691 return "/dev/%s" %(self.getDevice(),)
99237823
MT
1692
1693
1694ext2 = fileSystemTypeGet("ext2")
1695
1696class PartitionDevice(Device):
082638e9
MT
1697 def __init__(self, partition):
1698 Device.__init__(self)
1699 if type(partition) != types.StringType:
1700 raise ValueError, "partition must be a string"
1701 self.device = partition
99237823 1702
082638e9
MT
1703 def setupDevice(self, chroot="/", devPrefix='/dev'):
1704 path = '%s/%s' % (devPrefix, self.getDevice(),)
1705 return path
99237823
MT
1706
1707class PartedPartitionDevice(PartitionDevice):
082638e9
MT
1708 def __init__(self, partition):
1709 Device.__init__(self)
1710 self.device = None
1711 self.partition = partition
1712
1713 def getDevice(self, asBoot = 0):
1714 if not self.partition:
1715 return self.device
1716
1717 return partedUtils.get_partition_name(self.partition)
1718
1719 def solidify(self):
1720 # drop reference on the parted partition object and note
1721 # the current minor number allocation
1722 self.device = self.getDevice()
1723 self.partition = None
99237823
MT
1724
1725class BindMountDevice(Device):
082638e9
MT
1726 def __init__(self, directory):
1727 Device.__init__(self)
1728 self.device = directory
99237823 1729
082638e9
MT
1730 def setupDevice(self, chroot="/", devPrefix="/tmp"):
1731 return chroot + self.device
99237823
MT
1732
1733class SwapFileDevice(Device):
082638e9
MT
1734 def __init__(self, file):
1735 Device.__init__(self)
1736 self.device = file
1737 self.size = 0
1738
1739 def setSize (self, size):
1740 self.size = size
1741
1742 def setupDevice (self, chroot="/", devPrefix='/tmp'):
1743 file = os.path.normpath(chroot + self.getDevice())
1744 if not os.access(file, os.R_OK):
1745 if self.size:
1746 # make sure the permissions are set properly
1747 fd = os.open(file, os.O_CREAT, 0600)
1748 os.close(fd)
1749 isys.ddfile(file, self.size, None)
1750 else:
1751 raise SystemError, (0, "swap file creation necessary, but "
d8ea2283 1752 "required size is unknown.")
082638e9 1753 return file
99237823
MT
1754
1755# This is a device that describes a swap file that is sitting on
1756# the loopback filesystem host for partitionless installs.
1757# The piggypath is the place where the loopback file host filesystem
1758# will be mounted
1759class PiggybackSwapFileDevice(SwapFileDevice):
082638e9
MT
1760 def __init__(self, piggypath, file):
1761 SwapFileDevice.__init__(self, file)
1762 self.piggypath = piggypath
1763
1764 def setupDevice(self, chroot="/", devPrefix='/tmp'):
1765 return SwapFileDevice.setupDevice(self, self.piggypath, devPrefix)
99237823
MT
1766
1767class LoopbackDevice(Device):
082638e9
MT
1768 def __init__(self, hostPartition, hostFs):
1769 Device.__init__(self)
1770 self.host = "/dev/" + hostPartition
1771 self.hostfs = hostFs
1772 self.device = "loop1"
1773
1774 def setupDevice(self, chroot="/", devPrefix='/tmp/'):
1775 if not self.isSetup:
1776 isys.mount(self.host[5:], "/mnt/loophost", fstype = "vfat")
1777 self.device = allocateLoopback("/mnt/loophost/redhat.img")
1778 if not self.device:
1779 raise SystemError, "Unable to allocate loopback device"
1780 self.isSetup = 1
1781 path = '%s/%s' % (devPrefix, self.getDevice())
1782 else:
1783 path = '%s/%s' % (devPrefix, self.getDevice())
1784 #isys.makeDevInode(self.getDevice(), path)
1785 path = os.path.normpath(path)
1786 return path
1787
1788 def getComment (self):
1789 return "# LOOP1: %s %s /redhat.img\n" % (self.host, self.hostfs)
99237823
MT
1790
1791def makeDevice(dev):
082638e9
MT
1792 device = DevDevice(dev)
1793 return device
99237823
MT
1794
1795def readFstab(pomona):
082638e9
MT
1796 path = pomona.rootPath + '/etc/fstab'
1797 intf = pomona.intf
1798 fsset = FileSystemSet()
1799
1800 # first, we look at all the disks on the systems and get any ext2/3
1801 # labels off of the filesystem.
1802 # temporary, to get the labels
1803 diskset = partedUtils.DiskSet(pomona)
1804 diskset.openDevices()
1805 labels = diskset.getLabels()
1806
1807 labelToDevice = {}
1808 for device, label in labels.items():
1809 if not labelToDevice.has_key(label):
1810 labelToDevice[label] = device
1811 elif intf is not None:
1812 try:
1813 intf.messageWindow(_("Duplicate Labels"),
d8ea2283
MT
1814 _("Multiple devices on your system are "
1815 "labelled %s. Labels across devices must be "
1816 "unique for your system to function "
1817 "properly.\n\n"
1818 "Please fix this problem and restart the "
1819 "installation process.")
1820 % (label,), type="custom", custom_icon="error",
1821 custom_buttons=[_("_Reboot")])
082638e9
MT
1822 except TypeError:
1823 intf.messageWindow(_("Invalid Label"),
d8ea2283
MT
1824 _("An invalid label was found on device "
1825 "%s. Please fix this problem and restart "
1826 "the installation process.")
1827 % (device,), type="custom", custom_icon="error",
1828 custom_buttons=[_("_Reboot")])
082638e9
MT
1829
1830 sys.exit(0)
1831 else:
1832 log.warning("Duplicate labels for %s, but no intf so trying "
d8ea2283 1833 "to continue" % (label,))
082638e9
MT
1834
1835 # mark these labels found on the system as used so the factory
1836 # doesn't give them to another device
1837 labelFactory.reserveLabels(labels)
1838
1839 loopIndex = {}
1840
1841 f = open (path, "r")
1842 lines = f.readlines ()
1843 f.close()
1844
1845 for line in lines:
1846 fields = string.split(line)
1847
1848 if not fields: continue
1849
1850 if line[0] == "#":
1851 # skip all comments
1852 continue
1853
1854 # all valid fstab entries have 6 fields; if the last two are missing
1855 # they are assumed to be zero per fstab(5)
1856 if len(fields) < 4:
1857 continue
1858 elif len(fields) == 4:
1859 fields.append(0)
1860 fields.append(0)
1861 elif len(fields) == 5:
1862 fields.append(0)
1863 elif len(fields) > 6:
1864 continue
1865
1866 if string.find(fields[3], "noauto") != -1: continue
1867
1868 # shenanigans to handle ext3,ext2 format in fstab
1869 fstotry = fields[2]
1870 if fstotry.find(","):
1871 fstotry = fstotry.split(",")
1872 else:
1873 fstotry = [ fstotry ]
1874 fsystem = None
1875 for fs in fstotry:
1876 # if we don't support mounting the filesystem, continue
1877 if not fileSystemTypes.has_key(fs):
1878 continue
1879 fsystem = fileSystemTypeGet(fs)
1880 break
1881 # "none" is valid as an fs type for bind mounts (#151458)
1882 if fsystem is None and (string.find(fields[3], "bind") == -1):
1883 continue
1884 label = None
1885 if fields[0] == "none":
1886 device = Device()
1887 elif ((string.find(fields[3], "bind") != -1) and fields[0].startswith("/")):
1888 # it's a bind mount, they're Weird (tm)
1889 device = BindMountDevice(fields[0])
1890 fsystem = fileSystemTypeGet("bind")
1891 elif len(fields) >= 6 and fields[0].startswith('LABEL='):
1892 label = fields[0][6:]
1893 if labelToDevice.has_key(label):
1894 device = makeDevice(labelToDevice[label])
1895 else:
1896 log.warning ("fstab file has LABEL=%s, but this label "
d8ea2283 1897 "could not be found on any file system", label)
082638e9
MT
1898 # bad luck, skip this entry.
1899 continue
1900 elif fields[2] == "swap" and not fields[0].startswith('/dev/'):
1901 # swap files
1902 file = fields[0]
1903 if file.startswith('/initrd/loopfs/'):
1904 file = file[14:]
1905 device = PiggybackSwapFileDevice("/mnt/loophost", file)
1906 else:
1907 device = SwapFileDevice(file)
1908 elif fields[0].startswith('/dev/loop'):
1909 # look up this loop device in the index to find the
1910 # partition that houses the filesystem image
1911 # XXX currently we assume /dev/loop1
1912 if loopIndex.has_key(device):
1913 (dev, fs) = loopIndex[device]
1914 device = LoopbackDevice(dev, fs)
1915 elif fields[0].startswith('/dev/'):
1916 device = makeDevice(fields[0][5:])
1917 else:
1918 device = Device(device = fields[0])
1919
1920 # if they have a filesystem being mounted as auto, we need
1921 # to sniff around a bit to figure out what it might be
1922 # if we fail at all, though, just ignore it
1923 if fsystem == "auto" and device.getDevice() != "none":
1924 try:
1925 tmp = partedUtils.sniffFilesystemType("/dev/%s" %(device.setupDevice(),))
1926 if tmp is not None:
1927 fsystem = tmp
1928 except:
1929 pass
1930
1931 entry = FileSystemSetEntry(device, fields[1], fsystem, fields[3],
d8ea2283 1932 origfsystem=fsystem)
082638e9
MT
1933 if label:
1934 entry.setLabel(label)
1935 fsset.add(entry)
1936 return fsset
99237823
MT
1937
1938def getDevFD(device):
082638e9
MT
1939 try:
1940 fd = os.open(device, os.O_RDONLY)
1941 except:
1942 file = '/dev/' + device
1943 try:
1944 fd = os.open(file, os.O_RDONLY)
1945 except:
1946 return -1
1947 return fd
99237823
MT
1948
1949def isValidExt2(device):
082638e9
MT
1950 fd = getDevFD(device)
1951 if fd == -1:
1952 return 0
99237823 1953
082638e9
MT
1954 buf = os.read(fd, 2048)
1955 os.close(fd)
99237823 1956
082638e9
MT
1957 if len(buf) != 2048:
1958 return 0
99237823 1959
082638e9
MT
1960 if struct.unpack("<H", buf[1080:1082]) == (0xef53,):
1961 return 1
99237823 1962
082638e9 1963 return 0
99237823
MT
1964
1965def isValidXFS(device):
082638e9
MT
1966 fd = getDevFD(device)
1967 if fd == -1:
1968 return 0
1969
1970 buf = os.read(fd, 4)
1971 os.close(fd)
1972
1973 if len(buf) != 4:
1974 return 0
1975
1976 if buf == "XFSB":
1977 return 1
1978
1979 return 0
99237823
MT
1980
1981def isValidReiserFS(device):
082638e9
MT
1982 fd = getDevFD(device)
1983 if fd == -1:
1984 return 0
1985
1986 '''
1987 ** reiserfs 3.5.x super block begins at offset 8K
1988 ** reiserfs 3.6.x super block begins at offset 64K
1989 All versions have a magic value of "ReIsEr" at
1990 offset 0x34 from start of super block
1991 '''
1992 reiserMagicVal = "ReIsEr"
1993 reiserMagicOffset = 0x34
1994 reiserSBStart = [64*1024, 8*1024]
1995 bufSize = 0x40 # just large enough to include the magic value
1996 for SBOffset in reiserSBStart:
1997 try:
1998 os.lseek(fd, SBOffset, 0)
1999 buf = os.read(fd, bufSize)
2000 except:
2001 buf = ""
2002
2003 if len(buf) < bufSize:
2004 continue
2005
2006 if (buf[reiserMagicOffset:reiserMagicOffset+len(reiserMagicVal)] == reiserMagicVal):
2007 os.close(fd)
2008 return 1
2009
2010 os.close(fd)
2011 return 0
99237823
MT
2012
2013# this will return a list of types of filesystems which device
2014# looks like it could be to try mounting as
2015def getFStoTry(device):
082638e9 2016 rc = []
99237823 2017
082638e9
MT
2018 if isValidXFS(device):
2019 rc.append("xfs")
99237823 2020
082638e9
MT
2021 if isValidReiserFS(device):
2022 rc.append("reiserfs")
99237823 2023
082638e9
MT
2024 if isValidExt2(device):
2025 if isys.ext2HasJournal(device):
2026 rc.append("ext3")
2027 rc.append("ext2")
99237823
MT
2028
2029 ### XXX FIXME: need to check for swap
2030
082638e9 2031 return rc
99237823
MT
2032
2033def allocateLoopback(file):
082638e9
MT
2034 found = 1
2035 for i in range(8):
2036 dev = "loop%d" % (i,)
2037 path = "/dev/loop%d" % (i,)
2038 try:
2039 isys.losetup(path, file)
2040 found = 1
2041 except SystemError:
2042 continue
2043 break
2044 if found:
2045 return dev
2046 return None
99237823
MT
2047
2048def ext2FormatFilesystem(argList, messageFile, windowCreator, mntpoint):
082638e9
MT
2049 if windowCreator:
2050 w = windowCreator(_("Formatting"),
d8ea2283 2051 _("Formatting %s file system...") % (mntpoint,), 100)
082638e9
MT
2052 else:
2053 w = None
2054
2055 fd = os.open(messageFile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
2056 p = os.pipe()
2057 childpid = os.fork()
2058 if not childpid:
2059 os.close(p[0])
2060 os.dup2(p[1], 1)
2061 os.dup2(fd, 2)
2062 os.close(p[1])
2063 os.close(fd)
2064 os.execvp(argList[0], argList)
2065 log.critical("failed to exec %s", argList)
2066 os._exit(1)
2067
2068 os.close(p[1])
2069
2070 # ignoring SIGCHLD would be cleaner then ignoring EINTR, but
2071 # we can't use signal() in this thread?
2072
2073 s = 'a'
2074 while s and s != '\b':
2075 try:
2076 s = os.read(p[0], 1)
2077 except OSError, args:
2078 (num, str) = args
2079 if (num != 4):
2080 raise IOError, args
2081
2082 os.write(fd, s)
2083
2084 num = ''
2085 while s:
2086 try:
2087 s = os.read(p[0], 1)
2088 os.write(fd, s)
2089
2090 if s != '\b':
2091 try:
2092 num = num + s
2093 except:
2094 pass
2095 else:
2096 if num and len(num):
2097 l = string.split(num, '/')
2098 try:
2099 val = (int(l[0]) * 100) / int(l[1])
2100 except (IndexError, TypeError):
2101 pass
2102 else:
2103 w and w.set(val)
2104 num = ''
2105 except OSError, args:
2106 (errno, str) = args
2107 if (errno != 4):
2108 raise IOError, args
2109
2110 try:
2111 (pid, status) = os.waitpid(childpid, 0)
2112 except OSError, (num, msg):
2113 log.critical("exception from waitpid while formatting: %s %s" %(num, msg))
2114 status = None
2115 os.close(fd)
2116
2117 w and w.pop()
2118
2119 # *shrug* no clue why this would happen, but hope that things are fine
2120 if status is None:
2121 return 0
2122
2123 if os.WIFEXITED(status) and (os.WEXITSTATUS(status) == 0):
2124 return 0
2125
2126 return 1
99237823
MT
2127
2128# copy and paste job from booty/bootloaderInfo.py...
2129def getDiskPart(dev):
082638e9
MT
2130 cut = len(dev)
2131 if (dev.startswith('rd/') or dev.startswith('ida/') or
2132 dev.startswith('cciss/') or dev.startswith('sx8/') or
2133 dev.startswith('mapper/')):
2134 if dev[-2] == 'p':
2135 cut = -1
2136 elif dev[-3] == 'p':
2137 cut = -2
2138 else:
2139 if dev[-2] in string.digits:
2140 cut = -2
2141 elif dev[-1] in string.digits:
2142 cut = -1
2143
2144 name = dev[:cut]
2145
2146 # hack off the trailing 'p' from /dev/cciss/*, for example
2147 if name[-1] == 'p':
2148 for letter in name:
2149 if letter not in string.letters and letter != "/":
2150 name = name[:-1]
2151 break
2152
2153 if cut < 0:
2154 partNum = int(dev[cut:]) - 1
2155 else:
2156 partNum = None
2157
2158 return (name, partNum)