Statistics
| Branch: | Tag: | Revision:

root / snf-image-helper / disklabel.py @ 501e19ec

History | View | Annotate | Download (22.9 kB)

1 de34e7aa Nikos Skalkotos
#!/usr/bin/env python
2 1bda0902 Nikos Skalkotos
#
3 de34e7aa Nikos Skalkotos
# -*- coding: utf-8 -*-
4 de34e7aa Nikos Skalkotos
#
5 de34e7aa Nikos Skalkotos
# Copyright (C) 2013 GRNET S.A.
6 de34e7aa Nikos Skalkotos
#
7 de34e7aa Nikos Skalkotos
# This program is free software; you can redistribute it and/or modify
8 de34e7aa Nikos Skalkotos
# it under the terms of the GNU General Public License as published by
9 de34e7aa Nikos Skalkotos
# the Free Software Foundation; either version 2 of the License, or
10 de34e7aa Nikos Skalkotos
# (at your option) any later version.
11 de34e7aa Nikos Skalkotos
#
12 de34e7aa Nikos Skalkotos
# This program is distributed in the hope that it will be useful, but
13 de34e7aa Nikos Skalkotos
# WITHOUT ANY WARRANTY; without even the implied warranty of
14 de34e7aa Nikos Skalkotos
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 de34e7aa Nikos Skalkotos
# General Public License for more details.
16 de34e7aa Nikos Skalkotos
#
17 de34e7aa Nikos Skalkotos
# You should have received a copy of the GNU General Public License
18 de34e7aa Nikos Skalkotos
# along with this program; if not, write to the Free Software
19 de34e7aa Nikos Skalkotos
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 de34e7aa Nikos Skalkotos
# 02110-1301, USA.
21 de34e7aa Nikos Skalkotos
22 34fd52a7 Nikos Skalkotos
"""This module provides the code for handling BSD disklabels"""
23 de34e7aa Nikos Skalkotos
24 de34e7aa Nikos Skalkotos
import struct
25 de34e7aa Nikos Skalkotos
import sys
26 34fd52a7 Nikos Skalkotos
import os
27 de34e7aa Nikos Skalkotos
import cStringIO
28 de34e7aa Nikos Skalkotos
import optparse
29 de34e7aa Nikos Skalkotos
30 de34e7aa Nikos Skalkotos
from collections import namedtuple
31 501e19ec Nikos Skalkotos
from collections import OrderedDict
32 de34e7aa Nikos Skalkotos
33 de34e7aa Nikos Skalkotos
BLOCKSIZE = 512
34 de34e7aa Nikos Skalkotos
35 de34e7aa Nikos Skalkotos
LABELSECTOR = 1
36 de34e7aa Nikos Skalkotos
LABELOFFSET = 0
37 de34e7aa Nikos Skalkotos
38 de34e7aa Nikos Skalkotos
BBSIZE = 8192  # size of boot area with label
39 de34e7aa Nikos Skalkotos
SBSIZE = 8192  # max size of fs superblock
40 de34e7aa Nikos Skalkotos
41 be5f0160 Nikos Skalkotos
DISKMAGIC = 0x82564557
42 be5f0160 Nikos Skalkotos
43 de34e7aa Nikos Skalkotos
44 de34e7aa Nikos Skalkotos
class MBR(object):
45 de34e7aa Nikos Skalkotos
    """Represents a Master Boot Record."""
46 de34e7aa Nikos Skalkotos
    class Partition(object):
47 de34e7aa Nikos Skalkotos
        """Represents a partition entry in MBR"""
48 de34e7aa Nikos Skalkotos
        format = "<B3sB3sLL"
49 de34e7aa Nikos Skalkotos
50 de34e7aa Nikos Skalkotos
        def __init__(self, raw_part):
51 de34e7aa Nikos Skalkotos
            """Create a Partition instance"""
52 501e19ec Nikos Skalkotos
            (self.status,
53 501e19ec Nikos Skalkotos
             self.start,
54 501e19ec Nikos Skalkotos
             self.type,
55 501e19ec Nikos Skalkotos
             self.end,
56 501e19ec Nikos Skalkotos
             self.first_sector,
57 501e19ec Nikos Skalkotos
             self.sector_count
58 501e19ec Nikos Skalkotos
             ) = struct.unpack(self.format, raw_part)
59 de34e7aa Nikos Skalkotos
60 de34e7aa Nikos Skalkotos
        def pack(self):
61 de34e7aa Nikos Skalkotos
            """Pack the partition values into a binary string"""
62 de34e7aa Nikos Skalkotos
            return struct.pack(self.format,
63 de34e7aa Nikos Skalkotos
                               self.status,
64 de34e7aa Nikos Skalkotos
                               self.start,
65 de34e7aa Nikos Skalkotos
                               self.type,
66 de34e7aa Nikos Skalkotos
                               self.end,
67 de34e7aa Nikos Skalkotos
                               self.first_sector,
68 de34e7aa Nikos Skalkotos
                               self.sector_count)
69 de34e7aa Nikos Skalkotos
70 de34e7aa Nikos Skalkotos
        @staticmethod
71 de34e7aa Nikos Skalkotos
        def size():
72 de34e7aa Nikos Skalkotos
            """Returns the size of an MBR partition entry"""
73 de34e7aa Nikos Skalkotos
            return struct.calcsize(MBR.Partition.format)
74 de34e7aa Nikos Skalkotos
75 de34e7aa Nikos Skalkotos
        def __str__(self):
76 de34e7aa Nikos Skalkotos
            start = self.unpack_chs(self.start)
77 de34e7aa Nikos Skalkotos
            end = self.unpack_chs(self.end)
78 de34e7aa Nikos Skalkotos
            return "%d %s %d %s %d %d" % (self.status, start, self.type, end,
79 de34e7aa Nikos Skalkotos
                                          self.first_sector, self.sector_count)
80 de34e7aa Nikos Skalkotos
81 de34e7aa Nikos Skalkotos
        @staticmethod
82 de34e7aa Nikos Skalkotos
        def unpack_chs(chs):
83 de34e7aa Nikos Skalkotos
            """Unpacks a CHS address string to a tuple."""
84 de34e7aa Nikos Skalkotos
85 de34e7aa Nikos Skalkotos
            assert len(chs) == 3
86 de34e7aa Nikos Skalkotos
87 de34e7aa Nikos Skalkotos
            head = struct.unpack('<B', chs[0])[0]
88 de34e7aa Nikos Skalkotos
            sector = struct.unpack('<B', chs[1])[0] & 0x3f
