]>
git.ipfire.org Git - ipfire-3.x.git/blob - src/pomona/fsset.py
2 # fsset.py: filesystem management
4 # Matt Wilson <msw@redhat.com>
6 # Copyright 2001-2006 Red Hat, Inc.
8 # This software may be freely redistributed under the terms of the GNU
9 # library public license.
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.
32 from flags
import flags
35 _
= lambda x
: gettext
.ldgettext("pomona", x
)
39 log
= logging
.getLogger("pomona")
41 class BadBlocksError(Exception):
44 class SuspendError(Exception):
47 class OldSwapError(Exception):
50 class ResizeError(Exception):
53 defaultMountPoints
= ['/', '/boot', '/home', '/tmp', '/usr', '/var', '/opt']
57 def fileSystemTypeGetDefault():
58 if fileSystemTypeGet('ext4').isSupported():
59 return fileSystemTypeGet('ext4')
60 elif fileSystemTypeGet('ext3').isSupported():
61 return fileSystemTypeGet('ext3')
62 elif fileSystemTypeGet('ext2').isSupported():
63 return fileSystemTypeGet('ext2')
65 raise ValueError, "You have neither ext4, ext3 or ext2 support in your kernel!"
67 def fileSystemTypeGet(key
):
68 return fileSystemTypes
[key
]
70 def fileSystemTypeRegister(klass
):
71 fileSystemTypes
[klass
.getName()] = klass
73 def fileSystemTypeGetTypes():
74 return fileSystemTypes
.copy()
76 def getUsableLinuxFs():
78 for fsType
in fileSystemTypes
.keys():
79 if fileSystemTypes
[fsType
].isMountable() and \
80 fileSystemTypes
[fsType
].isLinuxNativeFS():
83 # make sure the default is first in the list, kind of ugly
84 default
= fileSystemTypeGetDefault()
85 defaultName
= default
.getName()
87 del rc
[rc
.index(defaultName
)]
88 rc
.insert(0, defaultName
)
92 if device
in ["proc", "devpts", "sysfs", "tmpfs"]:
98 elif device
!= "none" and device
[0] != '/':
99 return "/dev/" + device
107 def createLabel(self
, mountpoint
, maxLabelChars
):
108 if self
.labels
== None:
110 diskset
= partedUtils
.DiskSet()
111 diskset
.openDevices()
112 labels
= diskset
.getLabels()
114 self
.reserveLabels(labels
)
116 if len(mountpoint
) > maxLabelChars
:
117 mountpoint
= mountpoint
[0:maxLabelChars
]
119 while self
.labels
.has_key(mountpoint
):
122 if (len(mountpoint
) + len(s
)) <= maxLabelChars
:
123 mountpoint
= mountpoint
+ s
125 strip
= len(mountpoint
) + len(s
) - maxLabelChars
126 mountpoint
= mountpoint
[0:len(mountpoint
) - strip
] + s
127 self
.labels
[mountpoint
] = 1
131 def reserveLabels(self
, labels
):
132 if self
.labels
== None:
134 for device
, label
in labels
.items():
135 self
.labels
[label
] = 1
137 def isLabelReserved(self
, label
):
138 if self
.labels
== None:
140 elif self
.labels
.has_key(label
):
145 labelFactory
= LabelFactory()
147 class FileSystemType
:
148 kernelFilesystems
= {}
149 lostAndFoundContext
= None
152 self
.deviceArguments
= {}
156 self
.linuxnativefs
= 0
157 self
.partedFileSystemType
= None
158 self
.partedPartitionFlags
= []
159 self
.maxSizeMB
= 8 * 1024 * 1024
161 self
.defaultOptions
= "defaults"
162 self
.migratetofs
= None
163 self
.extraFormatArgs
= []
164 self
.maxLabelChars
= 16
165 self
.resizable
= False
166 self
.supportsFsProfiles
= False
167 self
.fsProfileSpecifier
= None
168 self
.fsprofile
= None
169 self
.bootable
= False
171 def createLabel(self
, mountpoint
, maxLabelChars
, kslabel
= None):
172 # If a label was specified in the kickstart file, return that as the
177 if len(mountpoint
) > maxLabelChars
:
178 return mountpoint
[0:maxLabelChars
]
182 def isBootable(self
):
185 def isResizable(self
):
186 return self
.resizable
187 def resize(self
, entry
, size
, progress
, chroot
='/'):
189 def getMinimumSize(self
, device
):
190 log
.warning("Unable to determinine minimal size for %s", device
)
193 def isKernelFS(self
):
194 """Returns True if this is an in-kernel pseudo-filesystem."""
197 def mount(self
, device
, mountpoint
, readOnly
=0, bindMount
=0,
199 if not self
.isMountable():
201 inutil
.mkdirChain("%s/%s" %(instroot
, mountpoint
))
202 log
.debug("mounting %s on %s/%s as %s" %(device
, instroot
,
203 mountpoint
, self
.getMountName()))
204 isys
.mount(device
, "%s/%s" %(instroot
, mountpoint
),
205 fstype
= self
.getMountName(),
206 readOnly
= readOnly
, bindMount
= bindMount
,
207 options
= self
.defaultOptions
)
209 def umount(self
, device
, path
):
210 isys
.umount(path
, removeDir
= 0)
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)."""
216 if self
.name
.find(" ") != -1:
217 return "\"%s\"" %(self
.name
,)
220 def getMountName(self
, quoted
= 0):
221 return self
.getName(quoted
)
223 def registerDeviceArgumentFunction(self
, klass
, function
):
224 self
.deviceArguments
[klass
] = function
226 def formatDevice(self
, entry
, progress
, chroot
='/'):
227 if self
.isFormattable():
228 raise RuntimeError, "formatDevice method not defined"
230 def migrateFileSystem(self
, device
, message
, chroot
='/'):
231 if self
.isMigratable():
232 raise RuntimeError, "migrateFileSystem method not defined"
234 def labelDevice(self
, entry
, chroot
):
237 def clobberDevice(self
, entry
, chroot
):
240 def isFormattable(self
):
241 return self
.formattable
243 def isLinuxNativeFS(self
):
244 return self
.linuxnativefs
246 def setFsProfile(self
, fsprofile
=None):
247 if not self
.supportsFsProfiles
:
248 raise RuntimeError, "%s does not support profiles" % (self
,)
249 self
.fsprofile
= fsprofile
251 def getFsProfileArgs(self
):
252 if not self
.supportsFsProfiles
:
253 raise RuntimeError, "%s does not support profiles" % (self
,)
257 if self
.fsProfileSpecifier
:
258 args
.extend(self
.fsProfileSpecifier
)
259 args
.extend(self
.fsprofile
)
262 def readProcFilesystems(self
):
263 f
= open("/proc/filesystems", 'r')
266 lines
= f
.readlines()
268 fields
= string
.split(line
)
269 if fields
[0] == "nodev":
273 FileSystemType
.kernelFilesystems
[fsystem
] = None
275 def isMountable(self
):
276 if not FileSystemType
.kernelFilesystems
:
277 self
.readProcFilesystems()
279 return FileSystemType
.kernelFilesystems
.has_key(self
.getMountName()) or self
.getName() == "auto"
281 def isSupported(self
):
282 if self
.supported
== -1:
283 return self
.isMountable()
284 return self
.supported
289 def getDeviceArgs(self
, device
):
290 deviceArgsFunction
= self
.deviceArguments
.get(device
.__class
__)
291 if not deviceArgsFunction
:
293 return deviceArgsFunction(device
)
295 def getPartedFileSystemType(self
):
296 return self
.partedFileSystemType
298 def getPartedPartitionFlags(self
):
299 return self
.partedPartitionFlags
301 # note that this returns the maximum size of a filesystem in megabytes
302 def getMaxSizeMB(self
):
303 return self
.maxSizeMB
305 def getDefaultOptions(self
, mountpoint
):
306 return self
.defaultOptions
308 def getMigratableFSTargets(self
):
310 if not self
.migratetofs
:
313 for fs
in self
.migratetofs
:
314 if fileSystemTypeGet(fs
).isSupported():
319 def isMigratable(self
):
320 if len(self
.getMigratableFSTargets()) > 0:
326 class reiserfsFileSystem(FileSystemType
):
328 FileSystemType
.__init
__(self
)
329 self
.partedFileSystemType
= parted
.file_system_type_get("reiserfs")
332 self
.linuxnativefs
= 1
334 self
.name
= "reiserfs"
336 self
.maxSizeMB
= 8 * 1024 * 1024
338 def formatDevice(self
, entry
, progress
, chroot
='/'):
339 devicePath
= entry
.device
.setupDevice(chroot
)
341 os
.write(p
[1], "y\n")
344 rc
= inutil
.execWithRedirect("mkreiserfs",
347 stdout
= "/dev/tty5",
348 stderr
= "/dev/tty5", searchPath
= 1)
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",
357 ["--label", label
, devicePath
],
358 stdout
= "/dev/tty5",
359 stderr
= "/dev/tty5", searchPath
= 1)
362 entry
.setLabel(label
)
364 fileSystemTypeRegister(reiserfsFileSystem())
366 class xfsFileSystem(FileSystemType
):
368 FileSystemType
.__init
__(self
)
369 self
.partedFileSystemType
= parted
.file_system_type_get("xfs")
372 self
.linuxnativefs
= 1
374 self
.maxSizeMB
= 16 * 1024 * 1024
375 self
.maxLabelChars
= 12
378 def formatDevice(self
, entry
, progress
, chroot
='/'):
379 devicePath
= entry
.device
.setupDevice(chroot
)
381 rc
= inutil
.execWithRedirect("mkfs.xfs",
382 ["-f", "-l", "internal",
383 "-i", "attr=2", devicePath
],
384 stdout
= "/dev/tty5",
385 stderr
= "/dev/tty5", searchPath
= 1)
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",
395 ["-x", "-c", db_cmd
, devicePath
],
396 stdout
= "/dev/tty5",
397 stderr
= "/dev/tty5", searchPath
= 1)
400 entry
.setLabel(label
)
402 fileSystemTypeRegister(xfsFileSystem())
404 class extFileSystem(FileSystemType
):
406 FileSystemType
.__init
__(self
)
407 self
.partedFileSystemType
= None
410 self
.linuxnativefs
= 1
411 self
.maxSizeMB
= 8 * 1024 * 1024
412 self
.supportsFsProfiles
= True
413 self
.fsProfileSpecifier
= "-T"
414 self
.resizable
= True
417 def resize(self
, entry
, size
, progress
, chroot
='/'):
418 devicePath
= entry
.device
.setupDevice(chroot
)
420 log
.info("checking %s prior to resize" %(devicePath
,))
423 w
= progress(_("Checking"),
424 _("Checking filesystem on %s...") %(devicePath),
427 rc
= inutil
.execWithPulseProgress("e2fsck", ["-f", "-p", "-C", "0", devicePath
],
428 stdout
="/tmp/resize.out",
429 stderr
="/tmp/resize.out",
432 raise ResizeError
, ("Check of %s failed" %(devicePath
,), devicePath
)
435 w
= progress(_("Resizing"),
436 _("Resizing filesystem on %s...") %(devicePath),
439 log
.info("resizing %s" %(devicePath
,))
440 rc
= inutil
.execWithPulseProgress("resize2fs",
441 ["-p", devicePath
, "%sM" %(size
,)],
442 stdout
="/tmp/resize.out",
443 stderr
="/tmp/resize.out",
448 raise ResizeError
, ("Resize of %s failed" %(devicePath
,), devicePath
)
450 def getMinimumSize(self
, device
):
451 """Return the minimum filesystem size in megabytes"""
452 devicePath
= "/dev/%s" % (device
,)
454 # FIXME: it'd be nice if we didn't have to parse this out ourselves
455 buf
= inutil
.execWithCapture("dumpe2fs",
457 stderr
= "/dev/tty5")
458 blocks
= free
= bs
= 0
459 for l
in buf
.split("\n"):
460 if l
.startswith("Free blocks"):
465 log
.warning("error determining free blocks on %s: %s" %(devicePath
, e
))
467 elif l
.startswith("Block size"):
472 log
.warning("error determining block size of %s: %s" %(devicePath
, e
))
474 elif l
.startswith("Block count"):
476 blocks
= l
.split()[2]
479 log
.warning("error determining block count of %s: %s" %(devicePath
, e
))
482 if free
== 0 or bs
== 0:
483 log
.warning("Unable to determinine minimal size for %s", devicePath
)
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?
491 def labelDevice(self
, entry
, chroot
):
492 devicePath
= entry
.device
.setupDevice(chroot
)
493 label
= self
.createLabel(entry
.mountpoint
, self
.maxLabelChars
,
494 kslabel
= entry
.label
)
496 rc
= inutil
.execWithRedirect("e2label",
498 stdout
= "/dev/tty5",
499 stderr
= "/dev/tty5", searchPath
= 1)
502 entry
.setLabel(label
)
504 def formatDevice(self
, entry
, progress
, chroot
='/'):
505 devicePath
= entry
.device
.setupDevice(chroot
)
506 devArgs
= self
.getDeviceArgs(entry
.device
)
507 args
= [ "mke2fs", devicePath
]
509 fsProfileArgs
= self
.getFsProfileArgs()
511 args
.extend(fsProfileArgs
)
513 args
.extend(self
.extraFormatArgs
)
515 log
.info("Format command: %s\n" % str(args
))
517 rc
= ext2FormatFilesystem(args
, "/dev/tty5",
523 def clobberDevice(self
, entry
, chroot
):
524 device
= entry
.device
.setupDevice(chroot
)
525 isys
.ext2Clobber(device
)
527 # this is only for ext3 filesystems, but migration is a method
528 # of the ext2 fstype, so it needs to be here. FIXME should be moved
529 def setExt3Options(self
, entry
, message
, chroot
='/'):
530 devicePath
= entry
.device
.setupDevice(chroot
)
532 # if no journal, don't turn off the fsck
533 if not isys
.ext2HasJournal(devicePath
):
536 rc
= inutil
.execWithRedirect("tune2fs",
538 "-ouser_xattr,acl", devicePath
],
539 stdout
= "/dev/tty5",
540 stderr
= "/dev/tty5", searchPath
= 1)
542 class ext2FileSystem(extFileSystem
):
544 extFileSystem
.__init
__(self
)
546 self
.partedFileSystemType
= parted
.file_system_type_get("ext2")
547 self
.migratetofs
= ['ext3']
549 def migrateFileSystem(self
, entry
, message
, chroot
='/'):
550 devicePath
= entry
.device
.setupDevice(chroot
)
552 if not entry
.fsystem
or not entry
.origfsystem
:
553 raise RuntimeError, ("Trying to migrate fs w/o fsystem or "
555 if entry
.fsystem
.getName() != "ext3":
556 raise RuntimeError, ("Trying to migrate ext2 to something other "
559 # if journal already exists skip
560 if isys
.ext2HasJournal(devicePath
):
561 log
.info("Skipping migration of %s, has a journal already.\n" % devicePath
)
564 rc
= inutil
.execWithRedirect("tune2fs",
566 stdout
= "/dev/tty5",
567 stderr
= "/dev/tty5", searchPath
= 1)
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 "
577 "running tune2fs.\n" % (devicePath
))
579 rc
= message(_("Error"),
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?")
584 % (devicePath
, devicePath
), type = "yesno")
587 entry
.fsystem
= entry
.origfsystem
589 extFileSystem
.setExt3Options(self
, entry
, message
, chroot
)
592 fileSystemTypeRegister(ext2FileSystem())
594 class ext3FileSystem(extFileSystem
):
596 extFileSystem
.__init
__(self
)
598 self
.extraFormatArgs
= [ "-t", "ext3" ]
599 self
.partedFileSystemType
= parted
.file_system_type_get("ext3")
600 self
.migratetofs
= ['ext4dev']
602 def formatDevice(self
, entry
, progress
, chroot
='/'):
603 extFileSystem
.formatDevice(self
, entry
, progress
, chroot
)
604 extFileSystem
.setExt3Options(self
, entry
, progress
, chroot
)
606 def migrateFileSystem(self
, entry
, message
, chroot
='/'):
607 devicePath
= entry
.device
.setupDevice(chroot
)
609 if not entry
.fsystem
or not entry
.origfsystem
:
610 raise RuntimeError, ("Trying to migrate fs w/o fsystem or "
612 if entry
.fsystem
.getName() != "ext4dev":
613 raise RuntimeError, ("Trying to migrate ext3 to something other "
616 # This is only needed as long as ext4 is actually "ext4dev"
617 rc
= inutil
.execWithRedirect("tune2fs",
618 ["-E", "test_fs", devicePath
],
619 stdout
= "/dev/tty5",
620 stderr
= "/dev/tty5", searchPath
= 1)
624 fileSystemTypeRegister(ext3FileSystem())
626 class ext4FileSystem(extFileSystem
):
628 extFileSystem
.__init
__(self
)
630 self
.partedFileSystemType
= parted
.file_system_type_get("ext3")
631 self
.extraFormatArgs
= [ "-t", "ext4" ]
632 self
.bootable
= False
634 def formatDevice(self
, entry
, progress
, chroot
='/'):
635 extFileSystem
.formatDevice(self
, entry
, progress
, chroot
)
636 extFileSystem
.setExt3Options(self
, entry
, progress
, chroot
)
638 fileSystemTypeRegister(ext4FileSystem())
640 class swapFileSystem(FileSystemType
):
644 FileSystemType
.__init
__(self
)
645 self
.partedFileSystemType
= parted
.file_system_type_get("linux-swap")
648 self
.maxSizeMB
= 8 * 1024 * 1024
649 self
.linuxnativefs
= 1
651 self
.maxLabelChars
= 15
653 def mount(self
, device
, mountpoint
, readOnly
=0, bindMount
=0, instroot
= None):
654 pagesize
= resource
.getpagesize()
661 fd
= os
.open(device
, os
.O_RDONLY
)
662 buf
= os
.read(fd
, num
)
671 if buf
is not None and len(buf
) == pagesize
:
672 sig
= buf
[pagesize
- 10:]
673 if sig
== 'SWAP-SPACE':
675 if sig
== 'S1SUSPEND\x00' or sig
== 'S2SUSPEND\x00':
680 def umount(self
, device
, path
):
681 # unfortunately, turning off swap is bad.
682 raise RuntimeError, "unable to turn off swap"
684 def formatDevice(self
, entry
, progress
, chroot
='/'):
685 file = entry
.device
.setupDevice(chroot
)
686 rc
= inutil
.execWithRedirect("mkswap",
688 stdout
= "/dev/tty5",
689 stderr
= "/dev/tty5",
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
699 if devName
[0:6] == "cciss/":
700 swapLabel
= "SW-%s" % (devName
)
701 elif devName
.startswith("mapper/"):
702 swapLabel
= "SWAP-%s" % (devName
[7:],)
704 swapLabel
= "SWAP-%s" % (devName
)
705 label
= labelFactory
.createLabel(swapLabel
, self
.maxLabelChars
)
706 rc
= inutil
.execWithRedirect("mkswap",
707 ["-v1", "-L", label
, file],
708 stdout
= "/dev/tty5",
709 stderr
= "/dev/tty5",
713 entry
.setLabel(label
)
715 def clobberDevice(self
, entry
, chroot
):
716 pagesize
= resource
.getpagesize()
717 dev
= entry
.device
.setupDevice(chroot
)
719 fd
= os
.open(dev
, os
.O_RDWR
)
720 buf
= "\0x00" * pagesize
730 fileSystemTypeRegister(swapFileSystem())
732 class FATFileSystem(FileSystemType
):
734 FileSystemType
.__init
__(self
)
735 self
.partedFileSystemType
= parted
.file_system_type_get("fat32")
738 self
.maxSizeMB
= 1024 * 1024
741 fileSystemTypeRegister(FATFileSystem())
743 class NTFSFileSystem(FileSystemType
):
745 FileSystemType
.__init
__(self
)
746 self
.partedFileSystemType
= parted
.file_system_type_get("ntfs")
751 fileSystemTypeRegister(NTFSFileSystem())
753 class ForeignFileSystem(FileSystemType
):
755 FileSystemType
.__init
__(self
)
758 self
.name
= "foreign"
760 def formatDevice(self
, entry
, progress
, chroot
='/'):
763 fileSystemTypeRegister(ForeignFileSystem())
765 class PsudoFileSystem(FileSystemType
):
766 def __init__(self
, name
):
767 FileSystemType
.__init
__(self
)
773 def isKernelFS(self
):
776 class ProcFileSystem(PsudoFileSystem
):
778 PsudoFileSystem
.__init
__(self
, "proc")
780 fileSystemTypeRegister(ProcFileSystem())
782 class SysfsFileSystem(PsudoFileSystem
):
784 PsudoFileSystem
.__init
__(self
, "sysfs")
786 fileSystemTypeRegister(SysfsFileSystem())
788 class DevptsFileSystem(PsudoFileSystem
):
790 PsudoFileSystem
.__init
__(self
, "devpts")
791 self
.defaultOptions
= "gid=5,mode=620"
793 def isMountable(self
):
796 fileSystemTypeRegister(DevptsFileSystem())
798 class DevshmFileSystem(PsudoFileSystem
):
800 PsudoFileSystem
.__init
__(self
, "tmpfs")
802 def isMountable(self
):
805 fileSystemTypeRegister(DevshmFileSystem())
807 class AutoFileSystem(PsudoFileSystem
):
809 PsudoFileSystem
.__init
__(self
, "auto")
811 def mount(self
, device
, mountpoint
, readOnly
=0, bindMount
=0, instroot
= None):
813 errMsg
= "cannot mount auto filesystem on %s of this type" % device
815 if not self
.isMountable():
817 inutil
.mkdirChain("%s/%s" %(instroot
, mountpoint
))
818 for fs
in getFStoTry (device
):
820 isys
.mount (device
, mountpoint
, fstype
= fs
, readOnly
= readOnly
,
821 bindMount
= bindMount
)
823 except SystemError, (num
, msg
):
828 raise SystemError (errNum
, errMsg
)
830 def umount(self
, device
, path
):
831 isys
.umount(path
, removeDir
= 0)
833 fileSystemTypeRegister(AutoFileSystem())
835 class BindFileSystem(PsudoFileSystem
):
837 PsudoFileSystem
.__init
__(self
, "bind")
839 def isMountable(self
):
842 fileSystemTypeRegister(BindFileSystem())
846 self
.messageWindow
= None
847 self
.progressWindow
= None
848 self
.waitWindow
= None
852 self
.volumesCreated
= 0
855 return self
.mountcount
!= 0
857 def registerMessageWindow(self
, method
):
858 self
.messageWindow
= method
860 def registerProgressWindow(self
, method
):
861 self
.progressWindow
= method
863 def registerWaitWindow(self
, method
):
864 self
.waitWindow
= method
868 proc
= FileSystemSetEntry(Device(device
="proc"), '/proc',
869 fileSystemTypeGet("proc"))
871 sys
= FileSystemSetEntry(Device(device
="sys"), '/sys',
872 fileSystemTypeGet("sysfs"))
874 pts
= FileSystemSetEntry(Device(device
="devpts"), '/dev/pts',
875 fileSystemTypeGet("devpts"), "gid=5,mode=620")
877 shm
= FileSystemSetEntry(Device(device
="shm"), '/dev/shm',
878 fileSystemTypeGet("tmpfs"))
882 for entry
in self
.entries
:
883 if type(entry
.__dict
__) != type({}):
884 raise RuntimeError, "fsset internals inconsistent"
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
):
892 devA
= a
.device
.getDevice()
893 devB
= b
.device
.getDevice()
895 if not mntB
or not devB
:
897 if not mntA
or not devA
:
900 if (mntA
.startswith(mntB
) and mntA
!= mntB
) or (devA
.startswith(mntB
) and devA
!= devB
):
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
)
914 #log.info ("fsset at %s\n"
915 # "adding entry for %s\n"
916 # "entry object %s, class __dict__ is %s",
917 # self, entry.mountpoint, entry,
918 # isys.printObject(entry.__dict__))
922 # Special case for /.
923 if newEntry
.mountpoint
== "/":
924 self
.entries
.insert(insertAt
, newEntry
)
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
)
932 for entry
in self
.entries
:
933 if comesAfter(newEntry
, entry
):
934 insertAt
= self
.entries
.index(entry
)+1
936 self
.entries
.insert(insertAt
, newEntry
)
938 def remove (self
, entry
):
939 self
.entries
.remove(entry
)
941 def getEntryByMountPoint(self
, mount
):
942 for entry
in self
.entries
:
943 if entry
.mountpoint
== mount
:
947 def getEntryByDeviceName(self
, dev
):
948 for entry
in self
.entries
:
949 if entry
.device
.getDevice() == dev
:
954 new
= FileSystemSet()
955 for entry
in self
.entries
:
960 format
= "%-23s %-23s %-7s %-15s %d %d\n"
964 # Created by pomona on %s
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
971 for entry
in self
.entries
:
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:
976 device
= "LABEL=%s" % (entry
.getLabel(),)
978 device
= devify(entry
.device
.getDevice())
979 fstab
= fstab
+ entry
.device
.getComment()
980 fstab
= fstab
+ format
% (device
, entry
.mountpoint
,
981 entry
.fsystem
.getMountName(),
982 entry
.getOptions(), entry
.fsck
,
987 format
= "%s %s %s %s 0 0\n"
989 for entry
in self
.entries
:
990 if not entry
.isMounted():
993 # swap doesn't end up in the mtab
994 if entry
.fsystem
.getName() == "swap":
997 options
= "rw," + entry
.options
1000 mtab
= mtab
+ format
% (devify(entry
.device
.getDevice()),
1002 entry
.fsystem
.getName(),
1007 def write(self
, prefix
):
1008 f
= open(prefix
+ "/etc/fstab", "w")
1009 f
.write(self
.fstab())
1013 open(prefix
+ "/etc/mtab", "w+")
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
1022 #if not os.path.exists("%s/dev/root" %(instPath,)):
1023 # os.mknod("%s/dev/root" % (instPath,), stat.S_IFBLK | 0600, rdev)
1025 # return the "boot" device
1026 def getBootDev(self
):
1029 for entry
in self
.entries
:
1030 mntDict
[entry
.mountpoint
] = entry
.device
1032 if mntDict
.has_key("/boot"):
1033 bootDev
= mntDict
['/boot']
1034 elif mntDict
.has_key("/"):
1035 bootDev
= mntDict
['/']
1039 def bootloaderChoices(self
, diskSet
, bl
):
1041 bootDev
= self
.getBootDev()
1044 log
.warning("no boot device set")
1047 ret
['boot'] = (bootDev
.device
, N_("First sector of boot partition"))
1048 ret
['mbr'] = (bl
.drivelist
[0], N_("Master Boot Record (MBR)"))
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()
1060 bootDev
= dev
.device
1062 for drive
in diskset
.disks
.keys():
1065 disk
= diskset
.disks
[drive
]
1066 part
= disk
.next_partition()
1068 if not part
.is_active():
1069 part
= disk
.next_partition(part
)
1072 if not part
.is_flag_available(parted
.PARTITION_BOOT
):
1077 if part
.get_flag(parted
.PARTITION_BOOT
):
1085 if partedUtils
.get_partition_name(part
) == bootDev
:
1088 part
= disk
.next_partition(part
)
1090 if bootPart
and not foundActive
:
1091 bootPart
.set_flag(parted
.PARTITION_BOOT
, 1)
1096 def formatSwap(self
, chroot
, forceFormat
=False):
1100 for entry
in self
.entries
:
1101 if (not entry
.fsystem
or not entry
.fsystem
.getName() == "swap" or
1104 if not entry
.getFormat():
1106 notformatted
.append(entry
)
1109 self
.formatEntry(entry
, chroot
)
1110 formatted
.append(entry
)
1112 if self
.messageWindow
:
1113 self
.messageWindow(_("Error"),
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(),))
1122 for entry
in formatted
:
1124 self
.labelEntry(entry
, chroot
)
1126 # should be OK, fall back to by device
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":
1135 label
= isys
.readFSLabel(dev
)
1139 entry
.setLabel(label
)
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")
1148 self
.entries
.remove(entry
)
1150 self
.formatEntry(entry
, chroot
)
1152 self
.mountcount
= self
.mountcount
+ 1
1156 for entry
in self
.entries
:
1157 if (entry
.fsystem
and entry
.fsystem
.getName() == "swap"
1158 and not entry
.isMounted()):
1161 self
.mountcount
= self
.mountcount
+ 1
1162 except OldSwapError
:
1163 if self
.messageWindow
:
1164 msg
= _("The swap device:\n\n /dev/%s\n\n"
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())
1171 swapErrorDialog(msg
, _("Reformat"), entry
)
1172 except SuspendError
:
1173 if self
.messageWindow
:
1175 msg
= _("The swap device:\n\n /dev/%s\n\n"
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())
1183 msg
= _("The swap device:\n\n /dev/%s\n\n"
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())
1192 # choose your own adventure swap partitions...
1193 msg
= msg
+ _("\n\nChoose Skip if you want the "
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.")
1199 swapErrorDialog(msg
, _("Format"), entry
)
1203 except SystemError, (num
, msg
):
1204 if self
.messageWindow
:
1206 self
.messageWindow(_("Error"),
1207 _("Error enabling swap device "
1209 "The /etc/fstab on your "
1210 "upgrade partition does not "
1211 "reference a valid swap "
1213 "Press OK to reboot your "
1215 % (entry
.device
.getDevice(), msg
))
1217 self
.messageWindow(_("Error"),
1218 _("Error enabling swap device "
1220 "This most likely means this "
1221 "swap partition has not been "
1223 "Press OK to reboot your "
1225 % (entry
.device
.getDevice(), msg
))
1228 def labelEntry(self
, entry
, chroot
):
1229 label
= entry
.device
.getLabel()
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
)
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
)
1243 def badblocksEntry(self
, entry
, chroot
):
1244 entry
.fsystem
.badblocksDevice(entry
, self
.progressWindow
, chroot
)
1246 def getMigratableEntries(self
):
1248 for entry
in self
.entries
:
1249 if entry
.origfsystem
and entry
.origfsystem
.isMigratable():
1250 retval
.append(entry
)
1254 def formattablePartitions(self
):
1256 for entry
in self
.entries
:
1257 if entry
.fsystem
.isFormattable():
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()):
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"),
1272 _("Bad blocks have been detected on "
1273 "device /dev/%s. We do "
1274 "not recommend you use this device."
1276 "Press <Enter> to reboot your system")
1277 % (entry
.device
.getDevice(),))
1281 if self
.messageWindow
:
1282 self
.messageWindow(_("Error"),
1283 _("An error occurred searching for "
1284 "bad blocks on %s. This problem is "
1285 "serious, and the install cannot "
1287 "Press <Enter> to reboot your system.")
1288 % (entry
.device
.getDevice(),))
1291 def makeFilesystems(self
, chroot
='/'):
1294 for entry
in self
.entries
:
1295 if (not entry
.fsystem
.isFormattable() or not entry
.getFormat()
1296 or entry
.isMounted()):
1297 notformatted
.append(entry
)
1300 self
.formatEntry(entry
, chroot
)
1301 formatted
.append(entry
)
1303 if self
.messageWindow
:
1304 self
.messageWindow(_("Error"),
1305 _("An error occurred trying to "
1306 "format %s. This problem is "
1307 "serious, and the install cannot "
1309 "Press <Enter> to reboot your system.")
1310 % (entry
.device
.getDevice(),))
1313 for entry
in formatted
:
1315 self
.labelEntry(entry
, chroot
)
1317 # should be OK, we'll still use the device name to mount.
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":
1325 if not entry
.mountpoint
or entry
.mountpoint
== "swap":
1328 label
= isys
.readFSLabel(dev
)
1332 entry
.setLabel(label
)
1334 self
.labelEntry(entry
, chroot
)
1336 def haveMigratedFilesystems(self
):
1337 return self
.migratedfs
1339 def migrateFilesystems(self
, chroot
='/'):
1343 for entry
in self
.entries
:
1344 if not entry
.origfsystem
:
1347 if not entry
.origfsystem
.isMigratable() or not entry
.getMigrate():
1350 entry
.origfsystem
.migrateFileSystem(entry
, self
.messageWindow
, chroot
)
1352 if self
.messageWindow
:
1353 self
.messageWindow(_("Error"),
1354 _("An error occurred trying to "
1355 "migrate %s. This problem is "
1356 "serious, and the install cannot "
1358 "Press <Enter> to reboot your system.")
1359 % (entry
.device
.getDevice(),))
1364 def mountFilesystems(self
, pomona
, raiseErrors
= 0, readOnly
= 0):
1365 #protected = pomona.method.protectedPartitions()
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
):
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"),
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
,))
1390 self
.messageWindow(_("Invalid mount point"),
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
))
1398 except SystemError, (num
, msg
):
1400 raise SystemError, (num
, msg
)
1402 if self
.messageWindow
:
1403 if not entry
.fsystem
.isLinuxNativeFS():
1404 ret
= self
.messageWindow(_("Unable to mount filesystem"),
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(),
1411 type="custom", custom_icon
="warning",
1412 custom_buttons
=[_("_Reboot"), _("_Continue")])
1419 if pomona
.id.getUpgrade() and not entry
.getLabel():
1420 errStr
= _("Error mounting device %s as %s: "
1422 "Devices in /etc/fstab should be "
1423 "specified by label, not by device name."
1425 "Press OK to reboot your system.") % (entry
.device
.getDevice(), entry
.mountpoint
, msg
)
1427 errStr
= _("Error mounting device %s as %s: "
1429 "This most likely means this "
1430 "partition has not been formatted."
1432 "Press OK to reboot your system.") % (entry
.device
.getDevice(), entry
.mountpoint
, msg
)
1434 self
.messageWindow(_("Error"), errStr
)
1438 def filesystemSpace(self
, chroot
='/'):
1440 for entry
in self
.entries
:
1441 if not entry
.isMounted():
1443 # we can't put swap files on swap partitions; that's nonsense
1444 if entry
.mountpoint
== "swap":
1446 path
= "%s/%s" % (chroot
, entry
.mountpoint
)
1448 space
.append((entry
.mountpoint
, isys
.pathSpaceAvailable(path
)))
1450 log
.error("failed to get space available in filesystemSpace() for %s" %(entry
.mountpoint
,))
1452 def spaceSort(a
, b
):
1462 space
.sort(spaceSort
)
1465 def hasDirtyFilesystems(self
, mountpoint
):
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
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(),))
1483 def umountFilesystems(self
, instPath
, ignoreErrors
= 0, swapoff
= True):
1484 # XXX remove special case
1486 isys
.umount(instPath
+ '/proc/bus/usb', removeDir
= 0)
1487 log
.info("Umount USB OK")
1489 # log.error("Umount USB Fail")
1492 # take a slice so we don't modify self.entries
1493 reverse
= self
.entries
[:]
1496 for entry
in reverse
:
1497 if entry
.mountpoint
== "swap" and not swapoff
:
1499 entry
.umount(instPath
)
1501 class FileSystemSetEntry
:
1502 def __init__ (self
, device
, mountpoint
,
1503 fsystem
=None, options
=None,
1504 origfsystem
=None, migrate
=0,
1505 order
=-1, fsck
=-1, format
=0,
1506 badblocks
= 0, bytesPerInode
=4096, fsprofile
=None):
1508 fsystem
= fileSystemTypeGet("ext2")
1509 self
.device
= device
1510 self
.mountpoint
= mountpoint
1511 self
.fsystem
= fsystem
1512 self
.origfsystem
= origfsystem
1513 self
.migrate
= migrate
1515 self
.options
= options
1517 self
.options
= fsystem
.getDefaultOptions(mountpoint
)
1518 self
.options
+= device
.getDeviceOptions()
1522 self
.fsck
= fsystem
.isChecked()
1526 if mountpoint
== '/':
1534 if format
and not fsystem
.isFormattable():
1535 raise RuntimeError, ("file system type %s is not formattable, "
1536 "but has been added to fsset with format "
1537 "flag on" % fsystem
.getName())
1538 self
.format
= format
1539 self
.badblocks
= badblocks
1540 self
.bytesPerInode
= bytesPerInode
1541 self
.fsprofile
= fsprofile
1543 def mount(self
, chroot
='/', devPrefix
='/dev', readOnly
= 0):
1544 device
= self
.device
.setupDevice(chroot
, devPrefix
=devPrefix
)
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
,),
1550 readOnly
= readOnly
,
1551 bindMount
= isinstance(self
.device
,
1555 self
.fsystem
.mount(device
, "%s" % (self
.mountpoint
,),
1556 readOnly
= readOnly
,
1557 bindMount
= isinstance(self
.device
,
1561 self
.mountcount
= self
.mountcount
+ 1
1563 def umount(self
, chroot
='/'):
1564 if self
.mountcount
> 0:
1566 self
.fsystem
.umount(self
.device
, "%s/%s" % (chroot
, self
.mountpoint
))
1567 self
.mountcount
= self
.mountcount
- 1
1568 except RuntimeError:
1571 def setFileSystemType(self
, fstype
):
1572 self
.fsystem
= fstype
1574 def setBadblocks(self
, state
):
1575 self
.badblocks
= state
1577 def getBadblocks(self
):
1578 return self
.badblocks
1580 def getMountPoint(self
):
1581 return self
.mountpoint
1583 def getOptions(self
):
1584 options
= self
.options
1586 options
= self
.fsystem
.getDefaultOptions(self
.mountpoint
)
1587 return options
+ self
.device
.getDeviceOptions()
1589 def setFormat (self
, state
):
1590 if self
.migrate
and state
:
1591 raise ValueError, "Trying to set format bit on when migrate is set!"
1594 def getFormat (self
):
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
1602 def getMigrate (self
):
1605 def isMounted (self
):
1606 return self
.mountcount
> 0
1608 def getLabel (self
):
1612 return isys
.readFSUuid(self
.device
.getDevice())
1614 def setLabel (self
, label
):
1618 if not self
.mountpoint
:
1621 mntpt
= self
.mountpoint
1623 str = ("fsentry -- device: %(device)s mountpoint: %(mountpoint)s\n"
1624 " fsystem: %(fsystem)s format: %(format)s\n"
1625 " ismounted: %(mounted)s options: '%(options)s'\n"
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
})
1635 def __init__(self
, device
= "none"):
1636 self
.device
= device
1640 self
.deviceOptions
= ""
1642 def getComment (self
):
1645 def getDevice (self
, asBoot
= 0):
1648 def setupDevice (self
, chroot
='/', devPrefix
='/dev'):
1651 def cleanupDevice (self
, chroot
, devPrefix
='/dev'):
1654 def solidify (self
):
1658 return self
.__class
__.__name
__
1662 return isys
.readFSLabel(self
.setupDevice())
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"
1672 """Check to see if we're set as a netdev"""
1673 if "_netdev" in self
.deviceOptions
:
1677 def getDeviceOptions(self
):
1678 return self
.deviceOptions
1680 class DevDevice(Device
):
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
)
1687 def getDevice(self
, asBoot
= 0):
1690 def setupDevice(self
, chroot
='/', devPrefix
='/dev'):
1691 return "/dev/%s" %(self
.getDevice(),)
1694 ext2
= fileSystemTypeGet("ext2")
1696 class PartitionDevice(Device
):
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
1703 def setupDevice(self
, chroot
="/", devPrefix
='/dev'):
1704 path
= '%s/%s' % (devPrefix
, self
.getDevice(),)
1707 class PartedPartitionDevice(PartitionDevice
):
1708 def __init__(self
, partition
):
1709 Device
.__init
__(self
)
1711 self
.partition
= partition
1713 def getDevice(self
, asBoot
= 0):
1714 if not self
.partition
:
1717 return partedUtils
.get_partition_name(self
.partition
)
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
1725 class BindMountDevice(Device
):
1726 def __init__(self
, directory
):
1727 Device
.__init
__(self
)
1728 self
.device
= directory
1730 def setupDevice(self
, chroot
="/", devPrefix
="/tmp"):
1731 return chroot
+ self
.device
1733 class SwapFileDevice(Device
):
1734 def __init__(self
, file):
1735 Device
.__init
__(self
)
1739 def setSize (self
, size
):
1742 def setupDevice (self
, chroot
="/", devPrefix
='/tmp'):
1743 file = os
.path
.normpath(chroot
+ self
.getDevice())
1744 if not os
.access(file, os
.R_OK
):
1746 # make sure the permissions are set properly
1747 fd
= os
.open(file, os
.O_CREAT
, 0600)
1749 isys
.ddfile(file, self
.size
, None)
1751 raise SystemError, (0, "swap file creation necessary, but "
1752 "required size is unknown.")
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
1759 class PiggybackSwapFileDevice(SwapFileDevice
):
1760 def __init__(self
, piggypath
, file):
1761 SwapFileDevice
.__init
__(self
, file)
1762 self
.piggypath
= piggypath
1764 def setupDevice(self
, chroot
="/", devPrefix
='/tmp'):
1765 return SwapFileDevice
.setupDevice(self
, self
.piggypath
, devPrefix
)
1767 class LoopbackDevice(Device
):
1768 def __init__(self
, hostPartition
, hostFs
):
1769 Device
.__init
__(self
)
1770 self
.host
= "/dev/" + hostPartition
1771 self
.hostfs
= hostFs
1772 self
.device
= "loop1"
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")
1779 raise SystemError, "Unable to allocate loopback device"
1781 path
= '%s/%s' % (devPrefix
, self
.getDevice())
1783 path
= '%s/%s' % (devPrefix
, self
.getDevice())
1784 #isys.makeDevInode(self.getDevice(), path)
1785 path
= os
.path
.normpath(path
)
1788 def getComment (self
):
1789 return "# LOOP1: %s %s /redhat.img\n" % (self
.host
, self
.hostfs
)
1791 def makeDevice(dev
):
1792 device
= DevDevice(dev
)
1795 def readFstab(pomona
):
1796 path
= pomona
.rootPath
+ '/etc/fstab'
1798 fsset
= FileSystemSet()
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()
1808 for device
, label
in labels
.items():
1809 if not labelToDevice
.has_key(label
):
1810 labelToDevice
[label
] = device
1811 elif intf
is not None:
1813 intf
.messageWindow(_("Duplicate Labels"),
1814 _("Multiple devices on your system are "
1815 "labelled %s. Labels across devices must be "
1816 "unique for your system to function "
1818 "Please fix this problem and restart the "
1819 "installation process.")
1820 % (label
,), type="custom", custom_icon
="error",
1821 custom_buttons
=[_("_Reboot")])
1823 intf
.messageWindow(_("Invalid Label"),
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")])
1832 log
.warning("Duplicate labels for %s, but no intf so trying "
1833 "to continue" % (label
,))
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
)
1841 f
= open (path
, "r")
1842 lines
= f
.readlines ()
1846 fields
= string
.split(line
)
1848 if not fields
: continue
1854 # all valid fstab entries have 6 fields; if the last two are missing
1855 # they are assumed to be zero per fstab(5)
1858 elif len(fields
) == 4:
1861 elif len(fields
) == 5:
1863 elif len(fields
) > 6:
1866 if string
.find(fields
[3], "noauto") != -1: continue
1868 # shenanigans to handle ext3,ext2 format in fstab
1870 if fstotry
.find(","):
1871 fstotry
= fstotry
.split(",")
1873 fstotry
= [ fstotry
]
1876 # if we don't support mounting the filesystem, continue
1877 if not fileSystemTypes
.has_key(fs
):
1879 fsystem
= fileSystemTypeGet(fs
)
1881 # "none" is valid as an fs type for bind mounts (#151458)
1882 if fsystem
is None and (string
.find(fields
[3], "bind") == -1):
1885 if fields
[0] == "none":
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
])
1896 log
.warning ("fstab file has LABEL=%s, but this label "
1897 "could not be found on any file system", label
)
1898 # bad luck, skip this entry.
1900 elif fields
[2] == "swap" and not fields
[0].startswith('/dev/'):
1903 if file.startswith('/initrd/loopfs/'):
1905 device
= PiggybackSwapFileDevice("/mnt/loophost", file)
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:])
1918 device
= Device(device
= fields
[0])
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":
1925 tmp
= partedUtils
.sniffFilesystemType("/dev/%s" %(device
.setupDevice(),))
1931 entry
= FileSystemSetEntry(device
, fields
[1], fsystem
, fields
[3],
1932 origfsystem
=fsystem
)
1934 entry
.setLabel(label
)
1938 def getDevFD(device
):
1940 fd
= os
.open(device
, os
.O_RDONLY
)
1942 file = '/dev/' + device
1944 fd
= os
.open(file, os
.O_RDONLY
)
1949 def isValidExt2(device
):
1950 fd
= getDevFD(device
)
1954 buf
= os
.read(fd
, 2048)
1957 if len(buf
) != 2048:
1960 if struct
.unpack("<H", buf
[1080:1082]) == (0xef53,):
1965 def isValidXFS(device
):
1966 fd
= getDevFD(device
)
1970 buf
= os
.read(fd
, 4)
1981 def isValidReiserFS(device
):
1982 fd
= getDevFD(device
)
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
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
:
1998 os
.lseek(fd
, SBOffset
, 0)
1999 buf
= os
.read(fd
, bufSize
)
2003 if len(buf
) < bufSize
:
2006 if (buf
[reiserMagicOffset
:reiserMagicOffset
+len(reiserMagicVal
)] == reiserMagicVal
):
2013 # this will return a list of types of filesystems which device
2014 # looks like it could be to try mounting as
2015 def getFStoTry(device
):
2018 if isValidXFS(device
):
2021 if isValidReiserFS(device
):
2022 rc
.append("reiserfs")
2024 if isValidExt2(device
):
2025 if isys
.ext2HasJournal(device
):
2029 ### XXX FIXME: need to check for swap
2033 def allocateLoopback(file):
2036 dev
= "loop%d" % (i
,)
2037 path
= "/dev/loop%d" % (i
,)
2039 isys
.losetup(path
, file)
2048 def ext2FormatFilesystem(argList
, messageFile
, windowCreator
, mntpoint
):
2050 w
= windowCreator(_("Formatting"),
2051 _("Formatting %s file system...") % (mntpoint
,), 100)
2055 fd
= os
.open(messageFile
, os
.O_RDWR | os
.O_CREAT | os
.O_APPEND
)
2057 childpid
= os
.fork()
2064 os
.execvp(argList
[0], argList
)
2065 log
.critical("failed to exec %s", argList
)
2070 # ignoring SIGCHLD would be cleaner then ignoring EINTR, but
2071 # we can't use signal() in this thread?
2074 while s
and s
!= '\b':
2076 s
= os
.read(p
[0], 1)
2077 except OSError, args
:
2087 s
= os
.read(p
[0], 1)
2096 if num
and len(num
):
2097 l
= string
.split(num
, '/')
2099 val
= (int(l
[0]) * 100) / int(l
[1])
2100 except (IndexError, TypeError):
2105 except OSError, args
:
2111 (pid
, status
) = os
.waitpid(childpid
, 0)
2112 except OSError, (num
, msg
):
2113 log
.critical("exception from waitpid while formatting: %s %s" %(num
, msg
))
2119 # *shrug* no clue why this would happen, but hope that things are fine
2123 if os
.WIFEXITED(status
) and (os
.WEXITSTATUS(status
) == 0):
2128 # copy and paste job from booty/bootloaderInfo.py...
2129 def getDiskPart(dev
):
2131 if (dev
.startswith('rd/') or dev
.startswith('ida/') or
2132 dev
.startswith('cciss/') or dev
.startswith('sx8/') or
2133 dev
.startswith('mapper/')):
2136 elif dev
[-3] == 'p':
2139 if dev
[-2] in string
.digits
:
2141 elif dev
[-1] in string
.digits
:
2146 # hack off the trailing 'p' from /dev/cciss/*, for example
2149 if letter
not in string
.letters
and letter
!= "/":
2154 partNum
= int(dev
[cut
:]) - 1
2158 return (name
, partNum
)