/[soft]/usbdumper/trunk/liveusb/creator.py
ViewVC logotype

Contents of /usbdumper/trunk/liveusb/creator.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1110 - (show annotations) (download) (as text)
Wed May 4 21:14:55 2011 UTC (12 years, 11 months ago) by ennael
File MIME type: text/x-python
File size: 10542 byte(s)
update files for usbdumper

1 # -*- coding: utf-8 -*-
2 #
3 # Copyright © 2008 Red Hat, Inc. All rights reserved.
4 # Copyright © 2009 Mandriva. All rights reserved.
5 #
6 # This copyrighted material is made available to anyone wishing to use, modify,
7 # copy, or redistribute it subject to the terms and conditions of the GNU
8 # General Public License v.2. This program is distributed in the hope that it
9 # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
10 # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 # See the GNU General Public License for more details. You should have
12 # received a copy of the GNU General Public License along with this program; if
13 # not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
14 # Floor, Boston, MA 02110-1301, USA. Any Red Hat trademarks that are
15 # incorporated in the source code or documentation are not subject to the GNU
16 # General Public License and may only be used or replicated with the express
17 # permission of Red Hat, Inc.
18 #
19 # Author(s): Luke Macken <lmacken@redhat.com>
20 # Aurelien Lefebvre <alefebvre@mandriva.com>
21 # Luis Medinas <luis.medinas@caixamagica.pt>
22
23 import subprocess
24 import logging
25 import os
26 import re
27 import signal
28
29 from datetime import datetime
30 from stat import ST_SIZE
31 from threading import Thread
32 from time import sleep
33
34 from liveusb import _
35
36 class LiveUSBError(Exception):
37 _message = ""
38 def __init__(self, message): self._message = message
39 def _get_message(self): return self._message
40 def _set_message(self, message): self._message = message
41 message = property(_get_message, _set_message)
42
43 class LiveUSBCreator(object):
44 """ An OS-independent parent class for Live USB Creators """
45
46 iso = None
47 drives = {}
48 pids = []
49 isosize = 0
50 log = None
51 drive = None
52
53 def __init__(self, opts):
54 self.opts = opts
55 self._setup_logger()
56
57 def _setup_logger(self):
58 self.log = logging.getLogger(__name__)
59 level = logging.INFO
60 if self.opts.verbose:
61 level = logging.DEBUG
62 self.log.setLevel(level)
63 self.handler = logging.StreamHandler()
64 self.handler.setLevel(level)
65 formatter = logging.Formatter("[%(module)s:%(lineno)s] %(message)s")
66 self.handler.setFormatter(formatter)
67 self.log.addHandler(self.handler)
68
69 def detect_removable_drives(self):
70 """ This method should populate self.drives with removable devices """
71 raise NotImplementedError
72
73 def terminate(self):
74 """ Terminate any subprocesses that we have spawned """
75 raise NotImplementedError
76
77 def set_iso(self, iso):
78 """ Select the given ISO """
79 self.iso = self._to_unicode(iso)
80 self.isosize = os.stat(self.iso)[ST_SIZE]
81
82 def _to_unicode(self, obj, encoding='utf-8'):
83 if hasattr(obj, 'toUtf8'): # PyQt4.QtCore.QString
84 obj = str(obj.toUtf8())
85 #if isinstance(obj, basestring):
86 # if not isinstance(obj, unicode):
87 # obj = unicode(obj, encoding, 'replace')
88 return obj
89
90 def _test_hybrid_1(self, iso):
91 hybrid = False
92 for i in range(0,512):
93 if not iso.read(1) == '\x00':
94 hybrid = True
95 if hybrid:
96 break
97 return hybrid
98
99 def _test_hybrid_2(self, iso):
100 hybrid = False
101 iso.seek(0x1fe)
102 if iso.read(1) == '\x55':
103 iso.seek(0x1ff)
104 if iso.read(1) == '\xaa':
105 hybrid = True
106 return hybrid
107
108 def _test_hybrid_3(self, iso):
109 hybrid = True
110 iso.seek(0x200)
111 for i in range(0x200,0x8000):
112 if iso.read(1) != '\x00':
113 hybrid = False
114 break
115 return hybrid
116
117 def is_hybrid(self, iso):
118 isofile = open(iso, "rb")
119 hybrid = self._test_hybrid_1(isofile) and self._test_hybrid_2(isofile) and self._test_hybrid_3(isofile)
120 isofile.close()
121 return hybrid
122
123 class LinuxLiveUSBCreator(LiveUSBCreator):
124
125 bus = None # the dbus.SystemBus
126 hal = None # the org.freedesktop.Hal.Manager dbus.Interface
127
128 def detect_removable_drives(self):
129 """ Detect all removable USB storage devices using HAL via D-Bus """
130 import dbus
131 self.drives = {}
132 self.bus = dbus.SystemBus()
133 hal_obj = self.bus.get_object("org.freedesktop.Hal",
134 "/org/freedesktop/Hal/Manager")
135 self.hal = dbus.Interface(hal_obj, "org.freedesktop.Hal.Manager")
136
137 devices = []
138 devices = self.hal.FindDeviceByCapability("storage")
139
140 for device in devices:
141 try:
142 dev = self._get_device(device)
143 if dev.GetProperty("storage.bus") == "usb":
144 self._add_device(dev)
145 except dbus.exceptions.DBusException:
146 pass
147
148 if not len(self.drives):
149 raise LiveUSBError(_("Unable to find any USB drives"))
150
151 def _add_device(self, dev, parent=None):
152 model = None
153 capacity = None
154 try:
155 model = dev.GetProperty('storage.model')
156 capacity = str(dev.GetProperty('storage.removable.media_size'))
157 except Exception:
158 pass
159
160 self.drives[dev.GetProperty('block.device')] = {
161 'name' : dev.GetProperty('block.device'),
162 'model' : model,
163 'capacity' : capacity
164 }
165
166 def _get_device(self, udi):
167 """ Return a dbus Interface to a specific HAL device UDI """
168 import dbus
169 dev_obj = self.bus.get_object("org.freedesktop.Hal", udi)
170 return dbus.Interface(dev_obj, "org.freedesktop.Hal.Device")
171
172 def build_disk(self, progress_thread):
173
174 isosize = float(self.isosize)
175 pattern = "^([0-9]+) bytes .*"
176 patternCompiled = re.compile(pattern)
177
178 pidPattern = "^DDPID=([0-9]+).*"
179 pidPatternCompiled = re.compile(pidPattern)
180
181 drive_infos = self.drives[self.drive]
182 if drive_infos.has_key("capacity") and drive_infos["capacity"]:
183 self.log.debug("Iso size = %s" % str(isosize))
184 self.log.debug("Device capacity = %s " % str(drive_infos['capacity']))
185 if int(drive_infos['capacity']) < int(isosize):
186 raise LiveUSBError(_("Selected iso is too large for the selected device"))
187
188 dd = '/usr/sbin/liveusb-dd.sh "' + self.iso + '" "' + self.drive + '"'
189 self.log.debug(dd)
190 p = subprocess.Popen(dd,
191 shell=True,
192 stdout=subprocess.PIPE,
193 stderr=subprocess.STDOUT,
194 env={"LC_ALL": "C"})
195
196 ppid = p.pid
197 ddpid = None
198
199 self.pids.append(ppid)
200
201 # Updating progress bar by parsing /bin/dd output
202 while True:
203 line = p.stdout.readline()
204 if not line:
205 break
206
207 if not ddpid:
208 pidm = re.findall(pidPatternCompiled, line)
209 if len(pidm) > 0:
210 ddpid = int(pidm[0])
211 self.pids.append(ddpid)
212
213 m = re.findall(patternCompiled, line)
214 if len(m) > 0:
215 current = float(m[0])
216 progress = (current/isosize)*100
217 progress = round(progress, 2)
218 progress_thread.update(progress)
219
220 self.pids.remove(ppid)
221 self.pids.remove(ddpid)
222
223 def terminate(self):
224 for pid in self.pids:
225 try:
226 os.kill(pid, signal.SIGHUP)
227 self.log.debug("Killed process %d" % pid)
228 except OSError:
229 pass
230
231 class WindowsLiveUSBCreator(LiveUSBCreator):
232
233 def detect_removable_drives(self):
234 import win32file, win32api, pywintypes, wmi
235 self.drives = {}
236
237 c = wmi.WMI()
238
239 for physical_disk in c.Win32_DiskDrive ():
240 if physical_disk.InterfaceType == "USB":
241 if len(physical_disk.Capabilities):
242 for objElem in physical_disk.Capabilities:
243 if objElem == 7:
244 self.drives[physical_disk.DeviceID] = {
245 'name' : physical_disk.DeviceID,
246 'model' : physical_disk.Model,
247 'device' : physical_disk.DeviceID,
248 'capacity': physical_disk.Size
249 }
250 break
251 if not len(self.drives):
252 raise LiveUSBError(_("There isn't any removable drive available"))
253
254 def _get_device(self, drive):
255 if not self.drives[drive]:
256 return None
257 return self.drives[drive]['device']
258
259 def build_disk(self, progress_thread):
260
261 isosize = float(self.isosize)
262 pattern = "^([0-9,]+).*"
263 patternCompiled = re.compile(pattern)
264
265 # f = subprocess.Popen(['format', self.drive, '/q', '/y', '/fs:fat32'], shell=True)
266 # self.log.debug("Formating %s" % self.drive)
267 # f.wait()
268 # self.log.debug("Done, exit code: %d" % f.wait())
269
270 dd = os.path.join("tools", "dd.exe")
271 dd += " bs=8M" + " if=\"%s\" of=%s --progress" % (self.iso, self._get_device(self.drive))
272 self.log.debug(dd)
273 p = subprocess.Popen(dd,
274 shell=True,
275 stdout=subprocess.PIPE,
276 stderr=subprocess.STDOUT,
277 universal_newlines=True)
278
279 ppid = p.pid
280
281 self.pids.append(ppid)
282
283 # Updating progress bar by parsing /bin/dd output
284 while True:
285 line = p.stdout.readline()
286 if not line:
287 break
288
289 m = re.findall(patternCompiled, line)
290 if len(m) > 0:
291 current = float(re.sub(",", "", m[0]))
292 progress = (current/isosize)*100
293 progress = round(progress, 2)
294 progress_thread.update(progress)
295
296 self.pids.remove(ppid)
297
298 def terminate(self):
299 """ Terminate any subprocesses that we have spawned """
300 import win32api, win32con, pywintypes
301 for pid in self.pids:
302 try:
303 handle = win32api.OpenProcess(win32con.PROCESS_TERMINATE,
304 False, pid)
305 self.log.debug("Terminating process %s" % pid)
306 win32api.TerminateProcess(handle, -2)
307 win32api.CloseHandle(handle)
308 except pywintypes.error:
309 pass

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.30