89 de34e7aa Nikos Skalkotos
            cylinder = (struct.unpack('<B', chs[1])[0] & 0xC0) << 2 | \
90 de34e7aa Nikos Skalkotos
                struct.unpack('<B', chs[2])[0]
91 de34e7aa Nikos Skalkotos
92 de34e7aa Nikos Skalkotos
            return (cylinder, head, sector)
93 de34e7aa Nikos Skalkotos
94 de34e7aa Nikos Skalkotos
        @staticmethod
95 de34e7aa Nikos Skalkotos
        def pack_chs(cylinder, head, sector):
96 de34e7aa Nikos Skalkotos
            """Packs a CHS tuple to an address string."""
97 de34e7aa Nikos Skalkotos
98 de34e7aa Nikos Skalkotos
            assert 1 <= sector <= 63
99 de34e7aa Nikos Skalkotos
            assert 0 <= head <= 255
100 0d413fc6 Nikos Skalkotos
            assert 0 <= cylinder
101 0d413fc6 Nikos Skalkotos
102 0d413fc6 Nikos Skalkotos
            # If the cylinders overflow then put the value (1023, 254, 63) to
103 0d413fc6 Nikos Skalkotos
            # the tuple. At least this is what OpenBSD does.
104 0d413fc6 Nikos Skalkotos
            if cylinder > 1023:
105 0d413fc6 Nikos Skalkotos
                cylinder = 1023
106 0d413fc6 Nikos Skalkotos
                head = 254
107 0d413fc6 Nikos Skalkotos
                sector = 63
108 de34e7aa Nikos Skalkotos
109 de34e7aa Nikos Skalkotos
            byte0 = head
110 de34e7aa Nikos Skalkotos
            byte1 = (cylinder >> 2) & 0xC0 | sector
111 de34e7aa Nikos Skalkotos
            byte2 = cylinder & 0xff
112 de34e7aa Nikos Skalkotos
113 de34e7aa Nikos Skalkotos
            return struct.pack('<BBB', byte0, byte1, byte2)
114 de34e7aa Nikos Skalkotos
115 de34e7aa Nikos Skalkotos
    format = "<444s2x16s16s16s16s2s"
116 de34e7aa Nikos Skalkotos
    """
117 de34e7aa Nikos Skalkotos
    Offset  Length          Contents
118 de34e7aa Nikos Skalkotos
    0       440(max. 446)   code area
119 de34e7aa Nikos Skalkotos
    440     2(optional)     disk signature
120 de34e7aa Nikos Skalkotos
    444     2               Usually nulls
121 de34e7aa Nikos Skalkotos
    446     16              Partition 0
122 de34e7aa Nikos Skalkotos
    462     16              Partition 1
123 de34e7aa Nikos Skalkotos
    478     16              Partition 2
124 de34e7aa Nikos Skalkotos
    494     16              Partition 3
125 de34e7aa Nikos Skalkotos
    510     2               MBR signature
126 de34e7aa Nikos Skalkotos
    """
127 de34e7aa Nikos Skalkotos
    def __init__(self, block):
128 de34e7aa Nikos Skalkotos
        """Create an MBR instance"""
129 de34e7aa Nikos Skalkotos
        raw_part = {}
130 de34e7aa Nikos Skalkotos
        (self.code_area,
131 de34e7aa Nikos Skalkotos
         raw_part[0],
132 de34e7aa Nikos Skalkotos
         raw_part[1],
133 de34e7aa Nikos Skalkotos
         raw_part[2],
134 de34e7aa Nikos Skalkotos
         raw_part[3],
135 de34e7aa Nikos Skalkotos
         self.signature) = struct.unpack(self.format, block)
136 de34e7aa Nikos Skalkotos
137 de34e7aa Nikos Skalkotos
        self.part = {}
138 de34e7aa Nikos Skalkotos
        for i in range(4):
139 de34e7aa Nikos Skalkotos
            self.part[i] = self.Partition(raw_part[i])
140 de34e7aa Nikos Skalkotos
141 de34e7aa Nikos Skalkotos
    @staticmethod
142 de34e7aa Nikos Skalkotos
    def size():
143 de34e7aa Nikos Skalkotos
        """Return the size of a Master Boot Record."""
144 de34e7aa Nikos Skalkotos
        return struct.calcsize(MBR.format)
145 de34e7aa Nikos Skalkotos
146 de34e7aa Nikos Skalkotos
    def pack(self):
147 de34e7aa Nikos Skalkotos
        """Pack an MBR to a binary string."""
148 de34e7aa Nikos Skalkotos
        return struct.pack(self.format,
149 de34e7aa Nikos Skalkotos
                           self.code_area,
150 de34e7aa Nikos Skalkotos
                           self.part[0].pack(),
151 de34e7aa Nikos Skalkotos
                           self.part[1].pack(),
152 de34e7aa Nikos Skalkotos
                           self.part[2].pack(),
153 de34e7aa Nikos Skalkotos
                           self.part[3].pack(),
154 de34e7aa Nikos Skalkotos
                           self.signature)
155 de34e7aa Nikos Skalkotos
156 de34e7aa Nikos Skalkotos
    def __str__(self):
157 de34e7aa Nikos Skalkotos
        ret = ""
158 de34e7aa Nikos Skalkotos
        for i in range(4):
159 de34e7aa Nikos Skalkotos
            ret += "Partition %d: %s\n" % (i, self.part[i])
160 de34e7aa Nikos Skalkotos
        ret += "Signature: %s %s\n" % (hex(ord(self.signature[0])),
161 de34e7aa Nikos Skalkotos
                                       hex(ord(self.signature[1])))
162 34fd52a7 Nikos Skalkotos
        title = "Master Boot Record"
163 34fd52a7 Nikos Skalkotos
        return "%s\n%s\n%s\n" % (title, len(title) * "=", ret)
164 de34e7aa Nikos Skalkotos
165 de34e7aa Nikos Skalkotos
166 be5f0160 Nikos Skalkotos
class Disk(object):
167 be5f0160 Nikos Skalkotos
    """Represents an BSD Disk"""
168 be5f0160 Nikos Skalkotos
169 be5f0160 Nikos Skalkotos
    def __init__(self, device):
170 be5f0160 Nikos Skalkotos
        """Create a Disk instance"""
171 be5f0160 Nikos Skalkotos
        self.device = device
172 34fd52a7 Nikos Skalkotos
        self.part_num = None
173 34fd52a7 Nikos Skalkotos
        self.disklabel = None
174 34fd52a7 Nikos Skalkotos
175 be5f0160 Nikos Skalkotos
        with open(device, "rb") as d:
176 34fd52a7 Nikos Skalkotos
            sector0 = d.read(BLOCKSIZE)
177 34fd52a7 Nikos Skalkotos
            self.mbr = MBR(sector0)
178 34fd52a7 Nikos Skalkotos
179 34fd52a7 Nikos Skalkotos
            for i in range(4):
180 34fd52a7 Nikos Skalkotos
                ptype = self.mbr.part[i].type
181 34fd52a7 Nikos Skalkotos
                if ptype in (0xa5, 0xa6, 0xa9):
182 34fd52a7 Nikos Skalkotos
                    d.seek(BLOCKSIZE * self.mbr.part[i].first_sector)
183 34fd52a7 Nikos Skalkotos
                    self.part_num = i
184 34fd52a7 Nikos Skalkotos
                    if ptype == 0xa5:  # FreeBSD
185 34fd52a7 Nikos Skalkotos
                        self.disklabel = BSD_Disklabel(d)
186 34fd52a7 Nikos Skalkotos
                    elif ptype == 0xa6:  # OpenBSD
187 34fd52a7 Nikos Skalkotos
                        self.disklabel = OpenBSD_Disklabel(d)
188 34fd52a7 Nikos Skalkotos
                    else:  # NetBSD
189 34fd52a7 Nikos Skalkotos
                        self.disklabel = BSD_Disklabel(d)
190 34fd52a7 Nikos Skalkotos
                    break
191 34fd52a7 Nikos Skalkotos
192 34fd52a7 Nikos Skalkotos
        assert self.disklabel is not None, "No *BSD partition found"
193 34fd52a7 Nikos Skalkotos
194 34fd52a7 Nikos Skalkotos
    def write(self):
195 be5f0160 Nikos Skalkotos
        """Write the changes back to the media"""
196 be5f0160 Nikos Skalkotos
        with open(self.device, 'rw+b') as d:
197 34fd52a7 Nikos Skalkotos
            d.write(self.mbr.pack())
198 34fd52a7 Nikos Skalkotos
199 34fd52a7 Nikos Skalkotos
            d.seek(self.mbr.part[self.part_num].first_sector * BLOCKSIZE)
200 34fd52a7 Nikos Skalkotos
            self.disklabel.write_to(d)
201 34fd52a7 Nikos Skalkotos
202 34fd52a7 Nikos Skalkotos
    def __str__(self):
203 34fd52a7 Nikos Skalkotos
        return str(self.mbr) + str(self.disklabel)
204 34fd52a7 Nikos Skalkotos
205 be5f0160 Nikos Skalkotos
    def enlarge(self, new_size):
206 be5f0160 Nikos Skalkotos
        """Enlarge the disk and return the last usable sector"""
207 34fd52a7 Nikos Skalkotos
208 34fd52a7 Nikos Skalkotos
        # Fix the disklabel
209 be5f0160 Nikos Skalkotos
        end = self.disklabel.enlarge(new_size)
210 34fd52a7 Nikos Skalkotos
211 34fd52a7 Nikos Skalkotos
        # Fix the MBR
212 34fd52a7 Nikos Skalkotos
        start = self.mbr.part[self.part_num].first_sector
213 34fd52a7 Nikos Skalkotos
        self.mbr.part[self.part_num].sector_count = end - start + 1
214 34fd52a7 Nikos Skalkotos
215 501e19ec Nikos Skalkotos
        ntracks = self.disklabel.field['ntracks']
216 501e19ec Nikos Skalkotos
        nsectors = self.disklabel.field['nsectors']
217 501e19ec Nikos Skalkotos
218 501e19ec Nikos Skalkotos
        cylinder = end // (ntracks * nsectors)
219 501e19ec Nikos Skalkotos
        header = (end // nsectors) % ntracks
220 501e19ec Nikos Skalkotos
        sector = (end % nsectors) + 1
221 34fd52a7 Nikos Skalkotos
        chs = MBR.Partition.pack_chs(cylinder, header, sector)
222 34fd52a7 Nikos Skalkotos
        self.mbr.part[self.part_num].end = chs
223 34fd52a7 Nikos Skalkotos
224 34fd52a7 Nikos Skalkotos
    def enlarge_last_partition(self):
225 501e19ec Nikos Skalkotos
        """Enlarge the last partition to cover up all the free space"""
226 34fd52a7 Nikos Skalkotos
        self.disklabel.enlarge_last_partition()
227 34fd52a7 Nikos Skalkotos
228 501e19ec Nikos Skalkotos
    def get_last_partition_id(self):
229 501e19ec Nikos Skalkotos
        """Get the ID of the last partition"""
230 501e19ec Nikos Skalkotos
        return self.disklabel.get_last_partition_id()
231 501e19ec Nikos Skalkotos
232 501e19ec Nikos Skalkotos
    def get_duid(self):
233 501e19ec Nikos Skalkotos
        return self.disklabel.field['uid']
234 501e19ec Nikos Skalkotos
235 34fd52a7 Nikos Skalkotos
236 63656985 Nikos Skalkotos
class DisklabelBase(object):
237 63656985 Nikos Skalkotos
    """Disklabel base class"""
238 63656985 Nikos Skalkotos
239 63656985 Nikos Skalkotos
    def __init__(self, device):
240 63656985 Nikos Skalkotos
        """Create a Disklabel instance"""
241 63656985 Nikos Skalkotos
        raise NotImplementedError
242 63656985 Nikos Skalkotos
243 63656985 Nikos Skalkotos
    def pack(self, checksum=None):
244 63656985 Nikos Skalkotos
        """Return a binary copy of the Disklabel block"""
245 501e19ec Nikos Skalkotos
246 501e19ec Nikos Skalkotos
        out = OrderedDict()
247 501e19ec Nikos Skalkotos
        for k, v in self.field.items():
248 501e19ec Nikos Skalkotos
            out[k] = v
249 501e19ec Nikos Skalkotos
250 501e19ec Nikos Skalkotos
        if checksum is not None:
251 501e19ec Nikos Skalkotos
            out['checksum'] = checksum
252 501e19ec Nikos Skalkotos
253 501e19ec Nikos Skalkotos
        return struct.pack(self.format, * out.values() + [self.ptable.pack()])
254 63656985 Nikos Skalkotos
255 63656985 Nikos Skalkotos
    def compute_checksum(self):
256 63656985 Nikos Skalkotos
        """Compute the checksum of the disklabel"""
257 63656985 Nikos Skalkotos
258 63656985 Nikos Skalkotos
        raw = cStringIO.StringIO(self.pack(0))
259 63656985 Nikos Skalkotos
        checksum = 0
260 63656985 Nikos Skalkotos
        try:
261 63656985 Nikos Skalkotos
            uint16 = raw.read(2)
262 63656985 Nikos Skalkotos
            while uint16 != "":
263 63656985 Nikos Skalkotos
                checksum ^= struct.unpack('<H', uint16)[0]
264 63656985 Nikos Skalkotos
                uint16 = raw.read(2)
265 63656985 Nikos Skalkotos
        finally:
266 63656985 Nikos Skalkotos
            raw.close()
267 63656985 Nikos Skalkotos
268 63656985 Nikos Skalkotos
        return checksum
269 63656985 Nikos Skalkotos
270 63656985 Nikos Skalkotos
    def enlarge(self, new_size):
271 63656985 Nikos Skalkotos
        """Enlarge the disk and return the last usable sector"""
272 63656985 Nikos Skalkotos
        raise NotImplementedError
273 63656985 Nikos Skalkotos
274 63656985 Nikos Skalkotos
    def write_to(self, device):
275 63656985 Nikos Skalkotos
        """Write the disklabel to a device"""
276 501e19ec Nikos Skalkotos
277 501e19ec Nikos Skalkotos
        # The disklabel starts at sector 1
278 501e19ec Nikos Skalkotos
        device.seek(BLOCKSIZE, os.SEEK_CUR)
279 501e19ec Nikos Skalkotos
        device.write(self.pack())
280 63656985 Nikos Skalkotos
281 63656985 Nikos Skalkotos
    def enlarge_last_partition(self):
282 63656985 Nikos Skalkotos
        """Enlarge the last partition to consume all the usable space"""
283 63656985 Nikos Skalkotos
        raise NotImplementedError
284 63656985 Nikos Skalkotos
285 501e19ec Nikos Skalkotos
    def get_last_partition_id(self):
286 501e19ec Nikos Skalkotos
        """Get the ID of the last partition"""
287 501e19ec Nikos Skalkotos
        raise NotImplementedError
288 501e19ec Nikos Skalkotos
289 63656985 Nikos Skalkotos
    def __str__(self):
290 63656985 Nikos Skalkotos
        """Print the Disklabel"""
291 63656985 Nikos Skalkotos
        raise NotImplementedError
292 63656985 Nikos Skalkotos
293 63656985 Nikos Skalkotos
294 501e19ec Nikos Skalkotos
class PartitionTableBase(object):
295 501e19ec Nikos Skalkotos
    """Base Class for disklabel partition tables"""
296 501e19ec Nikos Skalkotos
297 501e19ec Nikos Skalkotos
    @property
298 501e19ec Nikos Skalkotos
    def format(self):
299 501e19ec Nikos Skalkotos
        """Partition table format string"""
300 501e19ec Nikos Skalkotos
        raise NotImplementedError
301 501e19ec Nikos Skalkotos
302 501e19ec Nikos Skalkotos
    Partition = namedtuple('Partition', '')
303 501e19ec Nikos Skalkotos
304 501e19ec Nikos Skalkotos
    def __init__(self, ptable, pnumber):
305 501e19ec Nikos Skalkotos
        """Create a Partition Table instance"""
306 501e19ec Nikos Skalkotos
        self.part = []
307 501e19ec Nikos Skalkotos
308 501e19ec Nikos Skalkotos
        size = struct.calcsize(self.format)
309 501e19ec Nikos Skalkotos
310 501e19ec Nikos Skalkotos
        raw = cStringIO.StringIO(ptable)
311 501e19ec Nikos Skalkotos
        try:
312 501e19ec Nikos Skalkotos
            for i in range(pnumber):
313 501e19ec Nikos Skalkotos
                p = self.Partition(
314 501e19ec Nikos Skalkotos
                    *struct.unpack(self.format, raw.read(size)))
315 501e19ec Nikos Skalkotos
                self.part.append(p)
316 501e19ec Nikos Skalkotos
        finally:
317 501e19ec Nikos Skalkotos
            raw.close()
318 501e19ec Nikos Skalkotos
319 501e19ec Nikos Skalkotos
    def __str__(self):
320 501e19ec Nikos Skalkotos
        """Print the Partition table"""
321 501e19ec Nikos Skalkotos
        val = ""
322 501e19ec Nikos Skalkotos
        for i in range(len(self.part)):
323 501e19ec Nikos Skalkotos
            val += "%c: %s\n" % (chr(ord('a') + i), str(self.part[i]))
324 501e19ec Nikos Skalkotos
        return val
325 501e19ec Nikos Skalkotos
326 501e19ec Nikos Skalkotos
    def pack(self):
327 501e19ec Nikos Skalkotos
        """Packs the partition table into a binary string."""
328 501e19ec Nikos Skalkotos
        ret = ""
329 501e19ec Nikos Skalkotos
        for i in range(len(self.part)):
330 501e19ec Nikos Skalkotos
            ret += struct.pack(self.format, *self.part[i])
331 501e19ec Nikos Skalkotos
        return ret + ((364 - len(self.part) * 16) * '\x00')
332 501e19ec Nikos Skalkotos
333 501e19ec Nikos Skalkotos
334 63656985 Nikos Skalkotos
class BSD_Disklabel(DisklabelBase):
335 be5f0160 Nikos Skalkotos
    """Represents an BSD Disklabel"""
336 34fd52a7 Nikos Skalkotos
337 be5f0160 Nikos Skalkotos
    class PartitionTable(PartitionTableBase):
338 be5f0160 Nikos Skalkotos
        """Represents a BSD Partition Table"""
339 be5f0160 Nikos Skalkotos
        format = "<IIIBBH"
340 be5f0160 Nikos Skalkotos
        """
341 be5f0160 Nikos Skalkotos
        Partition Entry:
342 be5f0160 Nikos Skalkotos
        Offset  Length          Contents
343 be5f0160 Nikos Skalkotos
        0       4               Number of sectors in partition
344 be5f0160 Nikos Skalkotos
        4       4               Starting sector
345 be5f0160 Nikos Skalkotos
        8       4               Filesystem basic fragment size
346 be5f0160 Nikos Skalkotos
        12      1               Filesystem type
347 be5f0160 Nikos Skalkotos
        13      1               Filesystem fragments per block
348 be5f0160 Nikos Skalkotos
        14      2               Filesystem cylinders per group
349 be5f0160 Nikos Skalkotos
        """
350 34fd52a7 Nikos Skalkotos
351 be5f0160 Nikos Skalkotos
        Partition = namedtuple(
352 be5f0160 Nikos Skalkotos
            'Partition', 'size, offset, fsize, fstype, frag, cpg')
353 be5f0160 Nikos Skalkotos
354 501e19ec Nikos Skalkotos
    format = "<IHH16s16sIIIIIIHHIHHHHIII20s20sIHHII364s"
355 de34e7aa Nikos Skalkotos
    """
356 de34e7aa Nikos Skalkotos
    Offset  Length          Contents
357 de34e7aa Nikos Skalkotos
    0       4               Magic
358 de34e7aa Nikos Skalkotos
    4       2               Drive Type
359 de34e7aa Nikos Skalkotos
    6       2               Subtype
360 de34e7aa Nikos Skalkotos
    8       16              Type Name
361 de34e7aa Nikos Skalkotos
    24      16              Pack Identifier
362 de34e7aa Nikos Skalkotos
    32      4               Bytes per sector
363 de34e7aa Nikos Skalkotos
    36      4               Data sectors per track
364 be5f0160 Nikos Skalkotos
    40      4               Tracks per cylinder
365 de34e7aa Nikos Skalkotos
    44      4               Data cylinders per unit
366 be5f0160 Nikos Skalkotos
    48      4               Data sectors per cylinder
367 de34e7aa Nikos Skalkotos
    52      4               Data sectors per unit
368 be5f0160 Nikos Skalkotos
    56      2               Spare sectors per track
369 be5f0160 Nikos Skalkotos
    58      2               Spare sectors per cylinder
370 be5f0160 Nikos Skalkotos
    60      4               Alternative cylinders per unit
371 be5f0160 Nikos Skalkotos
    64      2               Rotation Speed
372 be5f0160 Nikos Skalkotos
    66      2               Hardware sector interleave
373 be5f0160 Nikos Skalkotos
    68      2               Sector 0 skew, per track
374 be5f0160 Nikos Skalkotos
    70      2               Sector 0 skew, per cylinder
375 be5f0160 Nikos Skalkotos
    72      4               Head switch time
376 be5f0160 Nikos Skalkotos
    76      4               Track-to-track seek
377 de34e7aa Nikos Skalkotos
    80      4               Generic Flags
378 de34e7aa Nikos Skalkotos
    84      5*4             Drive-type specific information
379 be5f0160 Nikos Skalkotos
    104     5*4             Reserved for future use
380 be5f0160 Nikos Skalkotos
    124     4               Magic Number
381 be5f0160 Nikos Skalkotos
    128     2               Xor of data including partitions
382 be5f0160 Nikos Skalkotos
    130     2               Number of partitions following
383 de34e7aa Nikos Skalkotos
    132     4               size of boot area at sn0, bytes
384 de34e7aa Nikos Skalkotos
    136     4               Max size of fs superblock, bytes
385 de34e7aa Nikos Skalkotos
    140     16*16           Partition Table
386 de34e7aa Nikos Skalkotos
    """
387 de34e7aa Nikos Skalkotos
388 be5f0160 Nikos Skalkotos
389 63656985 Nikos Skalkotos
class OpenBSD_Disklabel(DisklabelBase):
390 be5f0160 Nikos Skalkotos
    """Represents an OpenBSD Disklabel"""
391 be5f0160 Nikos Skalkotos
392 be5f0160 Nikos Skalkotos
    class PartitionTable(PartitionTableBase):
393 de34e7aa Nikos Skalkotos
        """Reprepsents an OpenBSD Partition Table"""
394 de34e7aa Nikos Skalkotos
        format = "<IIHHBBH"
395 501e19ec Nikos Skalkotos
396 de34e7aa Nikos Skalkotos
        """
397 de34e7aa Nikos Skalkotos
        Partition Entry:
398 de34e7aa Nikos Skalkotos
        Offset  Length          Contents
399 de34e7aa Nikos Skalkotos
        0       4               Number of sectors in the partition
400 de34e7aa Nikos Skalkotos
        4       4               Starting sector
401 de34e7aa Nikos Skalkotos
        8       2               Starting sector (high part)
402 de34e7aa Nikos Skalkotos
        10      2               Number of sectors (high part)
403 de34e7aa Nikos Skalkotos
        12      1               Filesystem type
404 de34e7aa Nikos Skalkotos
        13      1               Filesystem Fragment per block
405 de34e7aa Nikos Skalkotos
        14      2               FS cylinders per group
406 de34e7aa Nikos Skalkotos
        """
407 de34e7aa Nikos Skalkotos
408 de34e7aa Nikos Skalkotos
        Partition = namedtuple(
409 de34e7aa Nikos Skalkotos
            'Partition', 'size, offset, offseth, sizeh, fstype, frag, cpg')
410 de34e7aa Nikos Skalkotos
411 de34e7aa Nikos Skalkotos
        def setpsize(self, i, size):
412 de34e7aa Nikos Skalkotos
            """Set size for partition i"""
413 de34e7aa Nikos Skalkotos
            tmp = self.part[i]
414 501e19ec Nikos Skalkotos
            self.part[i] = self.Partition(
415 501e19ec Nikos Skalkotos
                size & 0xffffffff, tmp.offset, tmp.offseth, size >> 32,
416 501e19ec Nikos Skalkotos
                tmp.fstype, tmp.frag, tmp.cpg)
417 de34e7aa Nikos Skalkotos
418 de34e7aa Nikos Skalkotos
        def getpsize(self, i):
419 34fd52a7 Nikos Skalkotos
            """Get size for partition i"""
420 de34e7aa Nikos Skalkotos
            return (self.part[i].sizeh << 32) + self.part[i].size
421 de34e7aa Nikos Skalkotos
422 de34e7aa Nikos Skalkotos
        def setpoffset(self, i, offset):
423 34fd52a7 Nikos Skalkotos
            """Set offset for partition i"""
424 de34e7aa Nikos Skalkotos
            tmp = self.part[i]
425 501e19ec Nikos Skalkotos
            self.part[i] = self.Partition(
426 501e19ec Nikos Skalkotos
                tmp.size, offset & 0xffffffff, offset >> 32, tmp.sizeh,
427 501e19ec Nikos Skalkotos
                tmp.frag, tmp.cpg)
428 de34e7aa Nikos Skalkotos
429 de34e7aa Nikos Skalkotos
        def getpoffset(self, i):
430 34fd52a7 Nikos Skalkotos
            """Get offset for partition i"""
431 de34e7aa Nikos Skalkotos
            return (self.part[i].offseth << 32) + self.part[i].offset
432 de34e7aa Nikos Skalkotos
433 be5f0160 Nikos Skalkotos
    format = "<IHH16s16sIIIIII8sIHHIII20sHH16sIHHII364s"
434 501e19ec Nikos Skalkotos
435 34fd52a7 Nikos Skalkotos
    def __init__(self, device):
436 34fd52a7 Nikos Skalkotos
        """Create a DiskLabel instance"""
437 de34e7aa Nikos Skalkotos
438 34fd52a7 Nikos Skalkotos
        device.seek(BLOCKSIZE, os.SEEK_CUR)
439 34fd52a7 Nikos Skalkotos
        # The offset of the disklabel from the beginning of the partition is
440 34fd52a7 Nikos Skalkotos
        # one sector
441 34fd52a7 Nikos Skalkotos
        sector1 = device.read(BLOCKSIZE)
442 de34e7aa Nikos Skalkotos
443 501e19ec Nikos Skalkotos
        d_ = OrderedDict()   # Off  Len    Content
444 501e19ec Nikos Skalkotos
        (d_["magic"],        # 0    4      Magic
445 501e19ec Nikos Skalkotos
         d_["dtype"],        # 4    2      Drive Type
446 501e19ec Nikos Skalkotos
         d_["subtype"],      # 6    2      Subtype
447 501e19ec Nikos Skalkotos
         d_["typename"],     # 8    16     Type Name
448 501e19ec Nikos Skalkotos
         d_["packname"],     # 24   16     Pack Identifier
449 501e19ec Nikos Skalkotos
         d_["secsize"],      # 32   4      Bytes per sector
450 501e19ec Nikos Skalkotos
         d_["nsectors"],     # 36   4      Data sectors per track
451 501e19ec Nikos Skalkotos
         d_["ntracks"],      # 40   4      Tracks per cylinder
452 501e19ec Nikos Skalkotos
         d_["ncylinders"],   # 44   4      Data cylinders per unit
453 501e19ec Nikos Skalkotos
         d_["secpercyl"],    # 48   4      Data sectors per cylinder
454 501e19ec Nikos Skalkotos
         d_["secperunit"],   # 52   4      Data sectors per unit
455 501e19ec Nikos Skalkotos
         d_["uid"],          # 56   8      Unique label identifier
456 501e19ec Nikos Skalkotos
         d_["acylinders"],   # 64   4      Alt cylinders per unit
457 501e19ec Nikos Skalkotos
         d_["bstarth"],      # 68   2      Start of useable region (high part)
458 501e19ec Nikos Skalkotos
         d_["bendh"],        # 70   2      Size of usable region (high part)
459 501e19ec Nikos Skalkotos
         d_["bstart"],       # 72   4      Start of useable region
460 501e19ec Nikos Skalkotos
         d_["bend"],         # 76   4      End of usable region
461 501e19ec Nikos Skalkotos
         d_["flags"],        # 80   4      Generic Flags
462 501e19ec Nikos Skalkotos
         d_["drivedata"],    # 84   5*4    Drive-type specific information
463 501e19ec Nikos Skalkotos
         d_["secperunith"],  # 104  2      Number of data sectors (high part)
464 501e19ec Nikos Skalkotos
         d_["version"],      # 106  2      Version
465 501e19ec Nikos Skalkotos
         d_["spare"],        # 108  4*4    Reserved for future use
466 501e19ec Nikos Skalkotos
         d_["magic2"],       # 124  4      Magic number
467 501e19ec Nikos Skalkotos
         d_["checksum"],     # 128  2      Xor of data including partitions
468 501e19ec Nikos Skalkotos
         d_["npartitions"],  # 130  2      Number of partitions in following
469 501e19ec Nikos Skalkotos
         d_["bbsize"],       # 132  4      size of boot area at sn0, bytes
470 501e19ec Nikos Skalkotos
         d_["sbsize"],       # 136  4      Max size of fs superblock, bytes
471 501e19ec Nikos Skalkotos
         ptable_raw          # 140  16*16  Partition Table
472 501e19ec Nikos Skalkotos
         ) = struct.unpack(self.format, sector1)
473 501e19ec Nikos Skalkotos
474 501e19ec Nikos Skalkotos
        assert d_['magic'] == d_['magic2'] == DISKMAGIC, "Disklabel not valid"
475 501e19ec Nikos Skalkotos
        self.ptable = self.PartitionTable(ptable_raw, d_['npartitions'])
476 501e19ec Nikos Skalkotos
        self.field = d_
477 de34e7aa Nikos Skalkotos
478 de34e7aa Nikos Skalkotos
    def setdsize(self, dsize):
479 de34e7aa Nikos Skalkotos
        """Set disk size"""
480 501e19ec Nikos Skalkotos
        self.field['secperunith'] = dsize >> 32
481 501e19ec Nikos Skalkotos
        self.field['secperunit'] = dsize & 0xffffffff
482 de34e7aa Nikos Skalkotos
483 de34e7aa Nikos Skalkotos
    def getdsize(self):
484 de34e7aa Nikos Skalkotos
        """Get disk size"""
485 501e19ec Nikos Skalkotos
        return (self.field['secperunith'] << 32) + self.field['secperunit']
486 501e19ec Nikos Skalkotos
487 501e19ec Nikos Skalkotos
    dsize = property(getdsize, setdsize, None, "disk size")
488 de34e7aa Nikos Skalkotos
489 de34e7aa Nikos Skalkotos
    def setbstart(self, bstart):
490 de34e7aa Nikos Skalkotos
        """Set start of useable region"""
491 501e19ec Nikos Skalkotos
        self.field['bstarth'] = bstart >> 32
492 501e19ec Nikos Skalkotos
        self.field['bstart'] = bstart & 0xffffffff
493 de34e7aa Nikos Skalkotos
494 de34e7aa Nikos Skalkotos
    def getbstart(self):
495 de34e7aa Nikos Skalkotos
        """Get start of usable region"""
496 501e19ec Nikos Skalkotos
        return (self.field['bstarth'] << 32) + self.field['bstart']
497 501e19ec Nikos Skalkotos
498 501e19ec Nikos Skalkotos
    bstart = property(getbstart, setbstart, None, "usable region start")
499 de34e7aa Nikos Skalkotos
500 de34e7aa Nikos Skalkotos
    def setbend(self, bend):
501 34fd52a7 Nikos Skalkotos
        """Set size of useable region"""
502 501e19ec Nikos Skalkotos
        self.field['bendh'] = bend >> 32
503 501e19ec Nikos Skalkotos
        self.field['bend'] = bend & 0xffffffff
504 de34e7aa Nikos Skalkotos
505 de34e7aa Nikos Skalkotos
    def getbend(self):
506 34fd52a7 Nikos Skalkotos
        """Get size of usable region"""
507 501e19ec Nikos Skalkotos
        return (self.field['bendh'] << 32) + self.field['bend']
508 501e19ec Nikos Skalkotos
509 501e19ec Nikos Skalkotos
    bend = property(getbend, setbend, None, "usable region size")
510 de34e7aa Nikos Skalkotos
511 be5f0160 Nikos Skalkotos
    def enlarge(self, new_size):
512 63656985 Nikos Skalkotos
        """Enlarge the disk and return the last usable sector"""
513 de34e7aa Nikos Skalkotos
514 501e19ec Nikos Skalkotos
        assert new_size >= self.dsize, \
515 501e19ec Nikos Skalkotos
            "New size cannot be smaller that %s" % self.dsize
516 de34e7aa Nikos Skalkotos
517 de34e7aa Nikos Skalkotos
        # Fix the disklabel
518 501e19ec Nikos Skalkotos
        self.dsize = new_size
519 501e19ec Nikos Skalkotos
        self.field['ncylinders'] = self.dsize // (self.field['nsectors'] *
520 501e19ec Nikos Skalkotos
                                                  self.field['ntracks'])
521 501e19ec Nikos Skalkotos
        self.bend = (self.field['ncylinders'] * self.field['nsectors'] *
522 501e19ec Nikos Skalkotos
                     self.field['ntracks'])
523 de34e7aa Nikos Skalkotos
524 de34e7aa Nikos Skalkotos
        # Partition 'c' descriptes the entire disk
525 de34e7aa Nikos Skalkotos
        self.ptable.setpsize(2, new_size)
526 de34e7aa Nikos Skalkotos
527 34fd52a7 Nikos Skalkotos
        # Update the checksum
528 de34e7aa Nikos Skalkotos
        self.checksum = self.compute_checksum()
529 de34e7aa Nikos Skalkotos
530 501e19ec Nikos Skalkotos
        # bend is the size and not the end of the usable region. I named it
531 501e19ec Nikos Skalkotos
        # like this because this is how it is named in OpenBSD. To get the last
532 501e19ec Nikos Skalkotos
        # usable sector you need to reduce this value by one.
533 501e19ec Nikos Skalkotos
        return self.bend - 1
534 de34e7aa Nikos Skalkotos
535 de34e7aa Nikos Skalkotos
    def get_last_partition_id(self):
536 de34e7aa Nikos Skalkotos
        """Returns the id of the last partition"""
537 de34e7aa Nikos Skalkotos
        part = 0
538 de34e7aa Nikos Skalkotos
        end = 0
539 de34e7aa Nikos Skalkotos
        # Don't check partition 'c' which is the whole disk
540 501e19ec Nikos Skalkotos
        for i in filter(lambda x: x != 2, range(len(self.ptable.part))):
541 de34e7aa Nikos Skalkotos
            curr_end = self.ptable.getpsize(i) + self.ptable.getpoffset(i)
542 de34e7aa Nikos Skalkotos
            if end < curr_end:
543 de34e7aa Nikos Skalkotos
                end = curr_end
544 de34e7aa Nikos Skalkotos
                part = i
545 de34e7aa Nikos Skalkotos
546 de34e7aa Nikos Skalkotos
        assert end > 0, "No partition found"
547 de34e7aa Nikos Skalkotos
548 de34e7aa Nikos Skalkotos
        return part
549 de34e7aa Nikos Skalkotos
550 de34e7aa Nikos Skalkotos
    def enlarge_last_partition(self):
551 de34e7aa Nikos Skalkotos
        """Enlarge the last partition to cover up all the free space"""
552 de34e7aa Nikos Skalkotos
553 de34e7aa Nikos Skalkotos
        part_num = self.get_last_partition_id()
554 de34e7aa Nikos Skalkotos
555 de34e7aa Nikos Skalkotos
        end = self.ptable.getpsize(part_num) + self.ptable.getpoffset(part_num)
