/[gli]/trunk/src/GLIStorageDevice.py
Gentoo

Diff of /trunk/src/GLIStorageDevice.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 596 Revision 1040
1# Copyright 1999-2005 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
1import commands, string, os, parted 6import commands, string, os, parted
2from GLIException import * 7from GLIException import *
3import GLIUtility 8import GLIUtility
4 9
5MEGABYTE = 1024 * 1024 10MEGABYTE = 1024 * 1024
6 11
12# these are here so that we can change them easily in future
13# the values were chosen to represent perfect floating point representations
14FREE_MINOR_FRAC_PRI = 1.0/32.0
15FREE_MINOR_FRAC_LOG = 1.0/8.0
16
7archinfo = { 'sparc': { 'fixedparts': [ { 'minor': 3, 'type': "wholedisk" } ], 'disklabel': 'sun', 'extended': False }, 17archinfo = { 'sparc': { 'fixedparts': [ { 'minor': 3, 'type': "wholedisk" } ], 'disklabel': 'sun', 'extended': False },
8 'hppa': { 'fixedparts': [ { 'minor': 1, 'type': "boot" } ], 'disklabel': 'msdos', 'extended': False }, 18 'hppa': { 'fixedparts': [ { 'minor': 1, 'type': "palo" } ], 'disklabel': 'msdos', 'extended': True },
9 'x86': { 'fixedparts': [], 'disklabel': 'msdos', 'extended': True }, 19 'x86': { 'fixedparts': [], 'disklabel': 'msdos', 'extended': True },
10 'amd64': { 'fixedparts': [], 'disklabel': 'msdos', 'extended': True }, 20 'amd64': { 'fixedparts': [], 'disklabel': 'msdos', 'extended': True },
11 'ppc': { 'fixedparts': [ { 'minor': 1, 'type': "metadata" } ], 'disklabel': 'mac', 'extended': False } 21 'ppc': { 'fixedparts': [ { 'minor': 1, 'type': "metadata" } ], 'disklabel': 'mac', 'extended': False }
12 } 22 }
13 23
32 42
33 ## 43 ##
34 # Initialization function for GLIStorageDevice class 44 # Initialization function for GLIStorageDevice class
35 # @param device Device node (e.g. /dev/hda) of device being represented 45 # @param device Device node (e.g. /dev/hda) of device being represented
36 # @param arch="x86" Architecture that we're partition for (defaults to 'x86' for now) 46 # @param arch="x86" Architecture that we're partition for (defaults to 'x86' for now)
37 def __init__(self, device, arch="x86", set_geometry=True): 47 def __init__(self, device, arch="x86", set_geometry=True, virtual=False, local_device=True):
38 self._device = device 48 self._device = device
39 self._partitions = {} 49 self._partitions = {}
40 self._geometry = {'cylinders': 0, 'heads': 0, 'sectors': 0, 'sectorsize': 512} 50 self._geometry = {'cylinders': 0, 'heads': 0, 'sectors': 0, 'sectorsize': 512}
41 self._total_bytes = 0 51 self._total_bytes = 0
42 self._cylinder_bytes = 0 52 self._cylinder_bytes = 0
43 self._arch = arch 53 self._arch = arch
54 self._local_device = local_device
55 if self._local_device:
44 self._parted_dev = parted.PedDevice.get(self._device) 56 self._parted_dev = parted.PedDevice.get(self._device)
45 try: 57 try:
46 self._parted_disk = parted.PedDisk.new(self._parted_dev) 58 self._parted_disk = parted.PedDisk.new(self._parted_dev)
47 except: 59 except:
48 self._parted_disk = self._parted_dev.disk_new_fresh(parted.disk_type_get(archinfo[self._arch]['disklabel'])) 60 self._parted_disk = self._parted_dev.disk_new_fresh(parted.disk_type_get(archinfo[self._arch]['disklabel']))
49 self._disklabel = self._parted_disk.type.name 61 self._disklabel = self._parted_disk.type.name
62 else:
63 self._disklabel = archinfo[self._arch]['disklabel']
50 if set_geometry: 64 if set_geometry:
51 self.set_disk_geometry_from_disk() 65 self.set_disk_geometry_from_disk()
52 66
53 ## 67 ##
54 # Sets disk geometry info from disk. This function is used internally by __init__() 68 # Sets disk geometry info from disk. This function is used internally by __init__()
57 self._geometry['heads'], self._geometry['sectors'], self._geometry['cylinders'] = self._parted_dev.heads, self._parted_dev.sectors, self._parted_dev.cylinders 71 self._geometry['heads'], self._geometry['sectors'], self._geometry['cylinders'] = self._parted_dev.heads, self._parted_dev.sectors, self._parted_dev.cylinders
58 self._sector_bytes = self._parted_dev.sector_size 72 self._sector_bytes = self._parted_dev.sector_size
59 self._cylinder_bytes = self._geometry['heads'] * self._geometry['sectors'] * self._sector_bytes 73 self._cylinder_bytes = self._geometry['heads'] * self._geometry['sectors'] * self._sector_bytes
60 self._total_sectors = self._parted_dev.length 74 self._total_sectors = self._parted_dev.length
61 self._sectors_in_cylinder = self._geometry['heads'] * self._geometry['sectors'] 75 self._sectors_in_cylinder = self._geometry['heads'] * self._geometry['sectors']
62 self._total_mb = int(self._total_bytes / MEGABYTE) 76 self._total_mb = long(self._total_bytes / MEGABYTE)
63 77
64 ## 78 ##
65 # Sets partition info from disk. 79 # Sets partition info from disk.
66 def set_partitions_from_disk(self): 80 def set_partitions_from_disk(self):
67 last_part = 0 81 last_part = 0
68 last_log_part = 4 82 last_log_part = 4
69 parted_part = self._parted_disk.next_partition() 83 parted_part = self._parted_disk.next_partition()
70 while parted_part: 84 while parted_part:
71 part_mb = int((parted_part.geom.end - parted_part.geom.start + 1) * self._sector_bytes / MEGABYTE) 85 part_mb = long((parted_part.geom.end - parted_part.geom.start + 1) * self._sector_bytes / MEGABYTE)
72 if parted_part.num >= 1: 86 if parted_part.num >= 1:
73 fs_type = "" 87 fs_type = ""
74 if parted_part.fs_type != None: fs_type = parted_part.fs_type.name 88 if parted_part.fs_type != None: fs_type = parted_part.fs_type.name
75 if parted_part.type == 2: fs_type = "extended" 89 if parted_part.type == 2: fs_type = "extended"
76 if archinfo[self._arch]['extended'] and parted_part.num > 4: 90 if archinfo[self._arch]['extended'] and parted_part.num > 4:
77 last_log_part = parted_part.num 91 last_log_part = parted_part.num
78 else: 92 else:
79 last_part = parted_part.num 93 last_part = parted_part.num
80 self._partitions[int(parted_part.num)] = Partition(self, parted_part.num, part_mb, parted_part.geom.start, parted_part.geom.end, fs_type, format=False, existing=True) 94 self._partitions[int(parted_part.num)] = Partition(self, parted_part.num, part_mb, parted_part.geom.start, parted_part.geom.end, fs_type, format=False, existing=True)
81 elif parted_part.type_name == "free": 95 elif parted_part.type_name == "free":
82 parent_part = self.get_partition_at(parted_part.geom.start, ignore_extended=0) 96# parent_part = self.get_partition_at(parted_part.geom.start, ignore_extended=0)
83 if parent_part: 97# if parent_part:
98 if self.get_extended_partition() and parted_part.geom.start >= self._partitions[self.get_extended_partition()].get_start() and parted_part.geom.end <= self._partitions[self.get_extended_partition()].get_end():
84 self._partitions[last_log_part+0.9] = Partition(self, last_log_part+0.9, part_mb, parted_part.geom.start, parted_part.geom.end, "free", format=False, existing=False) 99 self._partitions[last_log_part+FREE_MINOR_FRAC_LOG] = Partition(self, last_log_part+FREE_MINOR_FRAC_LOG, part_mb, parted_part.geom.start, parted_part.geom.end, "free", format=False, existing=False)
85 last_log_part += 1 100 last_log_part += 1
86 else: 101 else:
87 self._partitions[last_part+0.1] = Partition(self, last_part+0.1, part_mb, parted_part.geom.start, parted_part.geom.end, "free", format=False, existing=False) 102 self._partitions[last_part+FREE_MINOR_FRAC_PRI] = Partition(self, last_part+FREE_MINOR_FRAC_PRI, part_mb, parted_part.geom.start, parted_part.geom.end, "free", format=False, existing=False)
88 last_part += 1 103 last_part += 1
89 parted_part = self._parted_disk.next_partition(parted_part) 104 parted_part = self._parted_disk.next_partition(parted_part)
90 105
91 ## 106 ##
92 # Imports partition info from the install profile partition structure (currently does nothing) 107 # Imports partition info from the install profile partition structure
93 # @param ips Parameter structure returned from install_profile.get_partition_tables() 108 # @param ips Parameter structure returned from install_profile.get_partition_tables()
94 def set_partitions_from_install_profile_structure(self, ips): 109 def set_partitions_from_install_profile_structure(self, ips):
95 for part in ips: 110 for part in ips:
96 tmppart = ips[part] 111 tmppart = ips[part]
97 existing = False 112 existing = False
98 if tmppart['origminor'] and not tmppart['format']: 113 if tmppart['origminor'] and not tmppart['format']:
99 existing = True 114 existing = True
100 self._partitions[tmppart['minor']] = Partition(self, tmppart['minor'], tmppart['mb'], tmppart['start'], tmppart['end'], tmppart['type'], format=tmppart['format'], origminor=tmppart['origminor'], existing=existing, mountpoint=tmppart['mountpoint'], mountopts=['mountopts']) 115 self._partitions[tmppart['minor']] = Partition(self, tmppart['minor'], tmppart['mb'], tmppart['start'], tmppart['end'], tmppart['type'], format=tmppart['format'], origminor=tmppart['origminor'], existing=existing, mountpoint=tmppart['mountpoint'], mountopts=tmppart['mountopts'], mkfsopts=tmppart['mkfsopts'])
101 116
102 ## 117 ##
103 # Returns name of device (e.g. /dev/hda) being represented 118 # Returns name of device (e.g. /dev/hda) being represented
104 def get_device(self): 119 def get_device(self):
105 return self._device 120 return self._device
121
122 ##
123 # Uses magic to apply the recommended partition layout
124 def do_recommended(self):
125 free_minor = 0
126 recommended_parts = [ { 'type': "ext2", 'size': 100, 'mountpoint': "/boot" },
127 { 'type': "linux-swap", 'size': 512, 'mountpoint': "" },
128 { 'type': "ext3", 'size': "*", 'mountpoint': "/" } ]
129 to_create = []
130 physical_memory = int(GLIUtility.spawn(r"free -m | egrep '^Mem:' | sed -e 's/^Mem: \+//' -e 's/ \+.\+$//'", return_output=True)[1].strip())
131 parts = self.get_ordered_partition_list()
132 for part in parts:
133 if self._partitions[part].get_type() == "free" and self._partitions[part].get_mb() >= 4096:
134 free_minor = part
135 break
136 if not free_minor:
137 raise GLIException("RecommendedPartitionLayoutError", "notice", "do_recommended", "You do not have atleast 4GB of concurrent unallocated space. Please remove some partitions and try again.")
138 remaining_free = self._partitions[free_minor].get_mb()
139 for newpart in recommended_parts:
140 if archinfo[self._arch]['extended'] and free_minor == (3 + FREE_MINOR_FRAC_PRI) and not newpart == recommended_parts[-1]:
141 if self.get_extended_partition():
142 raise GLIException("RecommendedPartitionLayoutError", "notice", "do_recommended", "This code is not yet robust enough to handle automatic partitioning with your current layout.")
143 to_create.append({ 'type': "extended", 'size': remaining_free, 'mountpoint': "", 'free_minor': free_minor })
144 free_minor = 4 + FREE_MINOR_FRAC_LOG
145 newpart['free_minor'] = free_minor
146 if newpart['type'] == "linux-swap" and physical_memory and physical_memory < 1024:
147 newpart['size'] = physical_memory * 2
148 to_create.append(newpart)
149 free_minor = free_minor + 1
150 if not newpart['size'] == "*":
151 remaining_free = remaining_free - newpart['size']
152 for newpart in to_create:
153 if newpart['size'] == "*":
154 newpart['size'] = self._partitions[newpart['free_minor']].get_mb()
155 self.add_partition(newpart['free_minor'], newpart['size'], 0, 0, newpart['type'], mountpoint=newpart['mountpoint'])
106 156
107 ## 157 ##
108 # Combines free space and closes gaps in minor numbers. This is used internally 158 # Combines free space and closes gaps in minor numbers. This is used internally
109 def tidy_partitions(self): 159 def tidy_partitions(self):
110 last_minor = 0 160 last_minor = 0
116 for part in parts: 166 for part in parts:
117 if archinfo[self._arch]['extended'] and part > 4: break 167 if archinfo[self._arch]['extended'] and part > 4: break
118 tmppart = self._partitions[part] 168 tmppart = self._partitions[part]
119 if tmppart.get_type() == "extended": 169 if tmppart.get_type() == "extended":
120 for part_log in parts: 170 for part_log in parts:
121 if part_log < 4.9: continue 171 if part_log < (4 + FREE_MINOR_FRAC_LOG): continue
122 tmppart_log = self._partitions[part_log] 172 tmppart_log = self._partitions[part_log]
123 if tmppart_log.get_type() == "free": 173 if tmppart_log.get_type() == "free":
124 if last_log_minor < last_log_free: 174 if last_log_minor < last_log_free:
125 self._partitions[last_log_free].set_mb(self._partitions[last_log_free].get_mb()+tmppart_log.get_mb()) 175 self._partitions[last_log_free].set_mb(self._partitions[last_log_free].get_mb()+tmppart_log.get_mb())
126 del self._partitions[part_log] 176 del self._partitions[part_log]
127 else: 177 else:
128 if not last_log_free: 178 if not last_log_free:
129 last_log_free = last_log_minor + 0.9 179 last_log_free = last_log_minor + FREE_MINOR_FRAC_LOG
130 else: 180 else:
131 lost_log_free = part_log 181 last_log_free = part_log
132 tmppart_log.set_minor(last_log_free) 182 tmppart_log.set_minor(last_log_free)
133 self._partitions[last_log_free] = tmppart_log 183 self._partitions[last_log_free] = tmppart_log
134 if part_log != last_log_free: del self._partitions[part_log] 184 if part_log != last_log_free: del self._partitions[part_log]
135 continue
136 else: 185 else:
137 if part_log > (last_log_minor + 1): 186 if part_log > (last_log_minor + 1):
138 tmppart_log.set_minor(last_log_minor + 1) 187 tmppart_log.set_minor(last_log_minor + 1)
139 last_log_minor = last_log_minor + 1 188 last_log_minor = last_log_minor + 1
140 self._partitions[last_log_minor] = tmppart_log 189 self._partitions[last_log_minor] = tmppart_log
141 del self._partitions[part_log] 190 del self._partitions[part_log]
142 continue
143 else: 191 else:
144 last_log_minor = part_log 192 last_log_minor = part_log
145 if tmppart.get_type() == "free": 193 elif tmppart.get_type() == "free":
146 if last_minor < last_free: 194 if last_minor < last_free:
147 self._partitions[last_free].set_mb(self._partitions[last_free].get_mb()+tmppart.get_mb()) 195 self._partitions[last_free].set_mb(self._partitions[last_free].get_mb()+tmppart.get_mb())
148 del self._partitions[part] 196 del self._partitions[part]
149 else: 197 else:
150 if not last_free: 198 if not last_free:
151 last_free = last_minor + 0.1 199 last_free = last_minor + FREE_MINOR_FRAC_PRI
152 else: 200 else:
153 last_free = part 201 last_free = part
154 tmppart.set_minor(last_free) 202 tmppart.set_minor(last_free)
155 self._partitions[last_free] = tmppart 203 self._partitions[last_free] = tmppart
156 if part != last_free: del self._partitions[part] 204 if part != last_free: del self._partitions[part]
157 continue
158 else: 205 else:
159 if part > (last_minor + 1): 206 if part > (last_minor + 1):
160 tmppart.set_minor(last_minor + 1) 207 tmppart.set_minor(last_minor + 1)
161 last_minor = last_minor + 1 208 last_minor = last_minor + 1
162 self._partitions[last_minor] = tmppart 209 self._partitions[last_minor] = tmppart
163 del self._partitions[part] 210 del self._partitions[part]
164 continue
165 else: 211 else:
166 last_minor = part 212 last_minor = part
167 213
168 ## 214 ##
169 # Adds a new partition to the partition info 215 # Adds a new partition to the partition info
172 # @param start Start sector (only used for existing partitions) 218 # @param start Start sector (only used for existing partitions)
173 # @param end End sector (only used for existing partitions) 219 # @param end End sector (only used for existing partitions)
174 # @param type Partition type (ext2, ext3, fat32, linux-swap, free, extended, etc.) 220 # @param type Partition type (ext2, ext3, fat32, linux-swap, free, extended, etc.)
175 # @param mountpoint='' Partition mountpoint 221 # @param mountpoint='' Partition mountpoint
176 # @param mountopts='' Partition mount options 222 # @param mountopts='' Partition mount options
223 # @param mkfsopts='' Additional mkfs options
177 def add_partition(self, free_minor, mb, start, end, type, mountpoint='', mountopts=''): 224 def add_partition(self, free_minor, mb, start, end, type, mountpoint='', mountopts='',mkfsopts=''):
178 free_minor = free_minor 225 if free_minor == -1:
226 tmpparts = self._partitions.keys()
227 tmpparts.sort()
228 tmpminor = 0
229 if len(tmpparts):
230 tmpminor = tmpparts[-1]
231 if archinfo[self._arch]['extended'] and tmpminor >= 5:
232 free_minor = tmpminor + FREE_MINOR_FRAC_LOG
233 else:
234 free_minor = tmpminor + FREE_MINOR_FRAC_PRI
235 self._partitions[free_minor] = Partition(self, free_minor, mb, 0, 0, "free")
179 new_minor = int(free_minor) + 1 236 new_minor = int(free_minor) + 1
180# print "add_partition(): free_minor=" + str(free_minor) + ", new_minor=" + str(new_minor)
181 if self._partitions.has_key(new_minor): 237 if self._partitions.has_key(new_minor):
182 parts = self._partitions.keys() 238 parts = self._partitions.keys()
183 parts.sort() 239 parts.sort()
184 parts.reverse() 240 parts.reverse()
185 hole_at = 0 241 hole_at = 0
198 if i == new_minor: stopscooting = 1 254 if i == new_minor: stopscooting = 1
199 if mb != self._partitions[free_minor].get_mb(): 255 if mb != self._partitions[free_minor].get_mb():
200 old_free_mb = self._partitions[free_minor].get_mb() 256 old_free_mb = self._partitions[free_minor].get_mb()
201 del self._partitions[free_minor] 257 del self._partitions[free_minor]
202 if archinfo[self._arch]['extended'] and new_minor >= 5: 258 if archinfo[self._arch]['extended'] and new_minor >= 5:
203 free_minor = new_minor + 0.9 259 free_minor = new_minor + FREE_MINOR_FRAC_LOG
204 else: 260 else:
205 free_minor = new_minor + 0.1 261 free_minor = new_minor + FREE_MINOR_FRAC_PRI
206 self._partitions[free_minor] = Partition(self, free_minor, old_free_mb-mb, 0, 0, "free") 262 self._partitions[free_minor] = Partition(self, free_minor, old_free_mb-mb, 0, 0, "free")
207# print "add_partition(): new part doesn't use all freespace. new free part is: minor=" + str(free_minor)
208 else: 263 else:
209 del self._partitions[free_minor] 264 del self._partitions[free_minor]
210 self._partitions[new_minor] = Partition(self, new_minor, mb, start, end, type, mountpoint=mountpoint, mountopts=mountopts) 265 self._partitions[new_minor] = Partition(self, new_minor, mb, start, end, type, mountpoint=mountpoint, mountopts=mountopts,mkfsopts=mkfsopts)
211 if type == "extended": 266 if type == "extended":
212 self._partitions[4.9] = Partition(self, 4.9, mb, 0, 0, "free") 267 self._partitions[4 + FREE_MINOR_FRAC_LOG] = Partition(self, (4 + FREE_MINOR_FRAC_LOG), mb, 0, 0, "free")
213 self.tidy_partitions() 268 self.tidy_partitions()
269 return new_minor
214 270
215 ## 271 ##
216 # Removes partition from partition info 272 # Removes partition from partition info
217 # @param minor Minor of partition to remove 273 # @param minor Minor of partition to remove
218 def remove_partition(self, minor): 274 def remove_partition(self, minor):
219 tmppart = self._partitions[int(minor)] 275 tmppart = self._partitions[int(minor)]
220 free_minor = 0 276 free_minor = 0
221 if tmppart.is_logical(): 277 if tmppart.is_logical():
222 free_minor = minor-0.1 278 free_minor = int(minor-1)+FREE_MINOR_FRAC_LOG
223 else: 279 else:
224 free_minor = minor-0.9 280 free_minor = int(minor-1)+FREE_MINOR_FRAC_PRI
281 if free_minor in self._partitions:
282 self._partitions[free_minor].set_mb(self._partitions[free_minor].get_mb() + tmppart.get_mb())
283 else:
225 self._partitions[free_minor] = Partition(self, free_minor, tmppart.get_mb(), 0, 0, "free", format=False, existing=False) 284 self._partitions[free_minor] = Partition(self, free_minor, tmppart.get_mb(), 0, 0, "free", format=False, existing=False)
226 del self._partitions[int(minor)] 285 del self._partitions[int(minor)]
227 self.tidy_partitions() 286 self.tidy_partitions()
228 287
229 ## 288 ##
230 # Returns free space (no longer used) 289 # This function clears the partition table
231 # @param start Start sector for search 290 def clear_partitions(self):
232 def get_free_space(self, start): 291# parts = self._partitions.keys()
233 GAP_SIZE = 100 292# parts.sort()
293# parts.reverse()
294# for part in parts:
295# if not self._partitions[part].get_type() == "free":
296# self.remove_partition(part)
297 self._partitions = { (0 + FREE_MINOR_FRAC_PRI): Partition(self, (0 + FREE_MINOR_FRAC_PRI), self.get_total_mb(), 0, 0, "free", format=False, existing=False) }
298
299 ##
300 # Returns an ordered list (disk order) of partition minors
301 def get_ordered_partition_list(self):
234 parts = self._partitions.keys() 302 parts = self._partitions.keys()
235 parts.sort() 303 parts.sort()
236 lastend_pri = 0 304 partlist = []
237 lastend_log = 0
238 free_start = -1
239 free_end = -1
240 if start > self._total_sectors: return (-1, -1)
241 for part in parts:
242 if part > 4: break
243 tmppart = self._partitions[part]
244 if (tmppart.get_start() > (lastend_pri + GAP_SIZE)) and (lastend_pri >= start):
245 free_start = lastend_pri
246 free_end = tmppart.get_start() - 1
247 break
248 if tmppart.is_extended() and start < tmppart.get_end():
249 lastend_log = tmppart.get_start()
250 for part_log in parts:
251 if part_log < 5: continue
252 tmppart_log = self._partitions[part_log]
253 if (tmppart_log.get_start() > (lastend_log + GAP_SIZE)) and (lastend_log >= start):
254 free_start = lastend_log
255 free_end = tmppart_log.get_start() - 1
256 break
257 lastend_log = tmppart_log.get_end() + 1
258 if free_start == -1 and lastend_log < tmppart.get_end():
259 free_start = lastend_log
260 free_end = tmppart.get_end()
261 break
262 lastend_pri = tmppart.get_end() + 1
263 if free_start == -1 and lastend_pri < self._total_sectors:
264 free_start = lastend_pri
265 free_end = self._total_sectors
266 return (free_start, free_end)
267
268 ##
269 # Gets partition containing a certain sector (no longer used)
270 # @param sector Sector to look at
271 # @param ignore_extended=1 Ignore extended partitions
272 def get_partition_at(self, sector, ignore_extended=1):
273 parts = self._partitions.keys()
274 parts.sort()
275 for part in parts:
276 tmppart = self._partitions[part]
277 if ignore_extended and tmppart.is_extended(): continue
278 if (sector >= tmppart.get_start()) and (sector <= tmppart.get_end()):
279 return part
280 return 0
281
282 ##
283 # Returns free minor (no longer used)
284 # @param start Parameter description
285 # @param end Parameter description
286 def get_free_minor_at(self, start, end):
287 parts = self._partitions.keys()
288 parts.sort()
289 minor = 1
290 lastpart = 0
291 for part in parts:
292 if part > 4: break
293 tmppart = self._partitions[part]
294 if end < tmppart.get_start():
295 minor = part
296 if (minor - 1) > lastpart: minor = lastpart + 1
297 break
298 if tmppart.is_extended() and start < tmppart.get_end():
299 minor = 5
300 lastpart = 4
301 for part_log in parts:
302 if part_log < 5: continue
303 tmppart_log = self._partitions[part_log]
304 if end < tmppart_log.get_start():
305 minor = part_log
306 if (minor - 1) > lastpart: minor = lastpart + 1
307 break
308 minor = part_log + 1
309 lastpart = part_log
310 break
311 minor = part + 1
312 lastpart = part
313 return minor
314
315 ##
316 # Returns an ordered list (disk order) of partition minors
317 def get_ordered_partition_list(self):
318 parts = self._partitions.keys()
319 parts.sort()
320 partlist = []
321 tmppart = None 305 tmppart = None
322 for part in parts: 306 for part in parts:
323 if archinfo[self._arch]['extended'] and part > 4.1: break 307 if archinfo[self._arch]['extended'] and part > (4 + FREE_MINOR_FRAC_PRI): break
324 tmppart = self._partitions[part] 308 tmppart = self._partitions[part]
325 partlist.append(part) 309 partlist.append(part)
326 if tmppart.is_extended(): 310 if tmppart.is_extended():
327 for part_log in parts: 311 for part_log in parts:
328 if part_log < 4.9: continue 312 if part_log < (4 + FREE_MINOR_FRAC_LOG): continue
329 partlist.append(part_log) 313 partlist.append(part_log)
330 return partlist 314 return partlist
331 315
332 ## 316 ##
333 # Returns partition info in a format suitable for passing to install_profile.set_partition_tables() 317 # Returns partition info in a format suitable for passing to install_profile.set_partition_tables()
334 def get_install_profile_structure(self): 318 def get_install_profile_structure(self):
335 devdic = {} 319 devdic = {}
336 for part in self._partitions: 320 for part in self._partitions:
337 tmppart = self._partitions[part] 321 tmppart = self._partitions[part]
338 devdic[part] = { 'mb': tmppart.get_mb(), 'minor': float(part), 'origminor': tmppart.get_orig_minor(), 'start': tmppart.get_start(), 'end': tmppart.get_end(), 'type': tmppart.get_type(), 'mountpoint': tmppart.get_mountpoint(), 'mountopts': tmppart.get_mountopts(), 'format': tmppart.get_format() } 322 devdic[part] = { 'mb': tmppart.get_mb(), 'minor': float(part), 'origminor': tmppart.get_orig_minor(), 'type': tmppart.get_type(), 'mountpoint': tmppart.get_mountpoint(), 'mountopts': tmppart.get_mountopts(), 'format': tmppart.get_format(), 'mkfsopts': tmppart.get_mkfsopts(), 'start': 0, 'end': 0 }
339 return devdic 323 return devdic
340 324
341 ## 325 ##
342 # Returns the minor of the extended partition, if any 326 # Returns the minor of the extended partition, if any
343 def get_extended_partition(self): 327 def get_extended_partition(self):
346 if tmppart.is_extended(): 330 if tmppart.is_extended():
347 return part 331 return part
348 return 0 332 return 0
349 333
350 ## 334 ##
335 # Returns the drive model
336 def get_model(self):
337 if self._local_device:
338 return self._parted_dev.model
339 else:
340 return "Generic disk"
341
342 ##
351 # Sets the disklabel type 343 # Sets the disklabel type
352 def set_disklabel(self, disklabel): 344 def set_disklabel(self, disklabel):
353 self._disklabel = disklabel 345 self._disklabel = disklabel
354 346
355 ## 347 ##
358 return self._disklabel 350 return self._disklabel
359 351
360 ## 352 ##
361 # Returns the number of sectors on the device 353 # Returns the number of sectors on the device
362 def get_num_sectors(self): 354 def get_num_sectors(self):
363 return int(self._total_sectors) 355 return long(self._total_sectors)
364 356
365 ## 357 ##
366 # Returns the size of a cylinder in bytes 358 # Returns the size of a cylinder in bytes
367 def get_cylinder_size(self): 359 def get_cylinder_size(self):
368 return int(self._cylinder_bytes) 360 return long(self._cylinder_bytes)
369 361
370 ## 362 ##
371 # Returns the size of a sector in bytes 363 # Returns the size of a sector in bytes
372 def get_sector_size(self): 364 def get_sector_size(self):
373 return int(self._sector_bytes) 365 return long(self._sector_bytes)
374 366
375 ## 367 ##
376 # Returns the number of cylinders 368 # Returns the number of cylinders
377 def get_num_cylinders(self): 369 def get_num_cylinders(self):
378 return int(self._geometry['cylinders']) 370 return long(self._geometry['cylinders'])
379 371
380 ## 372 ##
381 # Returns the total number of bytes on the device 373 # Returns the total number of bytes on the device
382 def get_drive_bytes(self): 374 def get_drive_bytes(self):
383 return int(self._total_bytes) 375 return long(self._total_bytes)
384 376
385 ## 377 ##
386 # Returns the total number of MB on the device 378 # Returns the total number of MB on the device
387 def get_total_mb(self): 379 def get_total_mb(self):
380 if self._local_device:
388 return self._total_mb 381 return self._total_mb
382 else:
383 total_mb = 0
384 for tmppart in self._partitions:
385 total += tmppart.get_mb()
386 return total_mb
389 387
390 ## 388 ##
391 # Returns partition info dictionary 389 # Returns partition info dictionary
392 def get_partitions(self): 390 def get_partitions(self):
393 return self._partitions 391 return self._partitions
394 392
395 ## 393 ##
396 # Prints disk geometry to STDOUT (no longer used) 394 # Prints disk geometry to STDOUT (no longer used)
397 def print_geometry(self): 395 def print_geometry(self):
398 print self._total_bytes, self._geometry 396 print self._total_bytes, self._geometry
399
400 ##
401 # Utility function for running a command and returning it's output as a list
402 # @param cmd Command to run
403 def _run(self, cmd):
404 "Runs a command and returns the output"
405
406 # Run command
407 output_string = commands.getoutput(cmd)
408
409 # What we will return
410 output_list = []
411
412 # As long as there is a new line in the output_string
413 while output_string.find("\n") != -1:
414
415 # Find the \n in the string
416 index = output_string.find("\n") + 1
417
418 # Add the line to the output and remove it from
419 # the output_string
420 output_list.append(output_string[:index])
421 output_string = output_string[index:]
422
423 # return output
424 return output_list
425 397
426## 398##
427# This class represents a partition within a GLIStorageDevice object 399# This class represents a partition within a GLIStorageDevice object
428class Partition: 400class Partition:
429 "Class representing a single partition within a Device object" 401 "Class representing a single partition within a Device object"
438 _mountopts = None 410 _mountopts = None
439 _format = None 411 _format = None
440 _resizeable = None 412 _resizeable = None
441 _min_mb_for_resize = 0 413 _min_mb_for_resize = 0
442 _mb = 0 414 _mb = 0
415 _mkfsopts = None
443 416
444 ## 417 ##
445 # Initialization function for the Partition class 418 # Initialization function for the Partition class
446 # @param device Parent GLIStorageDevice object 419 # @param device Parent GLIStorageDevice object
447 # @param minor Minor of partition 420 # @param minor Minor of partition
449 # @param start Parameter Start sector of partition 422 # @param start Parameter Start sector of partition
450 # @param end Parameter Start sector of partition 423 # @param end Parameter Start sector of partition
451 # @param type Parameter Type of partition (ext2, ext3, fat32, linux-swap, free, extended, etc.) 424 # @param type Parameter Type of partition (ext2, ext3, fat32, linux-swap, free, extended, etc.)
452 # @param mountpoint='' Mountpoint of partition 425 # @param mountpoint='' Mountpoint of partition
453 # @param mountopts='' Mount options of partition 426 # @param mountopts='' Mount options of partition
427 # @param mkfsopts='' Additional mkfs options
454 # @param format=True Format partition 428 # @param format=True Format partition
455 # @param existing=False This partition exists on disk 429 # @param existing=False This partition exists on disk
456 def __init__(self, device, minor, mb, start, end, type, mountpoint='', mountopts='', format=True, existing=False, origminor=0): 430 def __init__(self, device, minor, mb, start, end, type, mountpoint='', mountopts='', format=True, existing=False, origminor=0, mkfsopts=''):
457 self._device = device 431 self._device = device
458 self._minor = float(minor) 432 self._minor = float(minor)
459 self._start = int(start) 433 self._start = long(start)
460 self._end = int(end) 434 self._end = long(end)
461 self._type = type or "unknown" 435 self._type = type or "unknown"
462 self._mountpoint = mountpoint 436 self._mountpoint = mountpoint
463 self._mountopts = mountopts 437 self._mountopts = mountopts
464 self._format = format 438 self._format = format
465 self._mb = mb 439 self._mb = mb
466 self._orig_minor = origminor 440 self._orig_minor = origminor
441 self._mkfsopts = mkfsopts
467 if type != "free": 442 if type != "free":
468 if existing and not origminor: 443 if existing and not origminor:
469 self._orig_minor = self._minor 444 self._orig_minor = self._minor
470 self._minor = int(self._minor) 445 self._minor = int(self._minor)
471 self._orig_minor = int(self._orig_minor) 446 self._orig_minor = int(self._orig_minor)
472 if existing: 447 if existing:
448 try:
473 parted_part = device._parted_disk.get_partition(self._orig_minor) 449 parted_part = device._parted_disk.get_partition(self._orig_minor)
474 label_type = device._parted_disk.type.name 450 label_type = device._parted_disk.type.name
475 if label_type == "loop": 451 if label_type == "loop":
476 dev_node = device._device 452 dev_node = device._device
477 else: 453 else:
478 dev_node = device._device + str(self._orig_minor) 454 dev_node = device._device + str(self._orig_minor)
479 print "dev_node = " + dev_node 455# print "dev_node = " + dev_node
480 if type == "ntfs": 456 if type == "ntfs":
481 min_bytes = int(commands.getoutput("ntfsresize -f --info " + dev_node + " | grep -e '^You might resize' | sed -e 's/You might resize at //' -e 's/ bytes or .\+//'")) 457 min_bytes = long(commands.getoutput("ntfsresize -f --info " + dev_node + " | grep -e '^You might resize' | sed -e 's/You might resize at //' -e 's/ bytes or .\+//'"))
482 self._min_mb_for_resize = int(min_bytes / MEGABYTE) + 1 458 self._min_mb_for_resize = long(min_bytes / MEGABYTE) + 1
483 self._resizeable = True 459 self._resizeable = True
484 elif type == "ext2" or type == "ext3": 460 elif type == "ext2" or type == "ext3":
485 block_size = int(string.strip(commands.getoutput("dumpe2fs -h " + dev_node + r" 2>&1 | grep -e '^Block size:' | sed -e 's/^Block size:\s\+//'"))) 461 block_size = long(string.strip(commands.getoutput("dumpe2fs -h " + dev_node + r" 2>&1 | grep -e '^Block size:' | sed -e 's/^Block size:\s\+//'")))
486 free_blocks = int(string.strip(commands.getoutput("dumpe2fs -h " + dev_node + r" 2>&1 | grep -e '^Free blocks:' | sed -e 's/^Free blocks:\s\+//'"))) 462 free_blocks = long(string.strip(commands.getoutput("dumpe2fs -h " + dev_node + r" 2>&1 | grep -e '^Free blocks:' | sed -e 's/^Free blocks:\s\+//'")))
487 free_bytes = int(block_size * free_blocks) 463 free_bytes = long(block_size * free_blocks)
488 # can't hurt to pad (the +50) it a bit since this is really just a guess 464 # can't hurt to pad (the +50) it a bit since this is really just a guess
489 self._min_mb_for_resize = self._mb - int(free_bytes / MEGABYTE) + 50 465 self._min_mb_for_resize = self._mb - long(free_bytes / MEGABYTE) + 50
490 self._resizeable = True 466 self._resizeable = True
491 else: 467 else:
492 parted_part = self._device._parted_disk.get_partition(int(self._orig_minor)) 468 parted_part = self._device._parted_disk.get_partition(int(self._orig_minor))
493 try:
494 parted_fs = parted_part.geom.file_system_open() 469 parted_fs = parted_part.geom.file_system_open()
495 except:
496 self._resizeable = False
497 return
498 resize_constraint = parted_fs.get_resize_constraint() 470 resize_constraint = parted_fs.get_resize_constraint()
499 min_bytes = resize_constraint.min_size * self._device._sector_bytes 471 min_bytes = resize_constraint.min_size * self._device._sector_bytes
500 self._min_mb_for_resize = int(min_bytes / MEGABYTE) + 1 472 self._min_mb_for_resize = long(min_bytes / MEGABYTE) + 1
501 self._resizeable = True 473 self._resizeable = True
474 except:
475 self._resizeable = False
502 476
503 ## 477 ##
504 # Returns whether or not the partition is extended 478 # Returns whether or not the partition is extended
505 def is_extended(self): 479 def is_extended(self):
506 if self._type == "extended": 480 if self._type == "extended":
510 484
511 ## 485 ##
512 # Returns whether or not the partition is logical 486 # Returns whether or not the partition is logical
513 def is_logical(self): 487 def is_logical(self):
514 if self._type == "free": 488 if self._type == "free":
515 if int(self._minor) + 0.9 == self._minor: 489 if int(self._minor) + FREE_MINOR_FRAC_LOG == self._minor:
516 return True 490 return True
517 else: 491 else:
518 return False 492 return False
519 elif archinfo[self._device._arch]['extended'] and self._minor > 4: 493 elif archinfo[self._device._arch]['extended'] and self._minor > 4:
520 return True 494 return True
542 return None 516 return None
543 else: 517 else:
544 return self._device.get_partition_at(self._start, ignore_extended=0) 518 return self._device.get_partition_at(self._start, ignore_extended=0)
545 519
546 ## 520 ##
521 # Sets the options passed to mkfs
522 # @param mkfsopts Options passed to mkfs
523 def set_mkfsopts(self, mkfsopts):
524 self._mkfsopts = mkfsopts
525
526 ##
527 # Returns the options passes to mkfs
528 def get_mkfsopts(self):
529 return self._mkfsopts
530
531 ##
547 # Sets the start sector for the partition 532 # Sets the start sector for the partition
548 # @param start Start sector 533 # @param start Start sector
549 def set_start(self, start): 534 def set_start(self, start):
550 self._start = int(start) 535 self._start = long(start)
551 536
552 ## 537 ##
553 # Returns the start sector for the partition 538 # Returns the start sector for the partition
554 def get_start(self): 539 def get_start(self):
555 return int(self._start) 540 return long(self._start)
556 541
557 ## 542 ##
558 # Sets the end sector of the partition 543 # Sets the end sector of the partition
559 # @param end End sector 544 # @param end End sector
560 def set_end(self, end): 545 def set_end(self, end):
561 self._end = int(end) 546 self._end = long(end)
562 547
563 ## 548 ##
564 # Returns end sector for the partition 549 # Returns end sector for the partition
565 def get_end(self): 550 def get_end(self):
566 return int(self._end) 551 return long(self._end)
567 552
568 ## 553 ##
569 # Returns size of partition in MB 554 # Returns size of partition in MB
570 def get_mb(self): 555 def get_mb(self):
571 return int(self._mb) 556 return long(self._mb)
572 557
573 ## 558 ##
574 # Sets size of partition in MB 559 # Sets size of partition in MB
575 # @param mb Parameter description 560 # @param mb Parameter description
576 def set_mb(self, mb): 561 def set_mb(self, mb):
577 self._mb = int(mb) 562 self._mb = long(mb)
578 563
579 ## 564 ##
580 # Sets type of partition 565 # Sets type of partition
581 # @param type Parameter description 566 # @param type Parameter description
582 def set_type(self, type): 567 def set_type(self, type):
671 # Returns maximum MB for resize 656 # Returns maximum MB for resize
672 def get_max_mb_for_resize(self): 657 def get_max_mb_for_resize(self):
673 if self._resizeable: 658 if self._resizeable:
674 free_minor = 0 659 free_minor = 0
675 if self.is_logical(): 660 if self.is_logical():
676 free_minor = self._minor + 0.9 661 free_minor = self._minor + FREE_MINOR_FRAC_LOG
677 else: 662 else:
678 free_minor = self._minor + 0.1 663 free_minor = self._minor + FREE_MINOR_FRAC_PRI
679 if free_minor in self._device._partitions: 664 if free_minor in self._device._partitions:
680 return self._mb + self._device._partitions[free_minor]._mb 665 return self._mb + self._device._partitions[free_minor]._mb
681 else: 666 else:
682 return self._mb 667 return self._mb
683 else: 668 else:
687 # Resizes the partition 672 # Resizes the partition
688 # @param mb New size in MB 673 # @param mb New size in MB
689 def resize(self, mb): 674 def resize(self, mb):
690 free_minor = self._minor 675 free_minor = self._minor
691 if self.is_logical(): 676 if self.is_logical():
692 free_minor += 0.9 677 free_minor += FREE_MINOR_FRAC_LOG
693 else: 678 else:
694 free_minor += 0.1 679 free_minor += FREE_MINOR_FRAC_PRI
695 if mb < self._mb: 680 if mb < self._mb:
696 # Shrinking 681 # Shrinking
697 if not free_minor in self._device._partitions: 682 if not free_minor in self._device._partitions:
698 self._device._partitions[free_minor] = Partition(self._device, free_minor, 0, 0, 0, "free", format=False, existing=False) 683 self._device._partitions[free_minor] = Partition(self._device, free_minor, 0, 0, 0, "free", format=False, existing=False)
699 self._device._partitions[free_minor]._mb += self._mb - mb 684 self._device._partitions[free_minor]._mb += self._mb - mb
711# Returns a list of detected partitionable devices 696# Returns a list of detected partitionable devices
712def detect_devices(): 697def detect_devices():
713 devices = [] 698 devices = []
714 699
715 # Make sure sysfs exists 700 # Make sure sysfs exists
701 # TODO: rewrite for 2.4 support
716 if not os.path.exists("/sys/bus"): 702 if not os.path.exists("/sys/bus"):
717 raise GLIException("GLIStorageDeviceError", 'fatal', 'detect_devices', "no sysfs found (you MUST use a kernel >2.6)") 703 raise GLIException("GLIStorageDeviceError", 'fatal', 'detect_devices', "no sysfs found (you MUST use a kernel >2.6)")
718 # Make sure /proc/partitions exists 704 # Make sure /proc/partitions exists
719 if not os.path.exists("/proc/partitions"): 705 if not os.path.exists("/proc/partitions"):
720 raise GLIException("GLIStorageDeviceError", 'fatal', 'detect_devices', "/proc/partitions does not exist! Please make sure procfs is in your kernel and mounted!") 706 raise GLIException("GLIStorageDeviceError", 'fatal', 'detect_devices', "/proc/partitions does not exist! Please make sure procfs is in your kernel and mounted!")
757 743
758 partitions.append(( major, minor, device )) 744 partitions.append(( major, minor, device ))
759 745
760 # Scan sysfs for the devices of type 'x' 746 # Scan sysfs for the devices of type 'x'
761 # 'x' being a member of the list below: 747 # 'x' being a member of the list below:
748 # TODO: rewrite for 2.4 support
762 for dev_type in [ "ide", "scsi" ]: # Other device types? usb? fw? 749 for dev_type in [ "ide", "scsi" ]: # Other device types? usb? fw?
763 if os.path.exists("/sys/bus/" + dev_type): 750 if os.path.exists("/sys/bus/" + dev_type):
764 sysfs_devices = os.listdir("/sys/bus/"+dev_type+"/devices") 751 sysfs_devices = os.listdir("/sys/bus/"+dev_type+"/devices")
765 752
766 # For each device in the devices on that bus 753 # For each device in the devices on that bus

Legend:
Removed from v.596  
changed lines
  Added in v.1040

  ViewVC Help
Powered by ViewVC 1.1.20