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