556 de34e7aa Nikos Skalkotos
557 de34e7aa Nikos Skalkotos
        assert end > 0, "No partition found"
558 de34e7aa Nikos Skalkotos
559 de34e7aa Nikos Skalkotos
        if self.ptable.part[part_num].fstype == 1:  # Swap partition.
560 de34e7aa Nikos Skalkotos
            #TODO: Maybe create a warning?
561 de34e7aa Nikos Skalkotos
            return
562 de34e7aa Nikos Skalkotos
563 501e19ec Nikos Skalkotos
        if end > (self.bend - 1024):
564 de34e7aa Nikos Skalkotos
            return
565 de34e7aa Nikos Skalkotos
566 de34e7aa Nikos Skalkotos
        self.ptable.setpsize(
567 501e19ec Nikos Skalkotos
            part_num, self.bend - self.ptable.getpoffset(part_num) - 1024)
568 de34e7aa Nikos Skalkotos
569 501e19ec Nikos Skalkotos
        self.field['checksum'] = self.compute_checksum()
570 de34e7aa Nikos Skalkotos
571 de34e7aa Nikos Skalkotos
    def __str__(self):
572 de34e7aa Nikos Skalkotos
        """Print the Disklabel"""
573 de34e7aa Nikos Skalkotos
574 34fd52a7 Nikos Skalkotos
        title = "Disklabel"
575 501e19ec Nikos Skalkotos
        typename = self.field['typename'].strip('\x00').strip()
576 501e19ec Nikos Skalkotos
        packname = self.field['packname'].strip('\x00').strip()
577 501e19ec Nikos Skalkotos
        duid = "".join(x.encode('hex') for x in self.field['uid'])
578 de34e7aa Nikos Skalkotos
        return \
579 34fd52a7 Nikos Skalkotos
            "%s\n%s\n" % (title, len(title) * "=") + \
580 501e19ec Nikos Skalkotos
            "Magic Number: 0x%(magic)x\n" \
581 501e19ec Nikos Skalkotos
            "Drive type: %(dtype)d\n" \
582 501e19ec Nikos Skalkotos
            "Subtype: %(subtype)d\n" % self.field + \
