Statistics
| Branch: | Tag: | Revision:

root / snf-image-helper / disklabel.py @ 63656985

History | View | Annotate | Download (23.5 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 de34e7aa Nikos Skalkotos
32 de34e7aa Nikos Skalkotos
BLOCKSIZE = 512
33 de34e7aa Nikos Skalkotos
34 de34e7aa Nikos Skalkotos
LABELSECTOR = 1
35 de34e7aa Nikos Skalkotos
LABELOFFSET = 0
36 de34e7aa Nikos Skalkotos
37 de34e7aa Nikos Skalkotos
BBSIZE = 8192  # size of boot area with label
38 de34e7aa Nikos Skalkotos
SBSIZE = 8192  # max size of fs superblock
39 de34e7aa Nikos Skalkotos
40 be5f0160 Nikos Skalkotos
DISKMAGIC = 0x82564557
41 be5f0160 Nikos Skalkotos
42 de34e7aa Nikos Skalkotos
43 de34e7aa Nikos Skalkotos
class MBR(object):
44 de34e7aa Nikos Skalkotos
    """Represents a Master Boot Record."""
45 de34e7aa Nikos Skalkotos
    class Partition(object):
46 de34e7aa Nikos Skalkotos
        """Represents a partition entry in MBR"""
47 de34e7aa Nikos Skalkotos
        format = "<B3sB3sLL"
48 de34e7aa Nikos Skalkotos
49 de34e7aa Nikos Skalkotos
        def __init__(self, raw_part):
50 de34e7aa Nikos Skalkotos
            """Create a Partition instance"""
51 de34e7aa Nikos Skalkotos
            (
52 de34e7aa Nikos Skalkotos
                self.status,
53 de34e7aa Nikos Skalkotos
                self.start,
54 de34e7aa Nikos Skalkotos
                self.type,
55 de34e7aa Nikos Skalkotos
                self.end,
56 de34e7aa Nikos Skalkotos
                self.first_sector,
57 de34e7aa Nikos Skalkotos
                self.sector_count
58 de34e7aa 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 PartitionTableBase(object):
167 be5f0160 Nikos Skalkotos
    """Base Class for disklabel partition tables"""
168 be5f0160 Nikos Skalkotos
    format = ""
169 34fd52a7 Nikos Skalkotos
170 be5f0160 Nikos Skalkotos
    Partition = namedtuple('Partition', '')
171 be5f0160 Nikos Skalkotos
172 be5f0160 Nikos Skalkotos
    def __init__(self, ptable, pnumber):
173 be5f0160 Nikos Skalkotos
        """Create a Partition Table instance"""
174 be5f0160 Nikos Skalkotos
        self.part = []
175 be5f0160 Nikos Skalkotos
176 be5f0160 Nikos Skalkotos
        size = struct.calcsize(self.format)
177 be5f0160 Nikos Skalkotos
178 be5f0160 Nikos Skalkotos
        raw = cStringIO.StringIO(ptable)
179 be5f0160 Nikos Skalkotos
        try:
180 be5f0160 Nikos Skalkotos
            for i in range(pnumber):
181 be5f0160 Nikos Skalkotos
                p = self.Partition(
182 be5f0160 Nikos Skalkotos
                    *struct.unpack(self.format, raw.read(size)))
183 be5f0160 Nikos Skalkotos
                self.part.append(p)
184 be5f0160 Nikos Skalkotos
        finally:
185 be5f0160 Nikos Skalkotos
            raw.close()
186 be5f0160 Nikos Skalkotos
187 be5f0160 Nikos Skalkotos
    def __str__(self):
188 be5f0160 Nikos Skalkotos
        """Print the Partition table"""
189 be5f0160 Nikos Skalkotos
        val = ""
190 be5f0160 Nikos Skalkotos
        for i in range(len(self.part)):
191 be5f0160 Nikos Skalkotos
            val += "%c: %s\n" % (chr(ord('a') + i), str(self.part[i]))
192 be5f0160 Nikos Skalkotos
        return val
193 be5f0160 Nikos Skalkotos
194 be5f0160 Nikos Skalkotos
    def pack(self):
195 be5f0160 Nikos Skalkotos
        """Packs the partition table into a binary string."""
196 be5f0160 Nikos Skalkotos
        ret = ""
197 be5f0160 Nikos Skalkotos
        for i in range(len(self.part)):
198 be5f0160 Nikos Skalkotos
            ret += struct.pack(self.format, *self.part[i])
199 be5f0160 Nikos Skalkotos
        return ret
200 be5f0160 Nikos Skalkotos
201 be5f0160 Nikos Skalkotos
202 be5f0160 Nikos Skalkotos
class Disk(object):
203 be5f0160 Nikos Skalkotos
    """Represents an BSD Disk"""
204 be5f0160 Nikos Skalkotos
205 be5f0160 Nikos Skalkotos
    def __init__(self, device):
206 be5f0160 Nikos Skalkotos
        """Create a Disk instance"""
207 be5f0160 Nikos Skalkotos
        self.device = device
208 34fd52a7 Nikos Skalkotos
        self.part_num = None
209 34fd52a7 Nikos Skalkotos
        self.disklabel = None
210 34fd52a7 Nikos Skalkotos
211 be5f0160 Nikos Skalkotos
        with open(device, "rb") as d:
212 34fd52a7 Nikos Skalkotos
            sector0 = d.read(BLOCKSIZE)
213 34fd52a7 Nikos Skalkotos
            self.mbr = MBR(sector0)
214 34fd52a7 Nikos Skalkotos
215 34fd52a7 Nikos Skalkotos
            for i in range(4):
216 34fd52a7 Nikos Skalkotos
                ptype = self.mbr.part[i].type
217 34fd52a7 Nikos Skalkotos
                if ptype in (0xa5, 0xa6, 0xa9):
218 34fd52a7 Nikos Skalkotos
                    d.seek(BLOCKSIZE * self.mbr.part[i].first_sector)
219 34fd52a7 Nikos Skalkotos
                    self.part_num = i
220 34fd52a7 Nikos Skalkotos
                    if ptype == 0xa5:  # FreeBSD
221 34fd52a7 Nikos Skalkotos
                        self.disklabel = BSD_Disklabel(d)
222 34fd52a7 Nikos Skalkotos
                    elif ptype == 0xa6:  # OpenBSD
223 34fd52a7 Nikos Skalkotos
                        self.disklabel = OpenBSD_Disklabel(d)
224 34fd52a7 Nikos Skalkotos
                    else:  # NetBSD
225 34fd52a7 Nikos Skalkotos
                        self.disklabel = BSD_Disklabel(d)
226 34fd52a7 Nikos Skalkotos
                    break
227 34fd52a7 Nikos Skalkotos
228 34fd52a7 Nikos Skalkotos
        assert self.disklabel is not None, "No *BSD partition found"
229 34fd52a7 Nikos Skalkotos
230 34fd52a7 Nikos Skalkotos
    def write(self):
231 be5f0160 Nikos Skalkotos
        """Write the changes back to the media"""
232 be5f0160 Nikos Skalkotos
        with open(self.device, 'rw+b') as d:
233 34fd52a7 Nikos Skalkotos
            d.write(self.mbr.pack())
234 34fd52a7 Nikos Skalkotos
235 34fd52a7 Nikos Skalkotos
            d.seek(self.mbr.part[self.part_num].first_sector * BLOCKSIZE)
236 34fd52a7 Nikos Skalkotos
            self.disklabel.write_to(d)
237 34fd52a7 Nikos Skalkotos
238 34fd52a7 Nikos Skalkotos
    def __str__(self):
239 34fd52a7 Nikos Skalkotos
        return str(self.mbr) + str(self.disklabel)
240 34fd52a7 Nikos Skalkotos
241 be5f0160 Nikos Skalkotos
    def enlarge(self, new_size):
242 be5f0160 Nikos Skalkotos
        """Enlarge the disk and return the last usable sector"""
243 34fd52a7 Nikos Skalkotos
244 34fd52a7 Nikos Skalkotos
        # Fix the disklabel
245 be5f0160 Nikos Skalkotos
        end = self.disklabel.enlarge(new_size)
246 34fd52a7 Nikos Skalkotos
247 34fd52a7 Nikos Skalkotos
        # Fix the MBR
248 34fd52a7 Nikos Skalkotos
        start = self.mbr.part[self.part_num].first_sector
249 34fd52a7 Nikos Skalkotos
        self.mbr.part[self.part_num].sector_count = end - start + 1
250 34fd52a7 Nikos Skalkotos
251 34fd52a7 Nikos Skalkotos
        cylinder = end // (self.disklabel.ntracks * self.disklabel.nsectors)
252 34fd52a7 Nikos Skalkotos
        header = (end // self.disklabel.nsectors) % self.disklabel.ntracks
253 34fd52a7 Nikos Skalkotos
        sector = (end % self.disklabel.nsectors) + 1
254 34fd52a7 Nikos Skalkotos
        chs = MBR.Partition.pack_chs(cylinder, header, sector)
255 34fd52a7 Nikos Skalkotos
        self.mbr.part[self.part_num].end = chs
256 34fd52a7 Nikos Skalkotos
257 34fd52a7 Nikos Skalkotos
    def enlarge_last_partition(self):
258 34fd52a7 Nikos Skalkotos
        self.disklabel.enlarge_last_partition()
259 34fd52a7 Nikos Skalkotos
260 34fd52a7 Nikos Skalkotos
261 63656985 Nikos Skalkotos
class DisklabelBase(object):
262 63656985 Nikos Skalkotos
    """Disklabel base class"""
263 63656985 Nikos Skalkotos
264 63656985 Nikos Skalkotos
    def __init__(self, device):
265 63656985 Nikos Skalkotos
        """Create a Disklabel instance"""
266 63656985 Nikos Skalkotos
        raise NotImplementedError
267 63656985 Nikos Skalkotos
268 63656985 Nikos Skalkotos
    def pack(self, checksum=None):
269 63656985 Nikos Skalkotos
        """Return a binary copy of the Disklabel block"""
270 63656985 Nikos Skalkotos
        raise NotImplementedError
271 63656985 Nikos Skalkotos
272 63656985 Nikos Skalkotos
    def compute_checksum(self):
273 63656985 Nikos Skalkotos
        """Compute the checksum of the disklabel"""
274 63656985 Nikos Skalkotos
275 63656985 Nikos Skalkotos
        raw = cStringIO.StringIO(self.pack(0))
276 63656985 Nikos Skalkotos
        checksum = 0
277 63656985 Nikos Skalkotos
        try:
278 63656985 Nikos Skalkotos
            uint16 = raw.read(2)
279 63656985 Nikos Skalkotos
            while uint16 != "":
280 63656985 Nikos Skalkotos
                checksum ^= struct.unpack('<H', uint16)[0]
281 63656985 Nikos Skalkotos
                uint16 = raw.read(2)
282 63656985 Nikos Skalkotos
        finally:
283 63656985 Nikos Skalkotos
            raw.close()
284 63656985 Nikos Skalkotos
285 63656985 Nikos Skalkotos
        return checksum
286 63656985 Nikos Skalkotos
287 63656985 Nikos Skalkotos
    def enlarge(self, new_size):
288 63656985 Nikos Skalkotos
        """Enlarge the disk and return the last usable sector"""
289 63656985 Nikos Skalkotos
        raise NotImplementedError
290 63656985 Nikos Skalkotos
291 63656985 Nikos Skalkotos
    def write_to(self, device):
292 63656985 Nikos Skalkotos
        """Write the disklabel to a device"""
293 63656985 Nikos Skalkotos
        raise NotImplementedError
294 63656985 Nikos Skalkotos
295 63656985 Nikos Skalkotos
    def enlarge_last_partition(self):
296 63656985 Nikos Skalkotos
        """Enlarge the last partition to consume all the usable space"""
297 63656985 Nikos Skalkotos
        raise NotImplementedError
298 63656985 Nikos Skalkotos
299 63656985 Nikos Skalkotos
    def __str__(self):
300 63656985 Nikos Skalkotos
        """Print the Disklabel"""
301 63656985 Nikos Skalkotos
        raise NotImplementedError
302 63656985 Nikos Skalkotos
303 63656985 Nikos Skalkotos
304 63656985 Nikos Skalkotos
class BSD_Disklabel(DisklabelBase):
305 be5f0160 Nikos Skalkotos
    """Represents an BSD Disklabel"""
306 34fd52a7 Nikos Skalkotos
307 be5f0160 Nikos Skalkotos
    class PartitionTable(PartitionTableBase):
308 be5f0160 Nikos Skalkotos
        """Represents a BSD Partition Table"""
309 be5f0160 Nikos Skalkotos
        format = "<IIIBBH"
310 be5f0160 Nikos Skalkotos
        """
311 be5f0160 Nikos Skalkotos
        Partition Entry:
312 be5f0160 Nikos Skalkotos
        Offset  Length          Contents
313 be5f0160 Nikos Skalkotos
        0       4               Number of sectors in partition
314 be5f0160 Nikos Skalkotos
        4       4               Starting sector
315 be5f0160 Nikos Skalkotos
        8       4               Filesystem basic fragment size
316 be5f0160 Nikos Skalkotos
        12      1               Filesystem type
317 be5f0160 Nikos Skalkotos
        13      1               Filesystem fragments per block
318 be5f0160 Nikos Skalkotos
        14      2               Filesystem cylinders per group
319 be5f0160 Nikos Skalkotos
        """
320 34fd52a7 Nikos Skalkotos
321 be5f0160 Nikos Skalkotos
        Partition = namedtuple(
322 be5f0160 Nikos Skalkotos
            'Partition', 'size, offset, fsize, fstype, frag, cpg')
323 be5f0160 Nikos Skalkotos
324 be5f0160 Nikos Skalkotos
    format = "<IHH16s16sIIIIIIHHIHHHHIII20s20sIHHII64s"
325 de34e7aa Nikos Skalkotos
    """
326 de34e7aa Nikos Skalkotos
    Offset  Length          Contents
327 de34e7aa Nikos Skalkotos
    0       4               Magic
328 de34e7aa Nikos Skalkotos
    4       2               Drive Type
329 de34e7aa Nikos Skalkotos
    6       2               Subtype
330 de34e7aa Nikos Skalkotos
    8       16              Type Name
331 de34e7aa Nikos Skalkotos
    24      16              Pack Identifier
332 de34e7aa Nikos Skalkotos
    32      4               Bytes per sector
333 de34e7aa Nikos Skalkotos
    36      4               Data sectors per track
334 be5f0160 Nikos Skalkotos
    40      4               Tracks per cylinder
335 de34e7aa Nikos Skalkotos
    44      4               Data cylinders per unit
336 be5f0160 Nikos Skalkotos
    48      4               Data sectors per cylinder
337 de34e7aa Nikos Skalkotos
    52      4               Data sectors per unit
338 be5f0160 Nikos Skalkotos
    56      2               Spare sectors per track
339 be5f0160 Nikos Skalkotos
    58      2               Spare sectors per cylinder
340 be5f0160 Nikos Skalkotos
    60      4               Alternative cylinders per unit
341 be5f0160 Nikos Skalkotos
    64      2               Rotation Speed
342 be5f0160 Nikos Skalkotos
    66      2               Hardware sector interleave
343 be5f0160 Nikos Skalkotos
    68      2               Sector 0 skew, per track
344 be5f0160 Nikos Skalkotos
    70      2               Sector 0 skew, per cylinder
345 be5f0160 Nikos Skalkotos
    72      4               Head switch time
346 be5f0160 Nikos Skalkotos
    76      4               Track-to-track seek
347 de34e7aa Nikos Skalkotos
    80      4               Generic Flags
348 de34e7aa Nikos Skalkotos
    84      5*4             Drive-type specific information
349 be5f0160 Nikos Skalkotos
    104     5*4             Reserved for future use
350 be5f0160 Nikos Skalkotos
    124     4               Magic Number
351 be5f0160 Nikos Skalkotos
    128     2               Xor of data including partitions
352 be5f0160 Nikos Skalkotos
    130     2               Number of partitions following
353 de34e7aa Nikos Skalkotos
    132     4               size of boot area at sn0, bytes
354 de34e7aa Nikos Skalkotos
    136     4               Max size of fs superblock, bytes
355 de34e7aa Nikos Skalkotos
    140     16*16           Partition Table
356 de34e7aa Nikos Skalkotos
    """
357 de34e7aa Nikos Skalkotos
358 be5f0160 Nikos Skalkotos
359 63656985 Nikos Skalkotos
class OpenBSD_Disklabel(DisklabelBase):
360 be5f0160 Nikos Skalkotos
    """Represents an OpenBSD Disklabel"""
361 be5f0160 Nikos Skalkotos
362 be5f0160 Nikos Skalkotos
    class PartitionTable(PartitionTableBase):
363 de34e7aa Nikos Skalkotos
        """Reprepsents an OpenBSD Partition Table"""
364 de34e7aa Nikos Skalkotos
        format = "<IIHHBBH"
365 de34e7aa Nikos Skalkotos
        """
366 de34e7aa Nikos Skalkotos
        Partition Entry:
367 de34e7aa Nikos Skalkotos
        Offset  Length          Contents
368 de34e7aa Nikos Skalkotos
        0       4               Number of sectors in the partition
369 de34e7aa Nikos Skalkotos
        4       4               Starting sector
370 de34e7aa Nikos Skalkotos
        8       2               Starting sector (high part)
371 de34e7aa Nikos Skalkotos
        10      2               Number of sectors (high part)
372 de34e7aa Nikos Skalkotos
        12      1               Filesystem type
373 de34e7aa Nikos Skalkotos
        13      1               Filesystem Fragment per block
374 de34e7aa Nikos Skalkotos
        14      2               FS cylinders per group
375 de34e7aa Nikos Skalkotos
        """
376 de34e7aa Nikos Skalkotos
377 de34e7aa Nikos Skalkotos
        Partition = namedtuple(
378 de34e7aa Nikos Skalkotos
            'Partition', 'size, offset, offseth, sizeh, fstype, frag, cpg')
379 de34e7aa Nikos Skalkotos
380 de34e7aa Nikos Skalkotos
        def setpsize(self, i, size):
381 de34e7aa Nikos Skalkotos
            """Set size for partition i"""
382 de34e7aa Nikos Skalkotos
            tmp = self.part[i]
383 de34e7aa Nikos Skalkotos
            self.part[i] = self.Partition(size & 0xffffffff, tmp.offset,
384 de34e7aa Nikos Skalkotos
                                          tmp.offseth, size >> 32, tmp.fstype,
385 de34e7aa Nikos Skalkotos
                                          tmp.frag, tmp.cpg)
386 de34e7aa Nikos Skalkotos
387 de34e7aa Nikos Skalkotos
        def getpsize(self, i):
388 34fd52a7 Nikos Skalkotos
            """Get size for partition i"""
389 de34e7aa Nikos Skalkotos
            return (self.part[i].sizeh << 32) + self.part[i].size
390 de34e7aa Nikos Skalkotos
391 de34e7aa Nikos Skalkotos
        def setpoffset(self, i, offset):
392 34fd52a7 Nikos Skalkotos
            """Set offset for partition i"""
393 de34e7aa Nikos Skalkotos
            tmp = self.part[i]
394 de34e7aa Nikos Skalkotos
            self.part[i] = self.Partition(tmp.size, offset & 0xffffffff,
395 de34e7aa Nikos Skalkotos
                                          offset >> 32, tmp.sizeh, tmp.frag,
396 de34e7aa Nikos Skalkotos
                                          tmp.cpg)
397 de34e7aa Nikos Skalkotos
398 de34e7aa Nikos Skalkotos
        def getpoffset(self, i):
399 34fd52a7 Nikos Skalkotos
            """Get offset for partition i"""
400 de34e7aa Nikos Skalkotos
            return (self.part[i].offseth << 32) + self.part[i].offset
401 de34e7aa Nikos Skalkotos
402 be5f0160 Nikos Skalkotos
    format = "<IHH16s16sIIIIII8sIHHIII20sHH16sIHHII364s"
403 be5f0160 Nikos Skalkotos
    """
404 be5f0160 Nikos Skalkotos
    Offset  Length          Contents
405 be5f0160 Nikos Skalkotos
    0       4               Magic
406 be5f0160 Nikos Skalkotos
    4       2               Drive Type
407 be5f0160 Nikos Skalkotos
    6       2               Subtype
408 be5f0160 Nikos Skalkotos
    8       16              Type Name
409 be5f0160 Nikos Skalkotos
    24      16              Pack Identifier
410 be5f0160 Nikos Skalkotos
    32      4               Bytes per sector
411 be5f0160 Nikos Skalkotos
    36      4               Data sectors per track
412 be5f0160 Nikos Skalkotos
    40      4               Tracks per cylinder
413 be5f0160 Nikos Skalkotos
    44      4               Data cylinders per unit
414 be5f0160 Nikos Skalkotos
    48      4               Data sectors per cylinder
415 be5f0160 Nikos Skalkotos
    52      4               Data sectors per unit
416 be5f0160 Nikos Skalkotos
    56      8               Unique label identifier
417 be5f0160 Nikos Skalkotos
    64      4               Alt cylinders per unit
418 be5f0160 Nikos Skalkotos
    68      2               Start of useable region (high part)
419 be5f0160 Nikos Skalkotos
    70      2               Size of usable region (high part)
420 be5f0160 Nikos Skalkotos
    72      4               Start of useable region
421 be5f0160 Nikos Skalkotos
    76      4               End of usable region
422 be5f0160 Nikos Skalkotos
    80      4               Generic Flags
423 be5f0160 Nikos Skalkotos
    84      5*4             Drive-type specific information
424 be5f0160 Nikos Skalkotos
    104     2               Number of data sectors (high part)
425 be5f0160 Nikos Skalkotos
    106     2               Version
426 be5f0160 Nikos Skalkotos
    108     4*4             Reserved for future use
427 be5f0160 Nikos Skalkotos
    124     4               Magic number
428 be5f0160 Nikos Skalkotos
    128     2               Xor of data including partitions
429 be5f0160 Nikos Skalkotos
    130     2               Number of partitions in following
430 be5f0160 Nikos Skalkotos
    132     4               size of boot area at sn0, bytes
431 be5f0160 Nikos Skalkotos
    136     4               Max size of fs superblock, bytes
432 be5f0160 Nikos Skalkotos
    140     16*16           Partition Table
433 be5f0160 Nikos Skalkotos
    """
434 34fd52a7 Nikos Skalkotos
    def __init__(self, device):
435 34fd52a7 Nikos Skalkotos
        """Create a DiskLabel instance"""
436 de34e7aa Nikos Skalkotos
437 34fd52a7 Nikos Skalkotos
        device.seek(BLOCKSIZE, os.SEEK_CUR)
438 34fd52a7 Nikos Skalkotos
        # The offset of the disklabel from the beginning of the partition is
439 34fd52a7 Nikos Skalkotos
        # one sector
440 34fd52a7 Nikos Skalkotos
        sector1 = device.read(BLOCKSIZE)
441 de34e7aa Nikos Skalkotos
442 de34e7aa Nikos Skalkotos
        (self.magic,
443 de34e7aa Nikos Skalkotos
         self.dtype,
444 de34e7aa Nikos Skalkotos
         self.subtype,
445 de34e7aa Nikos Skalkotos
         self.typename,
446 de34e7aa Nikos Skalkotos
         self.packname,
447 de34e7aa Nikos Skalkotos
         self.secsize,
448 de34e7aa Nikos Skalkotos
         self.nsectors,
449 de34e7aa Nikos Skalkotos
         self.ntracks,
450 de34e7aa Nikos Skalkotos
         self.ncylinders,
451 de34e7aa Nikos Skalkotos
         self.secpercyl,
452 de34e7aa Nikos Skalkotos
         self.secperunit,
453 de34e7aa Nikos Skalkotos
         self.uid,
454 de34e7aa Nikos Skalkotos
         self.acylinders,
455 de34e7aa Nikos Skalkotos
         self.bstarth,
456 de34e7aa Nikos Skalkotos
         self.bendh,
457 de34e7aa Nikos Skalkotos
         self.bstart,
458 de34e7aa Nikos Skalkotos
         self.bend,
459 de34e7aa Nikos Skalkotos
         self.flags,
460 de34e7aa Nikos Skalkotos
         self.drivedata,
461 de34e7aa Nikos Skalkotos
         self.secperunith,
462 de34e7aa Nikos Skalkotos
         self.version,
463 de34e7aa Nikos Skalkotos
         self.spare,
464 de34e7aa Nikos Skalkotos
         self.magic2,
465 de34e7aa Nikos Skalkotos
         self.checksum,
466 de34e7aa Nikos Skalkotos
         self.npartitions,
467 de34e7aa Nikos Skalkotos
         self.bbsize,
468 de34e7aa Nikos Skalkotos
         self.sbsize,
469 34fd52a7 Nikos Skalkotos
         ptable_raw) = struct.unpack(self.format, sector1)
470 de34e7aa Nikos Skalkotos
471 be5f0160 Nikos Skalkotos
        assert self.magic == DISKMAGIC, "Disklabel is not valid"
472 de34e7aa Nikos Skalkotos
473 de34e7aa Nikos Skalkotos
        self.ptable = self.PartitionTable(ptable_raw, self.npartitions)
474 de34e7aa Nikos Skalkotos
475 de34e7aa Nikos Skalkotos
    def pack(self, checksum=None):
476 de34e7aa Nikos Skalkotos
        return struct.pack(self.format,
477 de34e7aa Nikos Skalkotos
                           self.magic,
478 de34e7aa Nikos Skalkotos
                           self.dtype,
479 de34e7aa Nikos Skalkotos
                           self.subtype,
480 de34e7aa Nikos Skalkotos
                           self.typename,
481 de34e7aa Nikos Skalkotos
                           self.packname,
482 de34e7aa Nikos Skalkotos
                           self.secsize,
483 de34e7aa Nikos Skalkotos
                           self.nsectors,
484 de34e7aa Nikos Skalkotos
                           self.ntracks,
485 de34e7aa Nikos Skalkotos
                           self.ncylinders,
486 de34e7aa Nikos Skalkotos
                           self.secpercyl,
487 de34e7aa Nikos Skalkotos
                           self.secperunit,
488 de34e7aa Nikos Skalkotos
                           self.uid,
489 de34e7aa Nikos Skalkotos
                           self.acylinders,
490 de34e7aa Nikos Skalkotos
                           self.bstarth,
491 de34e7aa Nikos Skalkotos
                           self.bendh,
492 de34e7aa Nikos Skalkotos
                           self.bstart,
493 de34e7aa Nikos Skalkotos
                           self.bend,
494 de34e7aa Nikos Skalkotos
                           self.flags,
495 de34e7aa Nikos Skalkotos
                           self.drivedata,
496 de34e7aa Nikos Skalkotos
                           self.secperunith,
497 de34e7aa Nikos Skalkotos
                           self.version,
498 de34e7aa Nikos Skalkotos
                           self.spare,
499 de34e7aa Nikos Skalkotos
                           self.magic2,
500 de34e7aa Nikos Skalkotos
                           self.checksum if checksum is None else checksum,
501 de34e7aa Nikos Skalkotos
                           self.npartitions,
502 de34e7aa Nikos Skalkotos
                           self.bbsize,
503 de34e7aa Nikos Skalkotos
                           self.sbsize,
504 de34e7aa Nikos Skalkotos
                           self.ptable.pack() +
505 ee78390c Nikos Skalkotos
                           ((364 - self.npartitions * 16) * '\x00'))
506 de34e7aa Nikos Skalkotos
507 de34e7aa Nikos Skalkotos
    def setdsize(self, dsize):
508 de34e7aa Nikos Skalkotos
        """Set disk size"""
509 de34e7aa Nikos Skalkotos
        self.secperunith = dsize >> 32
510 de34e7aa Nikos Skalkotos
        self.secperunit = dsize & 0xffffffff
511 de34e7aa Nikos Skalkotos
512 de34e7aa Nikos Skalkotos
    def getdsize(self):
513 de34e7aa Nikos Skalkotos
        """Get disk size"""
514 de34e7aa Nikos Skalkotos
        return (self.secperunith << 32) + self.secperunit
515 de34e7aa Nikos Skalkotos
516 de34e7aa Nikos Skalkotos
    def setbstart(self, bstart):
517 de34e7aa Nikos Skalkotos
        """Set start of useable region"""
518 de34e7aa Nikos Skalkotos
        self.bstarth = bstart >> 32
519 de34e7aa Nikos Skalkotos
        self.bstart = bstart & 0xffffffff
520 de34e7aa Nikos Skalkotos
521 de34e7aa Nikos Skalkotos
    def getbstart(self):
522 de34e7aa Nikos Skalkotos
        """Get start of usable region"""
523 de34e7aa Nikos Skalkotos
        return (self.bstarth << 32) + self.bstart
524 de34e7aa Nikos Skalkotos
525 de34e7aa Nikos Skalkotos
    def setbend(self, bend):
526 34fd52a7 Nikos Skalkotos
        """Set size of useable region"""
527 de34e7aa Nikos Skalkotos
        self.bendh = bend >> 32
528 de34e7aa Nikos Skalkotos
        self.bend = bend & 0xffffffff
529 de34e7aa Nikos Skalkotos
530 de34e7aa Nikos Skalkotos
    def getbend(self):
531 34fd52a7 Nikos Skalkotos
        """Get size of usable region"""
532 de34e7aa Nikos Skalkotos
        return (self.bendh << 32) + self.bend
533 de34e7aa Nikos Skalkotos
534 be5f0160 Nikos Skalkotos
    def enlarge(self, new_size):
535 63656985 Nikos Skalkotos
        """Enlarge the disk and return the last usable sector"""
536 de34e7aa Nikos Skalkotos
537 34fd52a7 Nikos Skalkotos
        assert new_size >= self.getdsize(), \
538 34fd52a7 Nikos Skalkotos
            "New size cannot be smaller that %s" % self.getdsize()
539 de34e7aa Nikos Skalkotos
540 de34e7aa Nikos Skalkotos
        # Fix the disklabel
541 de34e7aa Nikos Skalkotos
        self.setdsize(new_size)
542 de34e7aa Nikos Skalkotos
        self.ncylinders = self.getdsize() // (self.nsectors * self.ntracks)
543 de34e7aa Nikos Skalkotos
        self.setbend(self.ncylinders * self.nsectors * self.ntracks)
544 de34e7aa Nikos Skalkotos
545 de34e7aa Nikos Skalkotos
        # Partition 'c' descriptes the entire disk
546 de34e7aa Nikos Skalkotos
        self.ptable.setpsize(2, new_size)
547 de34e7aa Nikos Skalkotos
548 34fd52a7 Nikos Skalkotos
        # Update the checksum
549 de34e7aa Nikos Skalkotos
        self.checksum = self.compute_checksum()
550 de34e7aa Nikos Skalkotos
551 34fd52a7 Nikos Skalkotos
        # getbend() gives back the size of the usable region and not the end of
552 34fd52a7 Nikos Skalkotos
        # the usable region. I named it like this because this is how it is
553 34fd52a7 Nikos Skalkotos
        # named in OpenBSD. To get the last usable sector you need to reduce
554 34fd52a7 Nikos Skalkotos
        # this value by one.
555 34fd52a7 Nikos Skalkotos
        return self.getbend() - 1
556 34fd52a7 Nikos Skalkotos
557 34fd52a7 Nikos Skalkotos
    def write_to(self, device):
558 34fd52a7 Nikos Skalkotos
        """Write the disklabel to a device"""
559 de34e7aa Nikos Skalkotos
560 34fd52a7 Nikos Skalkotos
        # The disklabel starts at sector 1
561 34fd52a7 Nikos Skalkotos
        device.seek(BLOCKSIZE, os.SEEK_CUR)
562 34fd52a7 Nikos Skalkotos
        device.write(self.pack())
563 de34e7aa Nikos Skalkotos
564 de34e7aa Nikos Skalkotos
    def get_last_partition_id(self):
565 de34e7aa Nikos Skalkotos
        """Returns the id of the last partition"""
566 de34e7aa Nikos Skalkotos
        part = 0
567 de34e7aa Nikos Skalkotos
        end = 0
568 de34e7aa Nikos Skalkotos
        # Don't check partition 'c' which is the whole disk
569 de34e7aa Nikos Skalkotos
        for i in filter(lambda x: x != 2, range(self.npartitions)):
570 de34e7aa Nikos Skalkotos
            curr_end = self.ptable.getpsize(i) + self.ptable.getpoffset(i)
571 de34e7aa Nikos Skalkotos
            if end < curr_end:
572 de34e7aa Nikos Skalkotos
                end = curr_end
573 de34e7aa Nikos Skalkotos
                part = i
574 de34e7aa Nikos Skalkotos
575 de34e7aa Nikos Skalkotos
        assert end > 0, "No partition found"
576 de34e7aa Nikos Skalkotos
577 de34e7aa Nikos Skalkotos
        return part
578 de34e7aa Nikos Skalkotos
579 de34e7aa Nikos Skalkotos
    def enlarge_last_partition(self):
580 de34e7aa Nikos Skalkotos
        """Enlarge the last partition to cover up all the free space"""
581 de34e7aa Nikos Skalkotos
582 de34e7aa Nikos Skalkotos
        part_num = self.get_last_partition_id()
583 de34e7aa Nikos Skalkotos
584 de34e7aa Nikos Skalkotos
        end = self.ptable.getpsize(part_num) + self.ptable.getpoffset(part_num)
585 de34e7aa Nikos Skalkotos
586 de34e7aa Nikos Skalkotos
        assert end > 0, "No partition found"
587 de34e7aa Nikos Skalkotos
588 de34e7aa Nikos Skalkotos
        if self.ptable.part[part_num].fstype == 1:  # Swap partition.
589 de34e7aa Nikos Skalkotos
            #TODO: Maybe create a warning?
590 de34e7aa Nikos Skalkotos
            return
591 de34e7aa Nikos Skalkotos
592 de34e7aa Nikos Skalkotos
        if end > (self.getbend() - 1024):
593 de34e7aa Nikos Skalkotos
            return
594 de34e7aa Nikos Skalkotos
595 de34e7aa Nikos Skalkotos
        self.ptable.setpsize(
596 de34e7aa Nikos Skalkotos
            part_num, self.getbend() - self.ptable.getpoffset(part_num) - 1024)
597 de34e7aa Nikos Skalkotos
598 de34e7aa Nikos Skalkotos
        self.checksum = self.compute_checksum()
599 de34e7aa Nikos Skalkotos
600 de34e7aa Nikos Skalkotos
    def __str__(self):
601 de34e7aa Nikos Skalkotos
        """Print the Disklabel"""
602 de34e7aa Nikos Skalkotos
603 34fd52a7 Nikos Skalkotos
        title = "Disklabel"
604 de34e7aa Nikos Skalkotos
        return \
605 34fd52a7 Nikos Skalkotos
            "%s\n%s\n" % (title, len(title) * "=") + \
606 de34e7aa Nikos Skalkotos
            "Magic Number: 0x%x\n" % self.magic + \
607 de34e7aa Nikos Skalkotos
            "Drive type: %d\n" % self.dtype + \
608 de34e7aa Nikos Skalkotos
            "Subtype: %d\n" % self.subtype + \
609 abe2770c Nikos Skalkotos
            "Typename: %s\n" % self.typename.strip('\x00').strip() + \
610 abe2770c Nikos Skalkotos
            "Pack Identifier: %s\n" % self.packname.strip('\x00').strip() + \
611 de34e7aa Nikos Skalkotos
            "Number of bytes per sector: %d\n" % self.secsize + \
612 de34e7aa Nikos Skalkotos
            "Number of data sectors per track: %d\n" % self.nsectors + \
613 de34e7aa Nikos Skalkotos
            "Number of tracks per cylinder: %d\n" % self.ntracks + \
614 de34e7aa Nikos Skalkotos
            "Number of data cylinders per unit: %d\n" % self.ncylinders + \
615 de34e7aa Nikos Skalkotos
            "Number of data sectors per cylinder: %d\n" % self.secpercyl + \
616 de34e7aa Nikos Skalkotos
            "Number of data sectors per unit: %d\n" % self.secperunit + \
617 de34e7aa Nikos Skalkotos
            "DUID: %s\n" % "".join(x.encode('hex') for x in self.uid) + \
618 de34e7aa Nikos Skalkotos
            "Alt. cylinders per unit: %d\n" % self.acylinders + \
619 de34e7aa Nikos Skalkotos
            "Start of useable region (high part): %d\n" % self.bstarth + \
620 de34e7aa Nikos Skalkotos
            "Size of useable region (high part): %d\n" % self.bendh + \
621 de34e7aa Nikos Skalkotos
            "Start of useable region: %d\n" % self.bstart + \
622 de34e7aa Nikos Skalkotos
            "End of usable region: %d\n" % self.bend + \
623 de34e7aa Nikos Skalkotos
            "Generic Flags: %r\n" % self.flags + \
624 de34e7aa Nikos Skalkotos
            "Drive data: %r\n" % self.drivedata + \
625 de34e7aa Nikos Skalkotos
            "Number of data sectors (high part): %d\n" % self.secperunith + \
626 de34e7aa Nikos Skalkotos
            "Version: %d\n" % self.version + \
627 de34e7aa Nikos Skalkotos
            "Reserved for future use: %r\n" % self.spare + \
628 de34e7aa Nikos Skalkotos
            "The magic number again: 0x%x\n" % self.magic2 + \
629 de34e7aa Nikos Skalkotos
            "Checksum: %d\n" % self.checksum + \
630 de34e7aa Nikos Skalkotos
            "Number of partitions: %d\n" % self.npartitions + \
631 de34e7aa Nikos Skalkotos
            "Size of boot aread at sn0: %d\n" % self.bbsize + \
632 de34e7aa Nikos Skalkotos
            "Max size of fs superblock: %d\n" % self.sbsize + \
633 de34e7aa Nikos Skalkotos
            "%s" % self.ptable
634 de34e7aa Nikos Skalkotos
635 de34e7aa Nikos Skalkotos
636 de34e7aa Nikos Skalkotos
if __name__ == '__main__':
637 de34e7aa Nikos Skalkotos
638 de34e7aa Nikos Skalkotos
    usage = "Usage: %prog [options] <input_media>"
639 de34e7aa Nikos Skalkotos
    parser = optparse.OptionParser(usage=usage)
640 de34e7aa Nikos Skalkotos
641 de34e7aa Nikos Skalkotos
    parser.add_option("-l", "--list", action="store_true", dest="list",
642 de34e7aa Nikos Skalkotos
                      default=False,
643 de34e7aa Nikos Skalkotos
                      help="list the disklabel on the specified media")
644 1de1eff5 Nikos Skalkotos
    parser.add_option("--get-last-partition", action="store_true",
645 1de1eff5 Nikos Skalkotos
                      dest="last_part", default=False,
646 de34e7aa Nikos Skalkotos
                      help="print the label of the last partition")
647 1de1eff5 Nikos Skalkotos
    parser.add_option("--get-duid", action="store_true", dest="duid",
648 de34e7aa Nikos Skalkotos
                      default=False,
649 de34e7aa Nikos Skalkotos
                      help="print the disklabel unique identifier")
650 de34e7aa Nikos Skalkotos
    parser.add_option("-d", "--enlarge-disk", type="int", dest="disk_size",
651 de34e7aa Nikos Skalkotos
                      default=None, metavar="SIZE",
652 de34e7aa Nikos Skalkotos
                      help="Enlarge the disk to this SIZE (in sectors)")
653 de34e7aa Nikos Skalkotos
    parser.add_option(
654 de34e7aa Nikos Skalkotos
        "-p", "--enlarge-partition", action="store_true",
655 de34e7aa Nikos Skalkotos
        dest="enlarge_partition", default=False,
656 de34e7aa Nikos Skalkotos
        help="Enlarge the last partition to cover up the free space")
657 de34e7aa Nikos Skalkotos
658 de34e7aa Nikos Skalkotos
    options, args = parser.parse_args(sys.argv[1:])
659 de34e7aa Nikos Skalkotos
660 de34e7aa Nikos Skalkotos
    if len(args) != 1:
661 de34e7aa Nikos Skalkotos
        parser.error("Wrong number of arguments")
662 de34e7aa Nikos Skalkotos
663 be5f0160 Nikos Skalkotos
    disk = Disk(args[0])
664 de34e7aa Nikos Skalkotos
665 de34e7aa Nikos Skalkotos
    if options.list:
666 be5f0160 Nikos Skalkotos
        print disk
667 de34e7aa Nikos Skalkotos
        sys.exit(0)
668 de34e7aa Nikos Skalkotos
669 de34e7aa Nikos Skalkotos
    if options.duid:
670 be5f0160 Nikos Skalkotos
        print "%s" % "".join(x.encode('hex') for x in disk.uid)
671 de34e7aa Nikos Skalkotos
        sys.exit(0)
672 de34e7aa Nikos Skalkotos
673 de34e7aa Nikos Skalkotos
    if options.last_part:
674 be5f0160 Nikos Skalkotos
        print "%c" % chr(ord('a') + disk.get_last_partition_id())
675 de34e7aa Nikos Skalkotos
676 de34e7aa Nikos Skalkotos
    if options.disk_size is not None:
677 be5f0160 Nikos Skalkotos
        disk.enlarge(options.disk_size)
678 de34e7aa Nikos Skalkotos
679 de34e7aa Nikos Skalkotos
    if options.enlarge_partition:
680 be5f0160 Nikos Skalkotos
        disk.enlarge_last_partition()
681 de34e7aa Nikos Skalkotos
682 be5f0160 Nikos Skalkotos
    disk.write()
683 de34e7aa Nikos Skalkotos
684 de34e7aa Nikos Skalkotos
sys.exit(0)
685 de34e7aa Nikos Skalkotos
686 de34e7aa Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :