/[gli]/branches/overhaul/src/Partitioning.py
Gentoo

Contents of /branches/overhaul/src/Partitioning.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1695 - (show annotations) (download) (as text)
Wed Feb 14 03:13:02 2007 UTC (9 years, 2 months ago) by agaffney
File MIME type: text/x-python
File size: 24622 byte(s)
forgot the quotes
1 # Copyright 1999-2006 Gentoo Foundation
2 # This source code is distributed under the terms of version 2 of the GNU
3 # General Public License as published by the Free Software Foundation, a copy
4 # of which can be found in the main directory of this project.
5
6 import commands, string, os, parted, copy
7 from glob import glob
8 from GLIException import *
9 import GLIUtility
10 import time
11
12 MEGABYTE = 1024 * 1024
13
14 supported_filesystems = {
15 'all': ( 'ext2', 'ext3', 'linux-swap', 'xfs', 'jfs', 'reiserfs' ),
16 'x86': ( 'ntfs', 'fat16', 'fat32' ),
17 'amd64': ( 'ntfs', 'fat16', 'fat32' ),
18 'ppc': ( 'reiserfs', 'apple_bootstrap', 'hfs' )
19 }
20
21 labelinfo = {
22 'msdos': { 'ignoredparts': [], 'extended': True },
23 'mac': { 'ignoredparts': [1], 'extended': False },
24 'sun': { 'ignoredparts': [3], 'extended': False },
25 'loop': { 'ignoredparts': [], 'extended': False }
26 }
27
28 archinfo = {
29 'sparc': 'sun',
30 'hppa': 'msdos',
31 'x86': 'msdos',
32 'amd64': 'msdos',
33 'ppc': 'mac'
34 }
35
36 parted_type_map = {
37 'linux-swap': 'swap'
38 }
39
40 ##
41 # This class provides a partitioning abstraction for the frontends
42 class Device:
43 "Class representing a partitionable device."
44
45 _device = None
46 _partitions = None
47 _geometry = None
48 _parted_dev = None
49 _parted_disk = None
50 _arch = None
51 _disklabel = None
52 _install_profile = None
53
54 ##
55 # Initialization function for Device class
56 # @param device Device node (e.g. /dev/hda) of device being represented
57 # @param arch Architecture that we're partition for (defaults to 'x86' for now)
58 def __init__(self, device, arch, install_profile):
59 self._device = device
60 self._arch = arch
61 self._partitions = []
62 self._geometry = {}
63 self._parted_dev = parted.PedDevice.get(self._device)
64 try:
65 self._parted_disk = parted.PedDisk.new(self._parted_dev)
66 except:
67 self._parted_disk = self._parted_dev.disk_new_fresh(parted.disk_type_get(archinfo[self._arch]))
68 self._disklabel = self._parted_disk.type.name
69 self._labelinfo = labelinfo[self._disklabel]
70 self.set_disk_geometry_from_disk()
71 self.set_partitions_from_disk()
72 self._install_profile = install_profile
73
74 def __getitem__(self, name):
75 return self.get_partition(name)
76
77 def __iter__(self):
78 for part in self.get_partitions():
79 yield part
80
81 ##
82 # Returns list of supported filesystems based on arch
83 def get_supported_filesystems(self):
84 return supported_filesystems['all'] + supported_filesystems[self._arch]
85
86 ##
87 # Sets disk geometry info from disk. This function is used internally by __init__()
88 def set_disk_geometry_from_disk(self):
89 self._geometry = {
90 'sector_size': self._parted_dev.sector_size,
91 'total_bytes': self._parted_dev.length * self._parted_dev.sector_size,
92 'heads': self._parted_dev.heads,
93 'cylinders': self._parted_dev.cylinders,
94 'sectors': self._parted_dev.sectors,
95 'cylinder_bytes': self._parted_dev.heads * self._parted_dev.sectors * self._parted_dev.sector_size,
96 'total_sectors': self._parted_dev.length,
97 'sectors_in_cylinder': self._parted_dev.heads * self._parted_dev.sectors,
98 'total_mb': long((self._parted_dev.length * self._parted_dev.sector_size) / MEGABYTE)
99 }
100
101 ##
102 # Sets partition info from disk.
103 def set_partitions_from_disk(self):
104 self._partitions = []
105 parted_part = self._parted_disk.next_partition()
106 while parted_part:
107 # Make sure it's a physical partition or unallocated space
108 if parted_part.num >= 1 or parted_part.type_name == "free":
109 self._partitions.append(Partition(self, parted_part))
110 parted_part = self._parted_disk.next_partition(parted_part)
111
112 ##
113 # Returns the partition object with the specified minor
114 # @param idx Index of partition object
115 def get_partition(self, idx):
116 return self._partitions[idx]
117
118 def get_partition_idx_from_part(self, part):
119 for idx, tmppart in enumerate(self._partitions):
120 if tmppart['start'] == part['start'] and tmppart['end'] == part['end']:
121 return idx
122 else:
123 return -1
124
125 def get_partition_idx_from_minor(self, minor):
126 for idx, tmppart in enumerate(self._partitions):
127 if tmppart['minor'] == minor:
128 return idx
129 else:
130 return -1
131
132 def get_partition_idx_from_start_end(self, start, end):
133 for idx, tmppart in enumerate(self._partitions):
134 if tmppart['start'] == start and tmppart['end'] == end:
135 return idx
136 else:
137 return -1
138
139 def get_partiton_at_start(self, start):
140 for i, part in enumerate(self._partitions):
141 if part['start'] == start:
142 return i
143 return -1
144
145 ##
146 # Returns name of device (e.g. /dev/hda) being represented
147 def get_device(self):
148 return self._device
149
150 ##
151 # Uses magic to apply the recommended partition layout
152 def do_recommended(self):
153 freeidx = -1
154 free_part = None
155 remaining_free = 0
156 recommended_parts = [ { 'type': "ext2", 'size': 100, 'mountpoint': '/boot', 'mountopts': 'defaults' },
157 { 'type': "linux-swap", 'size': 512, 'mountpoint': 'swap', 'mountopts': 'defaults' },
158 { 'type': "ext3", 'size': "*", 'mountpoint': '/', 'mountopts': 'noatime' } ]
159 localmounts = copy.deepcopy(self._install_profile.get_mounts())
160 physical_memory = int(GLIUtility.spawn(r"free -m | egrep '^Mem:' | sed -e 's/^Mem: \+//' -e 's/ \+.\+$//'", return_output=True)[1].strip())
161 self.clear_partitions()
162 for newpart in recommended_parts:
163 # Find idx of remaining unallocated space
164 for idx, part in enumerate(self._partitions):
165 # We want to ignore any "false" free space
166 if part['type'] == "free" and part['mb'] >= 10:
167 freeidx = idx
168 free_part = part
169 remaining_free = free_part['mb']
170 break
171 # Small hack to calculate optimal swap partition size
172 if newpart['type'] == "linux-swap" and physical_memory:
173 newpart['size'] = physical_memory * 2
174 if newpart['size'] > 2048:
175 newpart['size'] = 2048
176 if newpart['size'] == "*":
177 newpart['size'] = remaining_free
178 newidx = self.add_partition(freeidx, newpart['size'], newpart['type'])
179 for i, mount in enumerate(localmounts):
180 if mount['devnode'] == self._partitions[newidx]['devnode']:
181 del localmounts[i]
182 break
183 localmounts.append({ 'devnode': self._partitions[newidx]['devnode'], 'type': parted_type_map.get(newpart['type'], newpart['type']), 'mountpoint': newpart['mountpoint'], 'mountopts': newpart['mountopts'] })
184 self._install_profile.set_mounts(localmounts)
185
186 def _megabytes_to_sectors(self, mb, sector_bytes=512):
187 return long(mb * MEGABYTE / sector_bytes)
188
189 def _sectors_to_megabytes(self, sectors, sector_bytes=512):
190 return float((float(sectors) * sector_bytes)/ float(MEGABYTE))
191
192 ##
193 # Adds a new partition to the partition info
194 # @param freeidx minor of unallocated space partition is being created in
195 # @param mb size of partition in MB
196 # @param type Partition type (ext2, ext3, fat32, linux-swap, free, extended, etc.)
197 def add_partition(self, freeidx, mb, fs, mkfsopts="", pregap=0):
198 types = { 'primary': parted.PARTITION_PRIMARY, 'extended': parted.PARTITION_EXTENDED, 'logical': parted.PARTITION_LOGICAL }
199 fs_types = {}
200 fstype = None
201 try:
202 free_part = self._partitions[freeidx]
203 except:
204 # raise an exception here
205 pass
206 if mb > free_part['mb']:
207 # raise an exception here
208 pass
209 # Enumerate supported filesystem types
210 fs_type = parted.file_system_type_get_next()
211 while fs_type:
212 fs_types[fs_type.name] = fs_type
213 fs_type = parted.file_system_type_get_next(fs_type)
214 # apple_bootstrap is a "magic" hfs
215 if fs == "apple_bootstrap":
216 fs = "hfs"
217 # grab relevant parted filesystemtype object
218 if fs:
219 fstype = fs_types[fs]
220 # determine correct partition type
221 parttype = "primary"
222 if fs == "extended":
223 fstype = None
224 parttype = "extended"
225 elif free_part.is_logical():
226 parttype = "logical"
227 # figure out start/end sectors
228 start = free_part['start'] + self._megabytes_to_sectors(pregap)
229 end = start + self._megabytes_to_sectors(mb)
230 parted_newpart = self._parted_disk.partition_new(types[parttype], fstype, start, end)
231 constraint = self._parted_disk.dev.constraint_any()
232 self._parted_disk.add_partition(parted_newpart, constraint)
233 self._parted_disk.commit()
234 self.set_partitions_from_disk()
235 if parttype != "extended":
236 newpart = self._partitions[self.get_partition_idx_from_minor(parted_newpart.num)]
237 devnode = newpart['devnode']
238 format_cmds = { 'linux-swap': "mkswap", 'fat16': "mkfs.vfat -F 16", 'fat32': "mkfs.vfat -F 32",
239 'ntfs': "mkntfs", 'xfs': "mkfs.xfs -f", 'jfs': "mkfs.jfs -f",
240 'reiserfs': "mkfs.reiserfs -f", 'ext2': "mkfs.ext2", 'ext3': "mkfs.ext3",
241 'hfs': "hformat", 'apple_bootstrap': "hformat"
242 }
243 if fs in format_cmds:
244 cmdname = format_cmds[fs]
245 else:
246 raise GLIException("PartitionFormatError", 'fatal', '_partition_format_step', "Unknown partition type " + fstype)
247 # sleep a bit first
248 time.sleep(1)
249 wait_for_device_node(devnode)
250 cmd = "%s %s %s" % (cmdname, mkfsopts, devnode)
251 ret = GLIUtility.spawn(cmd)
252 if not GLIUtility.exitsuccess(ret):
253 raise GLIException("PartitionFormatError", 'fatal', '_partition_format_step', "Could not create %s filesystem on %s" % (fstype, devnode))
254 self.set_partitions_from_disk()
255 newidx = self.get_partition_idx_from_start_end(parted_newpart.geom.start, parted_newpart.geom.end)
256 return newidx
257
258 ##
259 # Removes partition from partition info
260 # @param minor Minor of partition to remove
261 def remove_partition(self, partidx):
262 try:
263 tmp_part = self._partitions[partidx]
264 except:
265 # raise exception here
266 pass
267 if tmp_part['minor'] < 1:
268 # raise an exception here
269 pass
270 try:
271 self._parted_disk.delete_partition(self._parted_disk.get_partition(tmp_part['minor']))
272 except:
273 # raise an exception here
274 pass
275 self._parted_disk.commit()
276 self.set_partitions_from_disk()
277
278 # def resize_partition(self, partidx, mb):
279 # part = self._partitions[partidx]
280 # type = part['type']
281 # start = part['start']
282 # end = start + long(mb * MEGABYTE / 512) - 1
283 #
284 # total_sectors = end - start + 1
285 # total_bytes = long(total_sectors) * 512
286 #
287 # # Delete partition and recreate at same start point with new size if growing
288 # if mb > part['mb']:
289 # curminor = self._find_current_minor_for_part(device, start)
290 # self._parted_disk.delete_partition(self._parted_disk.get_partition(part['minor']))
291 # if part['logical']:
292 # tmptype = "logical"
293 # else:
294 # tmptype = "primary"
295 # self._add_partition(parted_disk, start, end, tmptype, tmppart_new['type'], strict_start=True)
296 # parted_disk.commit()
297 #
298 # curminor = self._find_current_minor_for_part(device, start)
299 # devnode = device + str(curminor)
300 #
301 # wait_for_device_node(devnode)
302 #
303 # if type in ("ext2", "ext3"):
304 # resizecmd = "resize2fs %s %sK" % (devnode, str(int((total_bytes - (2 * MEGABYTE)) / 1024)))
305 # self._logger.log("_partition_resize_step(): running: " + resizecmd)
306 # ret = GLIUtility.spawn(resizecmd, logfile=self._compile_logfile, append_log=True)
307 # if not GLIUtility.exitsuccess(ret):
308 # raise GLIException("PartitionResizeError", 'fatal', 'partition', "could not resize ext2/3 filesystem on " + devnode)
309 # elif type == "ntfs":
310 # ret = GLIUtility.spawn("yes | ntfsresize -v --size " + str(total_bytes) + " " + devnode, logfile=self._compile_logfile, append_log=True)
311 # if not GLIUtility.exitsuccess(ret):
312 # raise GLIException("PartitionResizeError", 'fatal', 'partition', "could not resize NTFS filesystem on " + devnode)
313 # elif type in ("linux-swap", "fat32", "fat16"):
314 # parted_fs = parted_disk.get_partition(curminor).geom.file_system_open()
315 # resize_constraint = parted_fs.get_resize_constraint()
316 # if total_sectors < resize_constraint.min_size or start != resize_constraint.start_range.start:
317 # raise GLIException("PartitionError", 'fatal', 'partition', "New size specified for " + devnode + " is not within allowed boundaries (blame parted)")
318 # new_geom = resize_constraint.start_range.duplicate()
319 # new_geom.set_start(start)
320 # new_geom.set_end(end)
321 # try:
322 # parted_fs.resize(new_geom)
323 # except:
324 # raise GLIException("PartitionResizeError", 'fatal', 'partition', "could not resize " + devnode)
325 # self._logger.log(" Deleting old minor " + str(oldpart) + " to be recreated in next pass")
326 # self._delete_partition(parted_disk, oldpart)
327 # parted_disk.delete_all()
328 # parted_disk.commit()
329
330
331 ##
332 # This function clears the partition table
333 def clear_partitions(self, disklabel=None):
334 if not disklabel:
335 disklabel = archinfo[self._arch]
336 self._parted_disk = self._parted_dev.disk_new_fresh(parted.disk_type_get(disklabel))
337 self._disklabel = disklabel
338 self._parted_disk.commit()
339 self.set_partitions_from_disk()
340
341 ##
342 # Returns an ordered list (disk order) of partitions
343 def get_partitions(self):
344 return self._partitions
345
346 ##
347 # Returns the minor of the extended partition, if any
348 def get_extended_partition(self):
349 for idx, part in enumerate(self._partitions):
350 if part.is_extended():
351 return idx
352 return -1
353
354 ##
355 # Returns the drive model
356 def get_model(self):
357 return self._parted_dev.model
358
359 ##
360 # Returns the disklabel type
361 def get_disklabel(self):
362 return self._disklabel
363
364 ##
365 # Returns all the geometry information
366 def get_geometry(self):
367 return self._geometry
368
369 ##
370 # This class represents a partition within a GLIStorageDevice object
371 class Partition:
372 "Class representing a single partition within a Device object"
373
374 ##
375 # Initialization function for the Partition class
376 # @param device Parent GLIStorageDevice object
377 # @param parted_part parted.Partition object
378 def __init__(self, device, parted_part):
379 self._device = device
380 self._start = parted_part.geom.start
381 self._end = parted_part.geom.end
382 self._type = parted_part.type_name
383 self._minor = parted_part.num
384 self._mb = float((self._end - self._start + 1) * device._geometry['sector_size'] / MEGABYTE)
385 self._part_name = ""
386 self._resizeable = False
387
388 # determine the /dev node that refers to this partition
389 tmpdevice = device.get_device()
390 label_type = device._parted_disk.type.name
391 if label_type == "loop":
392 self._devnode = tmpdevice
393 elif tmpdevice[-1] in "0123456789":
394 self._devnode = tmpdevice + "p" + str(self._minor)
395 else:
396 self._devnode = tmpdevice + str(self._minor)
397
398 if not self._type == "free":
399 if parted_part.fs_type:
400 self._type = parted_part.fs_type.name
401 if self._type == "hfs" and parted_part.is_flag_available(1) and parted_part.get_flag(1):
402 self._type = "apple_bootstrap"
403 else:
404 # Add additional partition identification code here
405 self._type = "unknown"
406 if parted_part.type == 2: self._type = "extended"
407 if device._parted_disk.type.check_feature(parted.DISK_TYPE_PARTITION_NAME):
408 self._part_name = parted_part.get_name()
409 # The 10 is completely arbitrary. If flags seem to be missed, this number should be increased
410 for flag in range(0, 10):
411 if parted_part.is_flag_available(flag) and parted_part.get_flag(flag):
412 self._flags.append(flag)
413
414 if type == "ext2" or type == "ext3":
415 block_size = long(string.strip(commands.getoutput("dumpe2fs -h " + self._devnode + r" 2>&1 | grep -e '^Block size:' | sed -e 's/^Block size:\s\+//'")))
416 free_blocks = long(string.strip(commands.getoutput("dumpe2fs -h " + self._devnode + r" 2>&1 | grep -e '^Free blocks:' | sed -e 's/^Free blocks:\s\+//'")))
417 free_bytes = long(block_size * free_blocks)
418 # can't hurt to pad (the +50) it a bit since this is really just a guess
419 self._min_size = self._mb - long(free_bytes / MEGABYTE) + 50
420 self._resizeable = True
421 elif type == "ntfs":
422 min_bytes = long(commands.getoutput("ntfsresize -f --info " + self._devnode + " | grep -e '^You might resize' | sed -e 's/You might resize at //' -e 's/ bytes or .\+//'"))
423 self._min_size = long(min_bytes / MEGABYTE) + 50
424 self._resizeable = True
425 else:
426 try:
427 parted_fs = parted_part.geom.file_system_open()
428 resize_constraint = parted_fs.get_resize_constraint()
429 min_bytes = resize_constraint.min_size * self._device._geometry['sector_size']
430 self._min_size = long(min_bytes / MEGABYTE) + 1
431 self._resizeable = True
432 except:
433 self._min_size = self._mb
434 self._resizeable = False
435
436 def __getitem__(self, name):
437 tmpdict = {
438 'start': self.get_start,
439 'end': self.get_end,
440 'type': self.get_type,
441 'minor': self.get_minor,
442 'mb': self.get_mb,
443 'flags': self.get_flags,
444 'name': self.get_name,
445 'devnode': self.get_devnode,
446 'resizeable': self.get_resizeable,
447 'min_size': self.get_min_size,
448 'max_size': self.get_max_size,
449 'extended': self.is_extended,
450 'logical': self.is_logical,
451 'device': self.get_device
452 }
453 if name in tmpdict:
454 return tmpdict[name]()
455 else:
456 raise ValueError(name + " is not a valid attribute!")
457
458 def __setitem__(self, name, value):
459 tmpdict = {
460 'flags': self.set_flags,
461 'name': self.set_name
462 }
463 if name in tmpdict:
464 tmpdict[name](value)
465 else:
466 raise ValueError(name + " is not a valid attribute!")
467
468 ##
469 # Returns the dev node that this partition will have
470 def get_devnode(self):
471 return self._devnode
472
473 ##
474 # Returns whether or not the partition is extended
475 def is_extended(self):
476 if self._type == "extended":
477 return True
478 else:
479 return False
480
481 ##
482 # Returns whether or not the partition is logical
483 def is_logical(self):
484 if self._type == "free":
485 ext_idx = self._device.get_extended_partition()
486 if ext_idx == -1: return False
487 ext_part = self._device[ext_idx]
488 if self._start >= ext_part['start'] and self._start <= ext_part['end'] and self._end >= ext_part['start'] and self._end <= ext_part['end']:
489 return True
490 else:
491 return False
492 elif self._device._labelinfo['extended'] and self._minor > 4:
493 return True
494 else:
495 return False
496
497 ##
498 # Returns a list of logical partitions if this is an extended partition
499 def get_logicals(self):
500 if not self.is_extended():
501 return None
502 logicals = []
503 for part in self._device._partitions:
504 if part.is_logical():
505 logicals.append(part)
506 return logicals
507
508 ##
509 # Returns the start sector for the partition
510 def get_start(self):
511 return long(self._start)
512
513 ##
514 # Returns end sector for the partition
515 def get_end(self):
516 return long(self._end)
517
518 ##
519 # Returns size of partition in MB
520 def get_mb(self):
521 return self._mb
522
523 ##
524 # Returns type of partition
525 def get_type(self):
526 return self._type
527
528 ##
529 # Returns parent Device object
530 def get_device(self):
531 return self._device
532
533 ##
534 # Returns minor of partition
535 def get_minor(self):
536 return self._minor
537
538 ##
539 # Returns whether the partition is resizeable
540 def get_resizeable(self):
541 return self._resizeable
542
543 ##
544 # Sets partition flags
545 def set_flags(self, flags):
546 self._flags = flags
547
548 ##
549 # Returns partition flags
550 def get_flags(self):
551 return self._flags
552
553 ##
554 # Sets partition name
555 def set_name(self, name):
556 self._name = name
557
558 ##
559 # Returns partition name
560 def get_name(self):
561 return self._name
562
563 ##
564 # Returns minimum MB for resize
565 def get_min_size(self):
566 if self._resizeable:
567 return self._min_size
568 else:
569 return self._mb
570
571 ##
572 # Returns maximum MB for resize
573 def get_max_size(self):
574 if self._resizeable:
575 partidx = self._device.get_partition_idx_from_minor(self._minor)
576 next_part = self._device._partitions[partidx + 1]
577 if next_part['type'] == "free":
578 if (next_part.is_logical() and self.is_logical()) or (not next_part.is_logical() and not self.is_logical()):
579 return self._mb + next_part['mb']
580 else:
581 return self._mb
582 else:
583 return self._mb
584 else:
585 return self._mb
586
587 ##
588 # Resizes the partition
589 # @param mb New size in MB
590 def resize(self, mb):
591 minor_pos = self._device.get_partition_idx_from_minor(self._minor)
592 try:
593 free_minor = self._device._partitions[minor_pos+1].get_minor()
594 except:
595 free_minor = 0
596 if mb < self._mb:
597 # Shrinking
598 if not free_minor or not self._device.get_partition(free_minor).get_type() == "free":
599 if self._device._disklabel == "mac":
600 free_minor = self._minor + 1
601 elif self.is_logical():
602 free_minor = self._minor + FREE_MINOR_FRAC_LOG
603 else:
604 free_minor = self._minor + FREE_MINOR_FRAC_PRI
605 if self._device.get_partition(free_minor):
606 for i, part in enumerate(self._device._partitions):
607 if i <= minor_pos or free_minor > part.get_minor(): continue
608 part.set_minor(part.get_minor() + 1)
609 self._device._partitions.insert(minor_pos+1, Partition(self._device, free_minor, self._mb - mb, 0, 0, "free", format=False, existing=False))
610 else:
611 self._device.get_partition(free_minor).set_mb(self._device.get_partition(free_minor).get_mb() + (self._mb - mb))
612 self._mb = mb
613 else:
614 if mb == self._mb + self._device.get_partition(free_minor).get_mb():
615 # Using all available unallocated space
616 self._device._partitions.pop(self._device.get_partition_idx_from_minor(free_minor))
617 self._mb = mb
618 else:
619 # Growing
620 self._device.get_partition(free_minor).set_mb(self._device.get_partition(free_minor).get_mb() - (mb - self._mb))
621 self._mb = mb
622 self._resized = True
623 self._device.tidy_partitions()
624
625 ##
626 # Returns a list of detected partitionable devices
627 def detect_devices():
628 devices = []
629
630 # Make sure sysfs exists
631 # TODO: rewrite for 2.4 support
632 if not os.path.exists("/sys/bus"):
633 raise GLIException("GLIStorageDeviceError", 'fatal', 'detect_devices', "no sysfs found (you MUST use a kernel >2.6)")
634 # Make sure /proc/partitions exists
635 if not os.path.exists("/proc/partitions"):
636 raise GLIException("GLIStorageDeviceError", 'fatal', 'detect_devices', "/proc/partitions does not exist! Please make sure procfs is in your kernel and mounted!")
637
638 # Load /proc/partitions into the variable 'partitions'
639 partitions = []
640 for line in open("/proc/partitions"):
641 tmpparts = line.split()
642 if len(tmpparts) < 4 or not tmpparts[0].isdigit() or not tmpparts[1].isdigit():
643 continue
644
645 # Get the major, minor and device name
646 major = int(tmpparts[0])
647 minor = int(tmpparts[1])
648 device = "/dev/" + tmpparts[3]
649
650 # If there is no /dev/'device_name', then scan
651 # all the devices in /dev to try and find a
652 # devices with the same major and minor
653 if not os.path.exists(device):
654 device = None
655 for path, dirs, files in os.walk("/dev"):
656 for d_file in files:
657 full_file = os.path.join(path, d_file)
658 if not os.path.exists(full_file):
659 continue
660 statres = os.stat(full_file)
661 fmaj = os.major(statres.st_rdev)
662 fmin = os.minor(statres.st_rdev)
663 if fmaj == major and fmin == minor:
664 device = full_file
665 break
666 if not device:
667 continue
668
669 partitions.append(( major, minor, device ))
670
671 # Scan sysfs for the devices of type 'x'
672 # 'x' being a member of the list below:
673 # Compaq cards.../sys/block/{cciss,ida}!cXdX/dev
674 for dev_glob in ("/sys/bus/ide/devices/*/block*/dev", "/sys/bus/scsi/devices/*/block*/dev", "/sys/block/cciss*/dev", "/sys/block/ida*/dev"):
675 sysfs_devices = glob(dev_glob)
676 if not sysfs_devices: continue
677 for sysfs_device in sysfs_devices:
678 # Get the major and minor info
679 try:
680 major, minor = open(sysfs_device).read().split(":")
681 major = int(major)
682 minor = int(minor)
683 except:
684 raise GLIException("GLIStorageDeviceError", 'fatal', 'detect_devices', "invalid major/minor in " + sysfs_device)
685
686 # Find a device listed in /proc/partitions
687 # that has the same minor and major as our
688 # current block device.
689 for record in partitions:
690 if major == record[0] and minor == record[1]:
691 devices.append(record[2])
692
693 # We have assembled the list of devices, so return it
694 return devices
695
696 def list_partitions():
697 # Load /proc/partitions into the variable 'partitions'
698 # return [("/dev/" + x[3]) for x in [y.strip().split() for y in open("/proc/partitions", "r").readlines()] if len(x) >= 4 and x[3][-1].isdigit()]
699 partitions = {}
700 for line in open("/proc/partitions"):
701 tmpparts = line.split()
702 if len(tmpparts) < 4 or not tmpparts[0].isdigit() or not tmpparts[1].isdigit():
703 continue
704 device = "/dev/" + tmpparts[3]
705 if device == "/dev/loop0": #we don't want this.
706 continue
707 if not device[-1].isdigit(): #A Drive
708 continue
709 else:
710 partitions[device] = tmpparts[2]
711 return partitions
712
713 def wait_for_device_node(devnode):
714 if GLIUtility.is_file("/sbin/udevsettle"):
715 GLIUtility.spawn("/sbin/udevsettle")
716 if not GLIUtility.is_file(devnode):
717 GLIUtility.spawn("/sbin/udevsettle")
718 else:
719 for i in range(0, 10):
720 if GLIUtility.is_file(devnode):
721 break
722 time.sleep(1)
723 time.sleep(1)
724 for i in range(0, 10):
725 if GLIUtility.is_file(devnode):
726 break
727 time.sleep(1)

Properties

Name Value
svn:eol-style native

  ViewVC Help
Powered by ViewVC 1.1.20