583 501e19ec Nikos Skalkotos
            "Typename: %s\n" % typename + \
584 501e19ec Nikos Skalkotos
            "Pack Identifier: %s\n" % packname + \
585 501e19ec Nikos Skalkotos
            "# of bytes per sector: %(secsize)d\n" \
586 501e19ec Nikos Skalkotos
            "# of data sectors per track: %(nsectors)d\n" \
587 501e19ec Nikos Skalkotos
            "# of tracks per cylinder: %(ntracks)d\n" \
588 501e19ec Nikos Skalkotos
            "# of data cylinders per unit: %(ncylinders)d\n" \
589 501e19ec Nikos Skalkotos
            "# of data sectors per cylinder: %(secpercyl)d\n" \
590 501e19ec Nikos Skalkotos
            "# of data sectors per unit: %(secperunit)d\n" % self.field + \
591 501e19ec Nikos Skalkotos
            "DUID: %s\n" % duid + \
592 501e19ec Nikos Skalkotos
            "Alt. cylinders per unit: %(acylinders)d\n" \
593 501e19ec Nikos Skalkotos
            "Start of useable region (high part): %(bstarth)d\n" \
594 501e19ec Nikos Skalkotos
            "Size of useable region (high part): %(bendh)d\n" \
595 501e19ec Nikos Skalkotos
            "Start of useable region: %(bstart)d\n" \
596 501e19ec Nikos Skalkotos
            "End of usable region: %(bend)d\n" \
597 501e19ec Nikos Skalkotos
            "Generic Flags: %(flags)r\n" \
598 501e19ec Nikos Skalkotos
            "Drive data: %(drivedata)r\n" \
599 501e19ec Nikos Skalkotos
            "Number of data sectors (high part): %(secperunith)d\n" \
600 501e19ec Nikos Skalkotos
            "Version: %(version)d\n" \
601 501e19ec Nikos Skalkotos
            "Reserved for future use: %(spare)r\n" \
602 501e19ec Nikos Skalkotos
            "The magic number again: 0x%(magic2)x\n" \
603 501e19ec Nikos Skalkotos
            "Checksum: %(checksum)d\n" \
604 501e19ec Nikos Skalkotos
            "Number of partitions: %(npartitions)d\n"  \
605 501e19ec Nikos Skalkotos
            "Size of boot aread at sn0: %(bbsize)d\n"  \
606 501e19ec Nikos Skalkotos
            "Max size of fs superblock: %(sbsize)d\n" % self.field + \
607 de34e7aa Nikos Skalkotos
            "%s" % self.ptable
608 de34e7aa Nikos Skalkotos
609 de34e7aa Nikos Skalkotos
610 de34e7aa Nikos Skalkotos
if __name__ == '__main__':
611 de34e7aa Nikos Skalkotos
612 de34e7aa Nikos Skalkotos
    usage = "Usage: %prog [options] <input_media>"
613 de34e7aa Nikos Skalkotos
    parser = optparse.OptionParser(usage=usage)
614 de34e7aa Nikos Skalkotos
615 de34e7aa Nikos Skalkotos
    parser.add_option("-l", "--list", action="store_true", dest="list",
616 de34e7aa Nikos Skalkotos
                      default=False,
617 de34e7aa Nikos Skalkotos
                      help="list the disklabel on the specified media")
618 1de1eff5 Nikos Skalkotos
    parser.add_option("--get-last-partition", action="store_true",
619 1de1eff5 Nikos Skalkotos
                      dest="last_part", default=False,
620 de34e7aa Nikos Skalkotos
                      help="print the label of the last partition")
621 1de1eff5 Nikos Skalkotos
    parser.add_option("--get-duid", action="store_true", dest="duid",
622 de34e7aa Nikos Skalkotos
                      default=False,
623 de34e7aa Nikos Skalkotos
                      help="print the disklabel unique identifier")
624 de34e7aa Nikos Skalkotos
    parser.add_option("-d", "--enlarge-disk", type="int", dest="disk_size",
625 de34e7aa Nikos Skalkotos
                      default=None, metavar="SIZE",
626 de34e7aa Nikos Skalkotos
                      help="Enlarge the disk to this SIZE (in sectors)")
627 de34e7aa Nikos Skalkotos
    parser.add_option(
628 de34e7aa Nikos Skalkotos
        "-p", "--enlarge-partition", action="store_true",
629 de34e7aa Nikos Skalkotos
        dest="enlarge_partition", default=False,
630 de34e7aa Nikos Skalkotos
        help="Enlarge the last partition to cover up the free space")
631 de34e7aa Nikos Skalkotos
632 de34e7aa Nikos Skalkotos
    options, args = parser.parse_args(sys.argv[1:])
633 de34e7aa Nikos Skalkotos
634 de34e7aa Nikos Skalkotos
    if len(args) != 1:
635 de34e7aa Nikos Skalkotos
        parser.error("Wrong number of arguments")
636 de34e7aa Nikos Skalkotos
637 be5f0160 Nikos Skalkotos
    disk = Disk(args[0])
638 de34e7aa Nikos Skalkotos
639 de34e7aa Nikos Skalkotos
    if options.list:
640 be5f0160 Nikos Skalkotos
        print disk
641 de34e7aa Nikos Skalkotos
        sys.exit(0)
642 de34e7aa Nikos Skalkotos
643 de34e7aa Nikos Skalkotos
    if options.duid:
644 501e19ec Nikos Skalkotos
        print "%s" % "".join(x.encode('hex') for x in disk.get_duid())
645 de34e7aa Nikos Skalkotos
        sys.exit(0)
646 de34e7aa Nikos Skalkotos
647 de34e7aa Nikos Skalkotos
    if options.last_part:
648 be5f0160 Nikos Skalkotos
        print "%c" % chr(ord('a') + disk.get_last_partition_id())
649 de34e7aa Nikos Skalkotos
650 de34e7aa Nikos Skalkotos
    if options.disk_size is not None:
651 be5f0160 Nikos Skalkotos
        disk.enlarge(options.disk_size)
652 de34e7aa Nikos Skalkotos
653 de34e7aa Nikos Skalkotos
    if options.enlarge_partition:
654 be5f0160 Nikos Skalkotos
        disk.enlarge_last_partition()
655 de34e7aa Nikos Skalkotos
656 be5f0160 Nikos Skalkotos
    disk.write()
657 de34e7aa Nikos Skalkotos
658 de34e7aa Nikos Skalkotos
sys.exit(0)
659 de34e7aa Nikos Skalkotos
660 de34e7aa Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :