9 from pbs import dmsetup
10 from pbs import blockdev
12 from pbs import kpartx
14 from pbs import umount
18 def __init__(self, source):
19 self._cleanup_jobs = []
23 def _add_cleanup(self, job, *args):
24 self._cleanup_jobs.append((job, args))
26 def _losetup(self, fname):
27 loop = losetup.find_unused_loop_device()
29 self._add_cleanup(loop.unmount)
32 def _dir_to_disk(self):
33 raise NotImplementedError
36 while len(self._cleanup_jobs):
37 job, args = self._cleanup_jobs.pop()
41 sourcedev = self.source
42 mode = os.stat(self.source).st_mode
43 if stat.S_ISDIR(mode):
44 return self._losetup(self._dir_to_disk())
45 elif stat.S_ISREG(mode):
46 sourcedev = self._losetup(self.source)
47 elif not stat.S_ISBLK(mode):
48 raise ValueError("Value for self.source is invalid")
50 # Take a snapshot and return it to the user
51 size = blockdev('--getsize', sourcedev)
52 cowfd, cow = tempfile.mkstemp()
53 self._add_cleanup(os.unlink, cow)
54 dd('if=/dev/zero', 'of=%s' % cow, 'count=%d' % (1024*1024))#(int(size)/4))
55 cowdev = self._losetup(cow)
57 snapshot = uuid.uuid4().hex
58 tablefd, table = tempfile.mkstemp()
60 os.write(tablefd, "0 %d snapshot %s %s n 8" % \
61 (int(size), sourcedev, cowdev))
62 dmsetup('create', snapshot, table)
63 self._add_cleanup(dmsetup, 'remove', snapshot)
67 new_device = DiskDevice(self, "/dev/mapper/%s" % snapshot)
68 self._devices.append(new_device)
71 class DiskDevice(object):
73 def __init__(self, disk, device):
76 self.partitions_mapped = False
77 self.magic_number = uuid.uuid4().hex
79 def list_partitions(self):
80 output = kpartx("-l", "-p", self.magic_number, self.dev)
81 return [ "/dev/mapper/%s" % x for x in
82 re.findall('^\S+', str(output), flags=re.MULTILINE)]
84 def mount(self, partition):
85 if not self.partitions_mapped:
86 kpartx("-a", "-p", self.magic_number, self.dev)
87 self.disk._cleanup_jobs.append(kpartx, "-d", "-p",
88 self.magic_number, self.dev)
89 self.partitions_mapped = True
91 targetfd, target = tempfile.mkdtemp()
99 def unmount(self, partition):
102 mode = os.stat(self.source).st_mode
103 if stat.S_ISDIR(mode):
106 # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :