Support turbo2.
[vuplus_dvbapp] / lib / python / Plugins / SystemPlugins / DeviceManager / plugin.py
1 from Components.Label import Label
2 from Components.ActionMap import ActionMap
3 from Components.config import config, ConfigSelection, getConfigListEntry, ConfigSubsection, ConfigEnableDisable, ConfigYesNo, ConfigInteger
4 from Components.ConfigList import ConfigListScreen
5 from Components.Console import Console
6 from Components.GUIComponent import GUIComponent
7 from Components.Harddisk import harddiskmanager, CheckSfdiskVer, enableUdevEvent
8 from Components.MenuList import MenuList
9 from Components.Pixmap import Pixmap, MultiPixmap
10 from Components.Sources.List import List
11 from Components.Sources.StaticText import StaticText
12 from Plugins.Plugin import PluginDescriptor
13 from Screens.MessageBox import MessageBox
14 from Screens.Screen import Screen
15 from Screens.VirtualKeyBoard import VirtualKeyBoard
16 from Tools.BoundFunction import boundFunction
17 from Tools.LoadPixmap import LoadPixmap
18 from Tools.Notifications import AddNotificationWithCallback
19 from Tools.Directories import pathExists, fileExists, resolveFilename, SCOPE_PLUGINS, SCOPE_CURRENT_PLUGIN, SCOPE_CURRENT_SKIN, SCOPE_METADIR
20 from skin import loadSkin
21 from os import system, makedirs, path, listdir, statvfs, popen
22 import os
23 import re
24 import time
25
26 from Components.Sources.StaticText import StaticText
27 from Components.FileList import FileList
28 from Screens.InputBox import InputBox
29 from Components.Input import Input
30 from Screens.ChoiceBox import ChoiceBox
31 from enigma import eTimer
32 from __init__ import _
33
34 config.plugins.devicemanager = ConfigSubsection()
35 config.plugins.devicemanager.mountcheck_enable = ConfigEnableDisable(default=True)
36
37 def readFile(filename):
38         file = open(filename)
39         data = file.read().strip()
40         file.close()
41         return data
42
43 def byteConversion(byte):
44         if type(byte) == str and len(byte) == 0:
45                 return ""
46         if type(byte) != long:
47                 byte = long(byte)
48         if byte > 1024*1024*1024:
49                 int_part = byte/1024/1024/1024
50                 dec_part = byte%(1024*1024*1024)/(1024*1024)
51                 return "%d.%d GB"%(int_part, dec_part)
52         else:
53                 int_part = byte/1024/1024
54                 dec_part = byte%(1024*1024)/1024
55                 return "%d.%d MB"%(int_part, dec_part)
56
57 def checkStrValue(value , empty = ""):
58         if type(value) != str or len(value) == 0:
59                 return empty
60         return value
61
62 class DeviceManagerConfiguration(Screen, ConfigListScreen):
63         def __init__(self,session):
64                 self.session = session
65                 Screen.__init__(self,session)
66                 self.skinName = "Setup"
67                 self.createConfigList()
68                 ConfigListScreen.__init__(self, self.list, session = self.session)
69                 self["key_red"] = StaticText(_("Cancel"))
70                 self["key_green"] = StaticText(_("OK"))
71                 self["shortcuts"] = ActionMap(["ShortcutActions", "SetupActions" ],
72                 {
73                         "ok": self.keySave,
74                         "cancel": self.keyCancel,
75                         "red": self.keyCancel,
76                         "green": self.keySave,
77                 }, -2)
78                 self.onShown.append(self.setWindowTitle)
79                 
80         def setWindowTitle(self):
81                 self.setTitle(_("DeviceManager configuration"))
82
83         def createConfigList(self):
84                 self.list = []
85                 self.list.append(getConfigListEntry(_("Enable mount check for HDD : "), config.plugins.devicemanager.mountcheck_enable))
86                 self.list.append(getConfigListEntry(_("Harddisk standby after : "), config.usage.hdd_standby))
87
88 class DeviceManager(Screen):
89         skin = """
90                 <screen position="center,center" size="590,350" title="DeviceManager">
91                         <ePixmap pixmap="skin_default/buttons/red.png" position="20,0" size="140,40" alphatest="on" />
92                         <ePixmap pixmap="skin_default/buttons/green.png" position="160,0" size="140,40" alphatest="on" />
93                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="300,0" size="140,40" alphatest="on" />
94                         <ePixmap pixmap="skin_default/buttons/blue.png" position="440,0" size="140,40" alphatest="on" />
95                         <widget name="key_red" position="20,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" foregroundColor="#ffffff" backgroundColor="#9f1313" transparent="1" />
96                         <widget name="key_green" position="160,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" foregroundColor="#ffffff" backgroundColor="#1f771f" transparent="1" />
97                         <widget name="key_yellow" position="300,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" foregroundColor="#ffffff" backgroundColor="#a08500" transparent="1" />
98                         <widget name="key_blue" position="440,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" foregroundColor="#ffffff" backgroundColor="#18188b" transparent="1" />
99                         <ePixmap pixmap="skin_default/div-h.png" position="0,48" size="590,2" alphatest="on" />
100                         <widget source="menu" render="Listbox" position="0,48" size="590,350" scrollbarMode="showOnDemand">
101                                 <convert type="TemplatedMultiContent">
102                                 {"templates":
103                                         {"default": (54,[
104                                                         MultiContentEntryText(pos = (50, 0), size = (510, 30), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 0), # index 0 is vendor  - model
105                                                         MultiContentEntryText(pos = (50, 32), size = (120, 20), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 1), # index 1 is Device
106                                                         MultiContentEntryText(pos = (170, 32), size = (120, 20), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 2), # index 2 is Size
107                                                         MultiContentEntryText(pos = (290, 32), size = (120, 20), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 3), # index 3 is Partitions
108                                                         MultiContentEntryText(pos = (410, 32), size = (130, 20), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 4), # index 4 is Removable
109                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 52), size = (590, 2), png = 5), # png 5 is the div pixmap
110                                                 ]),
111                                         "partitions": (98, [
112                                                         MultiContentEntryText(pos = (50, 0), size = (500, 30), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 0), # index 1 is Partition
113                                                         MultiContentEntryText(pos = (50, 32), size = (500, 20), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 1), # index 2 is Mounted on
114                                                         MultiContentEntryText(pos = (50, 54), size = (500, 20), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 2), # index 3 UUID
115                                                         MultiContentEntryText(pos = (50, 76), size = (130, 20), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 3), # index 4 Type
116                                                         MultiContentEntryText(pos = (180, 76), size = (130, 20), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 4), # index 5 Size_total
117                                                         MultiContentEntryText(pos = (310, 76), size = (190, 20), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 5), # index 6 Size_free
118                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 96), size = (590, 2), png = 6), # png 6 is the div pixmap
119                                                 ]),
120                                         "mountpoint": (54,[
121                                                         MultiContentEntryPixmapAlphaTest(pos = (10, 7), size = (30, 30), png = 0), # index 0: picture
122                                                         MultiContentEntryText(pos = (40, 0), size = (500, 30), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 1), # index 1 name
123                                                         MultiContentEntryText(pos = (40, 32), size = (500, 20), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 2), # index 2 path
124                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 52), size = (590, 2), png = 5), # index 5 is the div pixmap
125                                                 ])
126                                         },
127                                         "fonts": [gFont("Regular", 22),gFont("Regular", 16),gFont("Regular", 28)],
128                                         "itemHeight": 54
129                                 }
130                                 </convert>
131                         </widget>
132                 </screen>
133                 """
134
135         def __init__(self, session):
136                 Screen.__init__(self, session)
137                 self.session = session
138                 self.currList = "default"
139                 self.currDevice = None
140                 self.currPartition = None
141                 self.defaultMountPoint = "/media/hdd"
142                 self.deviceList = []
143                 self["menu"] = List(self.deviceList)
144                 self["key_red"] = Label(_("Close"))
145                 self["key_green"] = Label(" ")
146                 self["key_yellow"] = Label(" ")
147                 self["key_blue"] = Label(" ")
148
149                 self["shortcuts"] = ActionMap(["ShortcutActions", "SetupActions", "MenuActions" ],
150                 {
151                         "ok": self.keyOk,
152                         "cancel": self.keyCancel,
153                         "red": self.keyCancel,
154                         "green": self.keyOk,
155                         "yellow": self.keyYellow,
156                         "blue": self.keyBlue,
157                         "menu": self.keyMenu,
158                 }, -2)
159                 self.DeviceManagerConsole = Console()
160                 self.loadIcon()
161                 if not self.selectionChanged in self["menu"].onSelectionChanged:
162                         self["menu"].onSelectionChanged.append(self.selectionChanged)
163                 self.onLayoutFinish.append(self.showDeviceList)
164                 self.onLayoutFinish.append(self.addPartitionListChange)
165                 self.onClose.append(self.removePartitionListChange)
166                 self.onChangedEntry = []
167                 self.blockDevices = {}
168
169         def addPartitionListChange(self):
170                 harddiskmanager.on_partition_list_change.append(self.partitionListChanged)
171
172         def removePartitionListChange(self):
173                 harddiskmanager.on_partition_list_change.remove(self.partitionListChanged)
174
175         def partitionListChanged(self, action, device):
176                 print "[Device manager] hotplug partitionListChanged"
177                 if self.currList != "default" and device.device[:3] != self.currDevice["blockdev"]:
178                         return
179                 self.showDeviceList()
180
181         def loadIcon(self):
182                 self.icon_button_green = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/buttons/button_green.png"))
183                 self.divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
184
185         def selectionChanged(self):
186                 if self.currList == "partitions":
187                         currentPartition = self.getCurrentPartition()
188                         if currentPartition is not None:
189                                 if currentPartition["fstype"] == "":
190                                         self["key_blue"].setText("")
191                                 elif currentPartition["fstype"][:3] == "ext":
192                                         self["key_blue"].setText(_("Check"))
193                                 else:
194                                         self["key_blue"].setText("")
195
196         def showDeviceList(self):
197                 self.deviceList = []
198                 self["key_red"].setText(_("Close"))
199                 self["key_green"].setText(_("Ok"))
200                 self["key_yellow"].setText(" ")
201                 self["key_blue"].setText(_("Initialize"))
202                 deviceinfo.refresh()
203                 for device in deviceinfo.getBlockDevices():
204                         deviceEntry = (
205                                 "%s - %s"%(device["vendor"], device["model"]), # vendor : str, model : str, index 0 
206                                 _("device : %s")%(device["blockdev"]), # str
207                                 _("Size : %s")%(byteConversion(device["size"])), # str, bytes
208                                 _("Partitions : %s")%(len(device["partitions"])), # list
209                                 _("Removable : %s")%(device["removable"] and 'Yes' or 'No'), # bool [True, False]
210                                 self.divpng, # png 5
211                                 device, # index 6
212                                 )
213 #                       print "[DeviceManager] deviceEntry : ", deviceEntry
214                         self.deviceList.append(deviceEntry)
215                 self.currList = "default"
216                 self["menu"].style = "default"
217                 self["menu"].setList(self.deviceList)
218
219         def showPartitionList(self):
220                 if self.currDevice is None:
221                         return
222                 partitionList = []
223                 for partition in self.currDevice["partitions"]:
224                         partitionInfo = deviceinfo.getPartitionInfo(partition)
225                         partitionEntry = (
226                                 _("Partition : /dev/%s")%partition, # index 0
227                                 _("Mounted on : %s")%checkStrValue(partitionInfo["mountpoint"], _("not mounted")),
228                                 _("UUID : %s")%checkStrValue(partitionInfo["uuid"], _("unknown")),
229                                 _("Type : %s")%checkStrValue(partitionInfo["fstype"], _("unknown")),
230                                 _("Size : %s")%checkStrValue(byteConversion(partitionInfo["size"]), _("unknown")),
231                                 _("Free : %s")%checkStrValue(byteConversion(partitionInfo["free"]), _("unknown")),
232                                 self.divpng, # index 6
233                                 partitionInfo, # index 7
234                         )
235 #                       print "[DeviceManager] partitionEntry : ",partitionEntry
236                         partitionList.append(partitionEntry)
237                 if len(partitionList) != 0:
238                         self["key_red"].setText(_("Devices"))
239                         self["key_green"].setText(_(" "))
240                         self["key_yellow"].setText(_("Format"))
241                         self["key_blue"].setText(_("Check"))
242                         self.currList = "partitions"
243                         self["menu"].style = "partitions"
244                         self["menu"].setList(partitionList)
245                         self.selectionChanged()
246                 else:
247                         self.session.open(MessageBox, _("No partition list found on device.\nPlease click BLUE key and do Initialize to use this device."), MessageBox.TYPE_ERROR, timeout = 10)
248
249         def getCurrentDevice(self):
250                 try:
251                         return self["menu"].getCurrent()[6]
252                 except:
253                         return None
254
255         def getCurrentPartition(self):
256                 try:
257                         return self["menu"].getCurrent()[7]
258                 except:
259                         return None
260
261         def keyOk(self):
262 #               print "keyOk"
263                 if self.currList == "default":
264                         self.currDevice = self.getCurrentDevice()
265                         if self.currDevice is not None:
266                                 if len(self.currDevice["partitions"]) == 0:
267                                         self.session.open(MessageBox, _("No partition list found on device.\nPlease click BLUE key and do Initialize to use this device."), MessageBox.TYPE_ERROR, timeout = 10)
268                                 else:
269                                         self.showPartitionList()
270                         else:
271                                 self.session.open(MessageBox, _("Device not found."), MessageBox.TYPE_ERROR, timeout = 10)
272                 elif self.currList == "partitions":
273                         pass
274                 else:
275                         pass
276
277         def keyCancel(self):
278 #               print "keyCancel"
279                 if self.DeviceManagerConsole is not None:
280                         if len(self.DeviceManagerConsole.appContainers):
281                                 for name in self.DeviceManagerConsole.appContainers.keys():
282                                         self.DeviceManagerConsole.kill(name)
283                 if self.currList == "partitions":
284                         self.currDevice = None
285                         self.showDeviceList()
286                 else: # currList = "default"
287                         self.close()
288
289         def keyYellow(self):
290                 if self.currList == "partitions":
291                         self.choiceBoxFstype()
292
293         def keyBlue(self):
294                 if self.currList == "default":
295                         device = self.getCurrentDevice()
296                         if device is not None:
297                                 self.session.openWithCallback(self.deviceInitCB, DeviceInit, device["blockdev"], device["size"])
298                         else:
299                                 self.session.open(MessageBox, _("Device not found."), MessageBox.TYPE_ERROR, timeout = 10)
300                 elif self.currList == "partitions":
301                         partition = self.getCurrentPartition()
302                         if partition is not None:
303                                 self.session.openWithCallback(self.deviceCheckCB, DeviceCheck, partition)
304                         else:
305                                 self.session.open(MessageBox, _("Partition info is not found."), MessageBox.TYPE_ERROR, timeout = 10)
306
307         def keyMenu(self):
308                 self.session.open(DeviceManagerConfiguration)
309
310         def deviceInitCB(self, ret = True):
311                 self.showDeviceList()
312
313         def deviceCheckCB(self, ret = True):
314                 self.showPartitionList()
315
316         def deviceFormatCB(self, ret = True):
317                 self.showPartitionList()
318
319         def choiceBoxFstype(self):
320                 menu = []
321                 menu.append((_("ext2 - recommended for USB flash memory"), "ext2"))
322                 menu.append((_("ext3 - recommended for harddisks"), "ext3"))
323                 menu.append((_("ext4 - experimental"), "ext4"))
324                 menu.append((_("vfat - for USB flash memory"), "vfat"))
325                 self.session.openWithCallback(self.choiceBoxFstypeCB, ChoiceBox, title=_("Choice filesystem."), list=menu)
326
327         def choiceBoxFstypeCB(self, choice):
328                 if choice is None:
329                         return
330                 else:
331                         partition = self.getCurrentPartition()
332                         if partition is not None:
333                                 self.session.openWithCallback(self.deviceFormatCB, DeviceFormat, partition, choice[1])
334                         else:
335                                 self.session.open(MessageBox, _("Partition info is not found."), MessageBox.TYPE_ERROR, timeout = 10)
336
337 # Initializing Start...
338 class DeviceInit(Screen):
339         skin = """<screen position="0,0" size="0,0"/>"""
340         def __init__(self, session, device, devicesize):
341                 Screen.__init__(self, session)
342                 self.session = session
343                 self.deviceInitConsole = Console()
344                 self.device = device
345                 self.devicesize = int(devicesize)
346                 self.inputbox_partitions = 1
347                 self.inputbox_partitionSizeList = []
348                 self.inputbox_partitionSizeTotal = int(self.devicesize/1024/1024)
349                 self.msgWaiting = None
350                 self.msgWaitingMkfs = None
351                 self.devicenumber = 0
352                 self.newpartitions = 0
353                 self.onLayoutFinish.append(self.timerStart)
354                 self.initStartTimer = eTimer()
355                 self.initStartTimer.callback.append(self.confirmMessage)
356                 self.createFSStartTimer = eTimer()
357                 self.createFSStartTimer.callback.append(self.createFilesystemStart)
358                 self.exitMessageTimer = eTimer()
359                 self.exitMessageTimer.callback.append(self.exitMessage)
360                 self.msg = ""
361                 self.fstype = None
362                 self.mkfs_cmd = ""
363                 self.doMkfsTimer = eTimer()
364                 self.doMkfsTimer.callback.append(self.doMkfs)
365                 self.doInitializeTimer = eTimer()
366                 self.doInitializeTimer.callback.append(self.doInitialize)
367
368                 self.partitionType = "MBR"
369                 self.maxPartNum = 4
370                 self.inputbox_partitionSizeRemain = self.inputbox_partitionSizeTotal
371                 self.unit = "MB"
372                 self.onClose.append(enableUdevEvent)
373
374         def timerStart(self):
375                 enableUdevEvent(False)
376                 self.initStartTimer.start(100,True)
377
378         def confirmMessage(self):
379                 message = _("Do you really want to initialize the device?\nAll data on the device will be lost!")
380                 self.session.openWithCallback(self.confirmed, MessageBox, message)
381
382         def confirmed(self, ret):
383                 if ret:
384                         self.InitializeStart()
385                 else:
386                         self.exit()
387
388         def exit(self, ret = True):
389                 self.close()
390
391         def unmountAll(self, device):
392                 mounts = file('/proc/mounts').read().split('\n')
393                 cmd = ""
394 # umount all
395                 for line in mounts:
396                         if not line.startswith("/dev/" + device):
397                                 continue
398                         cmd += "umount %s ;"% line.split()[0]
399                 print "[DeviceManager] %s"%cmd
400                 os.system(cmd)
401 #recheck if umounted
402                 mounts = file('/proc/mounts').read().split('\n')
403                 for line in mounts:
404                         if line.startswith("/dev/" + device):
405                                 return False
406                 return True
407
408         def InitializeStart(self):
409                 if self.devicesize >= ( 2.2 * 1000 * 1000 * 1000 * 1000 ): # 2.2TB
410                         self.partitionType = "GPT"
411                         self.maxPartNum = 20
412                         self.inputbox_partitionSizeRemain = 100
413                         self.unit = "%"
414
415                 self.InputPartitionSize_step1()
416
417         def InputPartitionSize_step1(self):
418                 self.session.openWithCallback(self.InputPartitionSize_step1_CB, InputBox, title=_("How many partitions do you want?(1-%d)" % self.maxPartNum), text="1", maxSize=False, type=Input.NUMBER)
419
420         def InputPartitionSize_step1_CB(self, ret):
421                 if ret is not None and int(ret) in range(1,self.maxPartNum+1): # MBR 1~4, GPT 1~20
422                         self.inputbox_partitions = int(ret)
423                         self.InputPartitionSize_step2()
424                 else:
425                         self.session.openWithCallback(self.exit, MessageBox, _("The number you entered is wrong!"), MessageBox.TYPE_ERROR, timeout = 10)
426
427         def InputPartitionSize_step2(self):
428                 current_partition = len(self.inputbox_partitionSizeList)+1
429                 if self.inputbox_partitionSizeRemain == 0:
430                         self.choiceBoxFstype()
431                 elif current_partition == self.inputbox_partitions:
432                         self.inputbox_partitionSizeList.append(str(self.inputbox_partitionSizeRemain))
433                         self.choiceBoxFstype()
434                 else:
435                         text = str(int(self.inputbox_partitionSizeRemain/(self.inputbox_partitions-len(self.inputbox_partitionSizeList) )))
436                         self.session.openWithCallback(self.InputPartitionSize_step2_CB, InputBox, title=_("Input size of partition %s.(Unit = %s, Max = %d %s)")%(current_partition, self.unit, self.inputbox_partitionSizeRemain, self.unit), text=text, maxSize=False, type=Input.NUMBER)
437
438         def InputPartitionSize_step2_CB(self, ret):
439                 if ret is not None:
440                         if self.inputbox_partitionSizeRemain < int(ret) or int(ret) == 0:
441                                 self.InputPartitionSize_step2()
442                         else:
443                                 self.inputbox_partitionSizeList.append(str(ret))
444                                 self.inputbox_partitionSizeRemain -= int(ret)
445                                 self.InputPartitionSize_step2()
446                 else:
447                         self.session.openWithCallback(self.exit ,MessageBox, _("The number you entered is wrong!"), MessageBox.TYPE_ERROR, timeout = 10)
448
449         def choiceBoxFstype(self):
450                 menu = []
451                 menu.append((_("ext2 - recommended for USB flash memory"), "ext2"))
452                 menu.append((_("ext3 - recommended for harddisks"), "ext3"))
453                 menu.append((_("ext4 - experimental"), "ext4"))
454                 menu.append((_("vfat - for USB flash memory"), "vfat"))
455                 self.session.openWithCallback(self.choiceBoxFstypeCB, ChoiceBox, title=_("Choice filesystem."), list=menu)
456
457         def choiceBoxFstypeCB(self, choice):
458                 if choice is None:
459                         self.exit()
460                 else:
461                         self.fstype = choice[1]
462                         if self.fstype not in ["ext2", "ext3", "ext4", "vfat"]:
463                                 self.exit()
464                         else:
465                                 self.initInitializeConfirm()
466
467         def initInitializeConfirm(self):
468 #               print self.inputbox_partitionSizeList
469                 partitionsInfo = ""
470                 for index in range(len(self.inputbox_partitionSizeList)):
471                         print "partition %d : %s %s"%(index+1, str(self.inputbox_partitionSizeList[index]), self.unit)
472                         partitionsInfo += "partition %d : %s %s\n"%(index+1, str(self.inputbox_partitionSizeList[index]), self.unit)
473                 partitionsInfo += "filesystem type : %s"%(self.fstype)
474                 self.session.openWithCallback(self.initInitializeConfirmCB, MessageBoxConfirm, _("%s\nStart Device Inititlization?") % partitionsInfo , MessageBox.TYPE_YESNO)
475
476         def initInitializeConfirmCB(self,ret):
477                 if ret:
478                         self.initInitialize()
479                 else:
480                         self.exit()
481         
482         def initInitialize(self):
483                 if not self.unmountAll(self.device):
484                         self.session.openWithCallback(self.exit, MessageBox, _("umounting failed!Maybe some files in mount point are open"), MessageBox.TYPE_ERROR, timeout = 10)
485                 else:
486                         msg = _("InitInitializing, please wait ...")
487                         msg += _("\nDevice : %s")%self.device
488                         msg += _("\nSize : %s MB\n")%self.inputbox_partitionSizeTotal
489                         for index in range(len(self.inputbox_partitionSizeList)):
490                                 msg += _("\npartition %d : %s %s")%(index+1, str(self.inputbox_partitionSizeList[index]), self.unit)
491                         self.msgWaiting = self.session.openWithCallback(self.msgWaitingCB, MessageBox_2, msg, type = MessageBox.TYPE_INFO, enable_input = False)
492                         self.doInitializeTimer.start(500,True)
493
494         def doInitialize(self):
495                 def CheckPartedVer():
496                         cmd = 'parted --version'
497                         lines = os.popen(cmd).readlines()
498                         for l in lines:
499                                 if l.find("parted (GNU parted)") != -1:
500                                         ver = l.split()[3].strip()
501                                         break
502                         try:
503                                 ver = float(ver)
504                         except:
505                                 print "[DeviceManager] check parted version Failed!"
506                                 return 0
507                         return ver
508
509                 partitions = len(self.inputbox_partitionSizeList) # get num of partition
510                 set = ""
511
512                 setAlign = ""
513                 partedVer = CheckPartedVer()
514                 if partedVer >= 2.1: # align option is supported in version 2.1 or later
515                         setAlign = "--align optimal"
516                         if self.devicesize < 1024 * 1000 * 1000: # 1GB
517                                 setAlign = "-a min"
518                         else:
519                                 setAlign = "-a opt"
520
521                 if self.partitionType == "GPT": # partition type is GPT
522                         parttype = 'gpt'
523                 else:
524                         parttype = 'msdos'
525
526                 if partitions == 1:
527                         cmd = 'parted %s /dev/%s --script mklabel %s mkpart primary 0%% 100%%' % (setAlign, self.device, parttype)
528                 else: # has multiple partitions
529                         p_current = 0
530                         for p in range(partitions):
531                                 if p == 0:
532                                         p_start = p_current
533                                         p_end = int( (long(self.inputbox_partitionSizeList[p]) * 100) / self.inputbox_partitionSizeTotal )
534                                         p_current = p_end
535                                 elif p > 0 and partitions > (p + 1):
536                                         p_start = p_current
537                                         p_end = int( (long(self.inputbox_partitionSizeList[p]) * 100) / self.inputbox_partitionSizeTotal )+ p_start
538                                         p_current = p_end
539                                 elif partitions == (p + 1):
540                                         p_start = p_current
541                                         p_end = 100
542
543                                 if p_start == p_end:
544                                         p_end +=1
545                                 if p_end > 100:
546                                         continue
547
548                                 set += 'mkpart primary ext2 %d%% %d%% ' % (p_start, p_end)
549                         cmd = 'parted %s /dev/%s --script mklabel %s %s' % (setAlign, self.device, parttype, set)
550
551                 self.deviceInitConsole.ePopen(cmd, self.initInitializeFinished)
552
553         def initInitializeFinished(self, result, retval, extra_args = None):
554                 if retval == 0:
555                         if self.partitionType == "MBR":
556                                 sfdiskVer = CheckSfdiskVer()
557                                 if sfdiskVer < 2.26: # sfdisk -R option is deprecated at sfdiskVer >= 2.26
558                                         cmd = 'sfdisk -R /dev/%s; sleep 5' % (self.device)
559                                 elif path.exists('/usr/sbin/partprobe'):
560                                         cmd = 'partprobe /dev/%s; sleep 5' % (self.device)
561                                 elif path.exists('/usr/sbin/partx'):
562                                         cmd = 'partx -u /dev/%s; sleep 5' % (self.device)
563                                 else:
564                                         cmd = 'sfdisk -R /dev/%s; sleep 5' % (self.device)
565                         else: # is GPT
566                                 cmd = "sleep 5"
567                         self.deviceInitConsole.ePopen(cmd, self.initInitializingRefreshFinished)
568                 else:
569                         errorMsg = "initInitializing device Error at /dev/%s"%self.device
570                         self.msgWaiting.run_close(False, errorMsg)
571
572         def initInitializingRefreshFinished(self, result, retval, extra_args = None):
573                 cmd = "/bin/umount /dev/%s*" % (self.device)
574                 self.deviceInitConsole.ePopen(cmd, self.initInitializingUmountFinished)
575
576         def initInitializingUmountFinished(self, result, retval, extra_args = None):
577                 partitions = open("/proc/partitions")
578                 self.devicenumber = 0
579                 self.newpartitions = 0
580                 for part in partitions:
581                         res = re.sub("\s+", " ", part).strip().split(" ")
582                         if res and len(res) == 4 and res[3][:3] == self.device:
583                                 if len(res[3]) > 3 and res[3][:2] == "sd":
584                                         self.newpartitions += 1
585                 partitions.close()
586                 partNum = len(self.inputbox_partitionSizeList) # get num of partition
587                 if self.newpartitions != partNum:
588                         errorMsg = "Partitioning device Error at /dev/%s"%self.device
589                         self.msgWaiting.run_close(False, errorMsg)
590                 else:
591                         self.msgWaiting.run_close(True)
592 #               self.createFilesystem(self.newpartitions)
593
594         def createFilesystem(self, newpartitions):
595                 self.devicenumber = self.devicenumber + 1
596                 fulldevicename = "/dev/" + self.device + str(self.devicenumber)
597                 shortdevicename = self.device + str(self.devicenumber)
598 # get partition size
599                 partitions = open("/proc/partitions")
600                 for part in partitions:
601                         res = re.sub("\s+", " ", part).strip().split(" ")
602                         if res and len(res) == 4:
603                                 if res[3] == shortdevicename:
604                                         partitionsize = int(res[2])
605                                         break
606                 partitions.close()
607
608                 if self.fstype == "ext4":
609                         cmd = "mkfs.ext4 -F "
610                         if partitionsize > 2 * 1024 * 1024: # 2GB
611                                 cmd += "-T largefile "
612                         cmd += "-O extent,flex_bg,large_file,uninit_bg -m1 " + fulldevicename
613                 elif self.fstype == "ext3":
614                         cmd = "mkfs.ext3 -F "
615                         if partitionsize > 2 * 1024 * 1024:
616                                 cmd += "-T largefile "
617                         cmd += "-m0 " + fulldevicename
618                 elif self.fstype == "ext2":
619                         cmd = "mkfs.ext2 -F "
620                         if partitionsize > 2 * 1024 * 1024:
621                                 cmd += "-T largefile "
622                         cmd += "-m0 " + fulldevicename
623                 elif self.fstype == "vfat":
624                         if partitionsize > 4 * 1024 * 1024 * 1024:
625                                 cmd = "mkfs.vfat -I -S4096 " + fulldevicename
626                         else:
627                                 cmd = "mkfs.vfat -I " + fulldevicename
628                                 if partitionsize > 2 * 1024 * 1024: # if partiton size larger then 2GB, use FAT32
629                                         cmd += " -F 32"
630
631                 else:
632                         self.createFilesystemFinished(None, -1, (self.device, fulldevicename))
633                         return
634
635                 msg = _("Create filesystem, please wait ...")
636                 msg += _("\nPartition : %s") % (fulldevicename)
637                 msg += _("\nFilesystem : %s") % (self.fstype)
638                 msg += _("\nDisk Size : %s MB") % (self.inputbox_partitionSizeTotal)
639                 msg += _("\nPartition Size : %d %s\n") % (int(self.inputbox_partitionSizeList[self.devicenumber-1]), self.unit)
640                 self.msgWaitingMkfs = self.session.openWithCallback(self.msgWaitingMkfsCB, MessageBox_2, msg, type = MessageBox.TYPE_INFO, enable_input = False)
641                 self.mkfs_cmd = cmd
642                 self.doMkfsTimer.start(500,True)
643
644         def doMkfs(self):
645                 fulldevicename = "/dev/" + self.device + str(self.devicenumber)
646                 self.deviceInitConsole.ePopen(self.mkfs_cmd, self.createFilesystemFinished, (self.device, fulldevicename))
647
648         def createFilesystemFinished(self, result, retval, extra_args = None):
649                 device = extra_args[0]
650                 fulldevicename = extra_args[1]
651                 if retval == 0:
652                         self.msgWaitingMkfs.run_close(True)
653                 else:
654                         errorMsg = _("Creating filesystem Error")
655                         if fulldevicename is not None:
656                                 errorMsg += _(" at /dev/%s")%fulldevicename
657                         self.msgWaitingMkfs.run_close(False, errorMsg)
658
659         def createFilesystemStart(self):
660                 self.createFilesystem(self.newpartitions)
661
662         def msgWaitingCB(self, ret, msg=""):
663                 if ret:
664                         self.createFSStartTimer.start(100,True)
665                 else:
666                         self.success = False
667                         self.msg = msg
668                         self.exitMessageTimer.start(100,True)
669
670         def msgWaitingMkfsCB(self, ret, msg=""):
671                 if self.devicenumber < self.newpartitions:
672                         self.createFSStartTimer.start(100,True)
673                 else:
674                         if ret == True:
675                                 self.success = True
676                                 self.msg = _("Device Initialization finished sucessfully!")
677                                 self.exitMessageTimer.start(100,True)
678                         else:
679                                 self.success = False
680                                 self.msg = msg
681                                 self.exitMessageTimer.start(100,True)
682
683         def exitMessage(self):
684                 if self.success:
685                         self.session.openWithCallback(self.exit, MessageBox, self.msg, MessageBox.TYPE_INFO, timeout = 10)
686                 else:
687                         self.session.openWithCallback(self.exit, MessageBox, self.msg, MessageBox.TYPE_ERROR, timeout = 10)
688
689 # Initializing end
690
691 # device check start..
692 class DeviceCheck(Screen):
693         skin = """<screen position="0,0" size="0,0"/>"""
694         def __init__(self, session, partition):
695                 Screen.__init__(self, session)
696                 self.session = session
697                 self.deviceCheckConsole = Console()
698                 self.partition = partition
699                 self.onLayoutFinish.append(self.timerStart)
700                 self.checkStartTimer = eTimer()
701                 self.checkStartTimer.callback.append(self.confirmMessage)
702                 self.umountTimer = eTimer()
703                 self.umountTimer.callback.append(self.doUnmount)
704
705         def timerStart(self):
706                 self.checkStartTimer.start(100,True)
707
708         def confirmMessage(self):
709                 fssize = self.partition["size"]
710                 if long(fssize) > 1024*1024*1024*16:
711                         message = _("Do you really want to check the filesystem?\nThis could take lots of time!")
712                         self.session.openWithCallback(self.confirmed, MessageBox, message)
713                 else:
714                         self.deviceCheckStart()
715
716         def confirmed(self, ret):
717                 print "confirmed : ",ret
718                 if ret:
719                         self.deviceCheckStart()
720                 else:
721                         self.exit()
722
723         def deviceCheckStart(self):
724                 print "deviceCheckStart "
725                 print "partition : ", self.partition
726                 device = self.partition["partition"]
727                 fstype = self.partition["fstype"]
728                 fssize = self.partition["size"]
729                 if device is not None and fstype.startswith("ext"):
730                         msg = _("Check filesystem, please wait ...")
731                         msg += _("\nDevice : /dev/%s")%(device)
732                         msg += _("\nFilesystem : %s")%(fstype)
733                         self.msgWaiting = self.session.openWithCallback(self.msgWaitingCB, MessageBox_2, msg, type = MessageBox.TYPE_INFO, enable_input = False)
734                         self.umountTimer.start(500,True)
735                 else:
736                         self.exit()
737
738         def doUnmount(self):
739                 device = self.partition["partition"]
740                 mountpoint = self.partition["mountpoint"]
741                 fstype = self.partition["fstype"]
742                 if mountpoint != "":
743                         self.doUmountFsck(device, mountpoint, fstype)
744                 else:
745                         self.umountFsckFinished("NORESULT", 0, (device, mountpoint, fstype))
746
747         def doUmountFsck(self, device, mountpoint, fstype):
748                 cmd = "umount /dev/%s" % device
749                 self.deviceCheckConsole.ePopen(cmd, self.umountFsckFinished, (device, mountpoint, fstype))
750
751         def umountFsckFinished(self, result, retval, extra_args = None):
752                 device = extra_args[0]
753                 mountpoint = extra_args[1]
754                 fstype = extra_args[2]
755                 if retval == 0:
756                         cmd = "fsck." + fstype + " -f -p /dev/" + device
757                         self.deviceCheckConsole.ePopen(cmd, self.fsckFinished, extra_args)
758                 else:
759                         errorMsg = _("Can not umount device /dev/%s.\nMaybe some files of the filesystem are open")%device
760                         self.msgWaiting.run_close(False,errorMsg)
761                         
762         def fsckFinished(self, result, retval, extra_args = None):
763                 device = extra_args[0]
764                 mountpoint = extra_args[1]
765                 if retval == 0:
766                         text = _("Filesystem check finished sucessfully")
767                         self.msgWaiting.run_close(True, text)
768                 else:
769                         text = _("Error checking disk. The disk or filesystem may be damaged")
770                         self.msgWaiting.run_close(False, text)
771
772         def msgWaitingCB(self, ret, msg):
773                 if ret:
774                         self.session.open(MessageBox, msg, MessageBox.TYPE_INFO, timeout = 10)
775                 else:
776                         self.session.open(MessageBox, msg, MessageBox.TYPE_ERROR, timeout = 10)
777
778                 partition = self.partition["partition"]
779                 mountpoint = self.partition["mountpoint"]
780                 fstype = self.partition["fstype"]
781                 if mountpoint != "":
782                         if fstype == "ntfs":
783                                 cmd = "ntfs-3g /dev/" + partition + " " + mountpoint
784                         else:
785                                 cmd = "mount /dev/" + partition + " " + mountpoint
786                         self.deviceCheckConsole.ePopen(cmd, self.mountPartitionFinished)
787                 else:
788                         self.exit()
789
790         def mountPartitionFinished(self, result, retval, extra_args = None):
791                 self.exit()
792
793         def exit(self):
794                 self.close()
795
796 #device check end
797
798 #device format start
799 class DeviceFormat(Screen):
800         skin = """<screen position="0,0" size="0,0"/>"""
801         def __init__(self, session, partition, newfstype):
802                 Screen.__init__(self, session)
803                 self.session = session
804                 self.deviceFormatConsole = Console()
805                 self.partition = partition
806                 self.newfstype = newfstype
807                 self.unmountedList = []
808                 self.onLayoutFinish.append(self.timerStart)
809                 self.formatStartTimer = eTimer()
810                 self.formatStartTimer.callback.append(self.DeviceFormatStart)
811                 self.umountTimer = eTimer()
812                 self.umountTimer.callback.append(self.doUnmount)
813                 self.onClose.append(enableUdevEvent)
814
815         def timerStart(self):
816                 enableUdevEvent(False)
817                 self.formatStartTimer.start(100,True)
818
819         def DeviceFormatStart(self):
820                 print "DeviceFormatStart : ", self.partition,
821                 print "Filesystem : ",self.newfstype
822                 device = self.partition["partition"]
823                 devicepath = "/dev/"+device
824                 fssize = self.partition["size"]
825                 newfstype = self.newfstype
826                 msg = _("Format filesystem, please wait ...")
827                 msg += _("\nDevice : %s")%(devicepath)
828                 msg += _("\nFilesystem : %s")%(newfstype)
829                 msg += _("\nSize : %s")%(byteConversion(fssize))
830                 self.msgWaiting = self.session.openWithCallback(self.msgWaitingCB, MessageBox_2, msg, type = MessageBox_2.TYPE_INFO, enable_input = False, msgBoxID = None)
831                 self.umountTimer.start(500,True)
832
833         def doUnmount(self):
834                 mountpoint = self.partition["mountpoint"]
835                 if mountpoint != "":
836                         self.doumountPartition()
837                 else:
838                         self.umountPartitionFinished("NORESULT", 0)
839
840         def doumountPartition(self):
841                 oldfstype = self.partition["fstype"]
842                 newfstype = self.newfstype
843
844                 if newfstype == oldfstype:
845                         device = self.partition["partition"]
846                 else:
847                         device = self.partition["partition"][:3]
848                 cmd = ""
849                 mounts = file('/proc/mounts','r')
850                 for line in mounts.readlines():
851                         if line.startswith("/dev/%s"%device):
852                                 cmd += "umount %s;"%line.split()[0]
853                                 self.unmountedList.append([line.split()[0], line.split()[1]])
854                 self.deviceFormatConsole.ePopen(cmd, self.umountPartitionFinished)
855
856         def umountPartitionFinished(self, result, retval, extra_args = None):
857                 partition = self.partition["partition"]
858                 oldfstype = self.partition["fstype"]
859                 newfstype = self.newfstype
860                 if retval == 0:
861                         if oldfstype == newfstype:
862                                 self.changePartitionIDFinished("NORESULT", 0)
863                         else:
864                                 sfdiskVer = CheckSfdiskVer()
865                                 if sfdiskVer >= 2.26:
866                                         cmd = "sfdisk --part-type /dev/%s %s" % (partition[:3], partition[3:])
867                                 else:
868                                         cmd = "sfdisk --change-id /dev/%s %s" % (partition[:3], partition[3:])
869
870                                 if newfstype[:3] == "ext":
871                                         cmd += " 83"
872                                 else:
873                                         cmd += " c"
874                                 self.deviceFormatConsole.ePopen(cmd, self.changePartitionIDFinished)
875                 else:
876                         errorMsg = _("Can not umount device /dev/%s.\nMaybe some files of the filesystem are open")%partition[:3]
877                         self.msgWaiting.run_close(False,errorMsg)
878
879         def changePartitionIDFinished(self, result, retval, extra_args = None):
880                 device = self.partition["partition"][:3]
881                 mountpoint = self.partition["mountpoint"]
882                 oldfstype = self.partition["fstype"]
883                 newfstype = self.newfstype
884                 if retval == 0:
885                         if oldfstype == newfstype:
886                                 self.refreshPartitionFinished("NORESULT", 0)
887                         else:
888                                 sfdiskVer = CheckSfdiskVer()
889                                 if sfdiskVer < 2.26: # sfdisk -R option is deprecated at sfdiskVer >= 2.26
890                                         cmd = "sfdisk -R /dev/%s; sleep 5" % (device)
891                                 elif path.exists('/usr/sbin/partprobe'):
892                                         cmd = 'partprobe /dev/%s; sleep 5' % (device)
893                                 elif path.exists('/usr/sbin/partx'):
894                                         cmd = 'partx -u /dev/%s; sleep 5' % (device)
895                                 else:
896                                         cmd = "sfdisk -R /dev/%s; sleep 5" % (device)
897
898                                 self.deviceFormatConsole.ePopen(cmd, self.refreshPartitionFinished)
899                 else:
900                         if result and result.find("Use GNU Parted") > 0:
901                                 print "[DeviceManager] /dev/%s use GNU Parted!" % device
902                                 self.refreshPartitionFinished("NORESULT", 0)
903                         else:
904                                 errorMsg = _("Can not change the partition ID for %s")%device
905                                 self.msgWaiting.run_close(False,errorMsg)
906
907         def refreshPartitionFinished(self, result, retval, extra_args = None):
908                 print "refreshPartitionFinished!"
909                 partition = self.partition["partition"]
910                 mountpoint = self.partition["mountpoint"]
911                 size = int(self.partition["size"])/1024/1024
912                 oldfstype = self.partition["fstype"]
913                 newfstype = self.newfstype
914                 if retval == 0:
915                         if newfstype == "ext4":
916                                 cmd = "mkfs.ext4 -F "
917                                 if size > 2 * 1024:
918                                         cmd += "-T largefile "
919                                 cmd += "-O extent,flex_bg,large_file,uninit_bg -m1 /dev/" + partition
920                         elif newfstype == "ext3":
921                                 cmd = "mkfs.ext3 -F "
922                                 if size > 2 * 1024:
923                                         cmd += "-T largefile "
924                                 cmd += "-m0 /dev/" + partition
925                         elif newfstype == "ext2":
926                                 cmd = "mkfs.ext2 -F "
927                                 if size > 2 * 1024:
928                                         cmd += "-T largefile "
929                                 cmd += "-m0 /dev/" + partition
930                         elif newfstype == "vfat":
931                                 if size > 4 * 1024 * 1024:
932                                         cmd = "mkfs.vfat -I -S4096 /dev/" + partition
933                                 else:
934                                         cmd = "mkfs.vfat -I /dev/" + partition
935                                         if size > 2 * 1024: # if partiton size larger then 2GB, use FAT32
936                                                 cmd += " -F 32"
937                         self.deviceFormatConsole.ePopen(cmd, self.mkfsFinished)
938                 else:
939                         errorMsg = _("Can not format device /dev/%s.\nrefresh partition information failed!")%partition
940                         self.msgWaiting.run_close(False,errorMsg)
941                         
942         def mkfsFinished(self, result, retval, extra_args = None):
943                 print "mkfsFinished!"
944                 partition = self.partition["partition"]
945                 if retval == 0:
946                         cmd = ""
947                         if len(self.unmountedList) == 0:
948                                 self.doMountFinished("NORESULT",0)
949                         for x in self.unmountedList:
950                                 cmd += "mount %s %s;"%(x[0], x[1])
951                                 self.deviceFormatConsole.ePopen(cmd, self.doMountFinished)
952                 else:
953                         text = _("Make filesystem Error /dev/%s.\nPlease check your device.")%partition
954                         self.msgWaiting.run_close(False, text)
955
956         def doMountFinished(self, result, retval, extra_args = None):
957                 print "doMountFinished!"
958                 text = _("Format finished sucessfully.")
959                 self.msgWaiting.run_close(True, text)
960
961         def msgWaitingCB(self, ret, msg):
962                 if ret:
963                         self.session.openWithCallback(self.exit, MessageBox, msg, MessageBox.TYPE_INFO, timeout = 10)
964                 else:
965                         self.session.openWithCallback(self.exit, MessageBox, msg, MessageBox.TYPE_ERROR, timeout = 10)
966
967         def exit(self, ret):
968                 self.close()
969
970 #device format end
971
972 class DeviceInfo():
973         def __init__(self):
974                 self.blockDeviceList = []
975
976         def getBlockDevices(self):
977                 return self.blockDeviceList
978
979         def refresh(self):
980                 self.blockDeviceList = []
981                 self.getBlockDeviceList()
982
983         def getBlockDeviceList(self):
984                 print "get block device Infomations..."
985                 for blockdev in listdir("/sys/block"):
986                         (error, blacklisted, removable, partitions, size, model, vendor) = self.getBlockDeviceInfo(blockdev)
987                         if not blacklisted and not error:
988 #                               print "%s : error %s, blacklisted %s, removable %s, partitions %s, size %s"%(blockdev, error, blacklisted, removable, partitions, size)
989                                 blockDevice = {}
990                                 blockDevice["blockdev"] = blockdev # str
991                                 blockDevice["removable"] = removable # bool [True, False]
992                                 blockDevice["partitions"] = partitions # list
993                                 blockDevice["size"] = size # str
994                                 blockDevice["model"] = model # str
995                                 blockDevice["vendor"] = vendor # str
996                                 self.blockDeviceList.append(blockDevice)
997
998         def SortPartList(self, partList):
999                 length = len(partList)-1
1000                 sorted = False
1001                 while sorted is False:
1002                         sorted = True
1003                         for idx in range(length):
1004                                 if int(partList[idx][3:]) > int(partList[idx+1][3:]):
1005                                         sorted = False
1006                                         partList[idx] , partList[idx+1] = partList[idx+1], partList[idx]
1007
1008         def getBlockDeviceInfo(self, blockdev):
1009                 devpath = "/sys/block/" + blockdev
1010                 error = False
1011                 removable = False
1012                 blacklisted = False
1013                 partitions = []
1014                 size =""
1015                 model = ""
1016                 vendor = ""
1017                 try:
1018                         dev = int(readFile(devpath + "/dev").split(':')[0])
1019                         if dev in (7, 31) or blockdev[0:2] != 'sd': # 7: loop, 31 : mtdblock
1020                                 blacklisted = True
1021                                 return error, blacklisted, removable, partitions, size, model, vendor
1022                         removable = bool(int(readFile(devpath + "/removable")))
1023                         size = str(int(readFile(devpath + "/size").strip())*512)
1024                         model = readFile(devpath + "/device/model")
1025                         vendor = readFile(devpath + "/device/vendor")
1026                         for partition in listdir(devpath):
1027                                 if partition[:len(blockdev)] != blockdev:
1028                                         continue
1029                                 partitions.append(partition)
1030                         self.SortPartList(partitions)
1031
1032                 except IOError:
1033                         error = True
1034                 return error, blacklisted, removable, partitions, size, model, vendor
1035
1036         def getPartitionInfo(self, partition):
1037                 mountPoint = self.getPartitionMountpoint(partition)
1038                 (uuid , fsType) = self.getPartitionBlkidInfo(partition)
1039                 size_total = self.getPartitionSize(partition)
1040                 size_free = ""
1041                 if mountPoint != "":
1042                         size_free = self.getPartitionFree(mountPoint)   
1043                 partitionInfo = {}
1044                 partitionInfo["partition"] = partition
1045                 partitionInfo["mountpoint"] = mountPoint
1046                 partitionInfo["uuid"] = uuid
1047                 partitionInfo["fstype"] = fsType
1048                 partitionInfo["size"] = size_total
1049                 partitionInfo["free"] = size_free
1050                 return partitionInfo
1051
1052         def getPartitionMountpoint(self, partition):
1053                 mounts = file('/proc/mounts').read().split('\n')
1054                 for x in mounts:
1055                         if not x.startswith('/'):
1056                                 continue
1057                         devpath, mountpoint,  = x.split()[:2]
1058                         if mountpoint.startswith('/autofs'):
1059                                 continue
1060                         if path.basename(devpath) == partition:
1061                                 return mountpoint
1062                 return ""
1063
1064         def getPartitionBlkidInfo(self, partition):
1065                 parttionDev = "/dev/"+str(partition)
1066                 uuid = ""
1067                 partitionType = ""
1068                 cmd = "blkid -c /dev/null "+str(parttionDev)
1069                 try:
1070                         line = popen(cmd).readline().strip()
1071                         if not line.startswith(parttionDev):
1072                                 return (uuid, partitionType)
1073 #                       print "Blikd %s : %s"%(parttionDev, line)
1074                         if line.find(" UUID=") != -1:
1075                                 uuid = line.split(" UUID=")[1].split(' ')[0]
1076                         if line.find(" TYPE=") != -1:
1077                                 partitionType = line.split(" TYPE=")[1].split(' ')[0].strip('"')
1078                 except:
1079                         print "get blkid info error (%s)"%cmd
1080                 return (uuid, partitionType)
1081
1082         def getPartitionSize(self, partition):          
1083                 devpath = "/sys/block/%s/%s"%( str(partition[:3]), str(partition) )
1084                 try:
1085                         size = readFile(devpath + "/size")
1086                         return str(int(size)*512)
1087                 except:
1088                         return ""
1089
1090         def getPartitionFree(self, mountPoint):
1091                 try:
1092                         stat = statvfs(mountPoint)
1093                         size_free = stat.f_bfree*stat.f_bsize
1094                         return size_free
1095                 except:
1096                         return ""
1097
1098         def checkMountPoint(self, check_mountpoint):
1099                 res = []
1100                 try:
1101                         mounts = file('/proc/mounts').read().split('\n')
1102                         for x in mounts:
1103                                 if not x.startswith('/'):
1104                                         continue
1105                                 devpath, mountpoint  = x.split()[:2]
1106                                 if mountpoint == check_mountpoint:
1107                                         res.append(devpath)
1108                 except:
1109                         pass
1110                 return res
1111
1112         def checkMountDev(self, device):
1113                 res = []
1114                 try:
1115                         mounts = file('/proc/mounts').read().split('\n')
1116                         for x in mounts:
1117                                 if not x.startswith('/'):
1118                                         continue
1119                                 devpath, mountpoint  = x.split()[:2]
1120                                 if devpath == device:
1121                                         res.append(mountpoint)
1122                 except:
1123                         pass
1124                 return res
1125
1126         def isMounted(self, devpath, mountpoint):
1127                 try:
1128                         mounts = file('/proc/mounts').readlines()
1129                         for x in mounts:
1130                                 if not x.startswith('/'):
1131                                         continue
1132                                 _devpath, _mountpoint  = x.split()[:2]
1133                                 if devpath == _devpath and mountpoint == _mountpoint:
1134                                         return True
1135                 except:
1136                         pass
1137                 return False
1138
1139         def isMounted_anymp(self, devpath):
1140                 try:
1141                         mounts = open('/proc/mounts', 'r').readlines()
1142                         for x in mounts:
1143                                 if not x.startswith('/'):
1144                                         continue
1145                                 _devPart, _mountpoint  = x.split()[:2]
1146                                 if devpath == _devPart:
1147                                         return True
1148                 except:
1149                         pass
1150                 return False
1151
1152         # check partition type is extended or swap.
1153         def checkSwapExtended(self, partition):
1154                 blockName = partition[:-1]
1155                 partNum = partition[-1]
1156                 data = os.popen("parted /dev/%s print" % blockName).readlines()
1157                 for x in data:
1158                         info = x.strip().split()
1159
1160                         if len(info) > 0 and info[0] == str(partNum):
1161                                 if len(info) >= 5 and info[4].find('extended') != -1: # check Type is extended
1162                                         return True
1163                                 elif len(info) >= 6 and info[5].find('swap') != -1: # check File System is swap
1164                                         return True
1165
1166                 return False
1167
1168         def isMountable(self, partition):
1169                 if self.checkSwapExtended(partition):
1170                         return False
1171
1172                 try:
1173                         if self.isMounted_anymp('/dev/'+partition):
1174                                 return True
1175
1176                         elif os.access('/autofs/'+partition, 0):
1177                                 return True
1178                 except:
1179                         pass
1180                 return False
1181
1182         def isFstabAutoMounted(self, uuid, devpath, mountpoint):
1183 #               print " >> isFstabMounted, uuid : %s, devpath : %s, mountpoint : %s"%(uuid, devpath, mountpoint)
1184                 if mountpoint[-1] == '/':
1185                         mountpoint = mountpoint[:-1]
1186                 data = file('/etc/fstab').read().split('\n')
1187                 for line in data:
1188                         if not line.startswith('/'):
1189                                 continue
1190                         dev, mp, ms = line.split()[0:3]
1191                         if uuid is not None and dev.startswith('UUID'):
1192                                 if dev.split('=')[1] == uuid.strip("\"") and mp == mountpoint and ms == 'auto':
1193 #                                       print " >> line : ", line
1194                                         return True
1195                         elif dev == devpath and mp == mountpoint and ms == 'auto':
1196 #                               print " >> line : ", line
1197                                 return True
1198                 return False
1199
1200         def umountByMountpoint(self, mountpoint):
1201                 if mountpoint is None:
1202                         return False
1203                 try:
1204                         if path.ismount(mountpoint):
1205                                 cmd = "umount " + mountpoint
1206                                 print "[DeviceManager] ", cmd
1207                                 os.system(cmd)
1208                 except:
1209                         print "Umount by mountpoint failed!"
1210                 if not path.ismount(mountpoint):
1211                         return True
1212                 return False
1213
1214         def umountByDevpath(self, devpath):
1215                 cmd = "umount " + devpath
1216                 print "[DeviceManager] ", cmd
1217                 os.system(cmd)
1218
1219 deviceinfo = DeviceInfo()
1220
1221 class MountpointBrowser(Screen):
1222         skin="""
1223                 <screen name="MountpointBrowser" position="center,120" size="670,500" title="Select mountpoint">
1224                         <ePixmap pixmap="skin_default/buttons/red.png" position="20,0" size="140,40" alphatest="on" />
1225                         <ePixmap pixmap="skin_default/buttons/green.png" position="180,0" size="140,40" alphatest="on" />
1226                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="340,0" size="140,40" alphatest="on" />
1227                         <ePixmap pixmap="skin_default/buttons/blue.png" position="500,0" size="140,40" alphatest="on" />
1228                         <widget source="key_red" render = "Label" position="20,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" foregroundColor="#ffffff" backgroundColor="#9f1313" transparent="1" />
1229                         <widget source="key_green" render = "Label" position="180,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" foregroundColor="#ffffff" backgroundColor="#1f771f" transparent="1" />
1230                         <widget source="key_yellow" render = "Label" position="340,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" foregroundColor="#ffffff" backgroundColor="#a08500" transparent="1" />
1231                         <widget source="key_blue" render = "Label" position="500,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" foregroundColor="#ffffff" backgroundColor="#18188b" transparent="1" />
1232                         <eLabel position="10,50" size="650,1" backgroundColor="#b3b3b9"/>
1233                         <widget name="filelist" position="10,60" size="650,440" itemHeight="30" scrollbarMode="showOnDemand"/>
1234                 </screen>
1235         """
1236         def __init__(self, session):
1237                 Screen.__init__(self, session)
1238                 self["key_red"] = StaticText(_("Cancel"))
1239                 self["key_green"] = StaticText(_("Select"))
1240                 self["key_yellow"] = StaticText(_("Create directory"))
1241                 self["key_blue"] = StaticText("Delete directory")
1242                 directory = "/media/"
1243                 inhibitDirs = ["/autofs", "/mnt", "/hdd", "/bin", "/boot", "/dev", "/etc", "/home", "/lib", "/proc", "/sbin", "/share", "/sys", "/tmp", "/usr", "/var"]
1244                 self.filelist = FileList(directory, matchingPattern="", inhibitDirs = inhibitDirs)
1245                 self["filelist"] = self.filelist
1246
1247                 self["shortcuts"] = ActionMap(["ColorActions"],
1248                         {
1249                         "red": self.exit,
1250                         "green": self.select,
1251                         "yellow": self.createDirectory,
1252                         "blue": self.deleteDirectory,
1253                         }, -2)
1254
1255                 self["OkCancelActions"] = ActionMap(["OkCancelActions"],
1256                         {
1257                         "cancel": self.exit,
1258                         "ok": self.ok,
1259                         }, -2)
1260
1261         def ok(self):
1262                 if self.filelist.canDescent():
1263                         self.filelist.descent()
1264
1265         def select(self):
1266                 if self["filelist"].getCurrentDirectory() is not None:
1267                         if self.filelist.canDescent() and self["filelist"].getFilename() and self["filelist"].getFilename().startswith(self["filelist"].getCurrentDirectory()):
1268                                 self.filelist.descent()
1269                                 currDir = self["filelist"].getCurrentDirectory()
1270                                 self.close(currDir)
1271                 else:
1272                         self.close(self["filelist"].getFilename())
1273
1274         def createDirectory(self):
1275                 self.session.openWithCallback(self.createDirectoryCB, VirtualKeyBoard, title = (_("Input mount point path.")), text = "")
1276
1277         def createDirectoryCB(self, retval = None):
1278                 newdir=None
1279                 try:
1280                         if retval is not None:
1281                                 newdir = self["filelist"].getCurrentDirectory()+'/'+retval
1282                                 if not path.exists(newdir):
1283                                         os.system("mkdir %s"%newdir)
1284                                 self.filelist.refresh()
1285                 except:
1286                         if newdir:
1287                                 self.session.open(MessageBox, _("Create directory failed!\n%s")%newdir, MessageBox.TYPE_ERROR, timeout = 10)
1288
1289         def deleteDirectory(self):
1290                 delDir=None
1291                 try:
1292                         if self["filelist"].getCurrentDirectory() is not None:
1293                                 if self.filelist.canDescent() and self["filelist"].getFilename() and self["filelist"].getFilename().startswith(self["filelist"].getCurrentDirectory()):
1294                                         delDir = self["filelist"].getFilename()
1295                                         if path.exists(delDir):
1296                                                 os.system("rmdir '%s'"%delDir)
1297                                         if path.exists(delDir):
1298                                                 self.session.open(MessageBox, _("Delete directory failed!\nMaybe directory is not empty."), MessageBox.TYPE_ERROR, timeout = 10)
1299                                         self.filelist.refresh()
1300                 except:
1301                         if delDir:
1302                                 self.session.open(MessageBox, _("Delete directory failed!\n%s")%newdir, MessageBox.TYPE_ERROR, timeout = 10)
1303
1304         def exit(self):
1305                 self.close(False)
1306
1307 class MessageBoxConfirm(MessageBox):
1308         skin =  """
1309                 <screen position="center,center" size="620,10" title="Message">
1310                         <widget name="text" position="65,8" size="420,0" font="Regular;20" />
1311                         <widget name="ErrorPixmap" pixmap="skin_default/icons/input_error.png" position="5,5" size="53,53" alphatest="blend" />
1312                         <widget name="QuestionPixmap" pixmap="skin_default/icons/input_question.png" position="5,5" size="53,53" alphatest="blend" />
1313                         <widget name="InfoPixmap" pixmap="skin_default/icons/input_info.png" position="5,5" size="53,53" alphatest="blend" />
1314                         <widget name="list" position="100,100" size="380,375" transparent="1" />
1315                         <applet type="onLayoutFinish">
1316 # this should be factored out into some helper code, but currently demonstrates applets.
1317 from enigma import eSize, ePoint
1318
1319 orgwidth  = self.instance.size().width()
1320 orgheight = self.instance.size().height()
1321 orgpos    = self.instance.position()
1322 textsize  = self[&quot;text&quot;].getSize()
1323
1324 # y size still must be fixed in font stuff...
1325 textsize = (textsize[0] + 50, textsize[1] + 50)
1326 offset = 0
1327 if self.type == self.TYPE_YESNO:
1328         offset = 60
1329 wsizex = textsize[0] + 60
1330 wsizey = textsize[1] + offset
1331 if (280 &gt; wsizex):
1332         wsizex = 280
1333 wsize = (wsizex, wsizey)
1334
1335 # resize
1336 self.instance.resize(eSize(*wsize))
1337
1338 # resize label
1339 self[&quot;text&quot;].instance.resize(eSize(*textsize))
1340
1341 # move list
1342 listsize = (wsizex, 50)
1343 self[&quot;list&quot;].instance.move(ePoint(0, textsize[1]))
1344 self[&quot;list&quot;].instance.resize(eSize(*listsize))
1345
1346 # center window
1347 newwidth = wsize[0]
1348 newheight = wsize[1]
1349 self.instance.move(ePoint(orgpos.x() + (orgwidth - newwidth)/2, orgpos.y() + (orgheight - newheight)/2))
1350                         </applet>
1351                 </screen>
1352                 """
1353
1354 dmconfigfile = resolveFilename(SCOPE_PLUGINS, "SystemPlugins/DeviceManager/devicemanager.cfg")
1355
1356 def callBackforDeviceManager(session, callback_result = False):
1357         if callback_result == True:
1358                 session.open(DeviceManager)
1359
1360 def checkMounts(session):
1361         try:
1362                 noMountable_dev = ""
1363                 for blockdev in listdir("/sys/block"):
1364                         devpath = "/sys/block/" + blockdev
1365                         dev = int(readFile(devpath + "/dev").split(':')[0])
1366                         if dev in (7, 31) or blockdev[0:2] != 'sd': # 7: loop, 31 : mtdblock
1367                                 continue
1368                         partitions = []
1369                         noMountable_partitions = []
1370                         for partition in listdir(devpath):
1371                                 if not partition.startswith(blockdev):
1372                                         continue
1373
1374                                 if deviceinfo.checkSwapExtended(partition):
1375                                         continue
1376
1377                                 partitions.append(partition)
1378
1379                                 if deviceinfo.isMounted_anymp('/dev/' + partition):
1380                                         continue
1381
1382                                 if os.access('/autofs/'+partition, 0) is False:
1383                                         noMountable_partitions.append(partition)
1384
1385                         if len(partitions) == 0 or len(noMountable_partitions) != 0:
1386                                 if noMountable_dev != "":
1387                                         noMountable_dev +=  ' '
1388                                 noMountable_dev += blockdev
1389
1390                 if noMountable_dev != "":
1391                                 print "Umountable partitions found."
1392                                 InfoText = _("No mountable devices found.! (%s)\nDo you want to open DeviceManager and do initialize or format this device?\n\n(Open 'Menu->Setup->System -> Harddisk -> DeviceManager'\n and press MENU button to deactivate this check.)")%noMountable_dev
1393                                 AddNotificationWithCallback(
1394                                                                 boundFunction(callBackforDeviceManager, session), 
1395                                                                 MessageBox, InfoText, timeout = 60, default = False
1396                                 )
1397         except:
1398                 print "checkMounts failed!"
1399
1400 def sessionstart(reason, **kwargs):
1401         if reason == 0:
1402                 if kwargs.has_key("session") and config.plugins.devicemanager.mountcheck_enable.value == True:
1403                         session = kwargs["session"]
1404                         checkMounts(session)
1405         elif reason == 1:
1406                 pass
1407
1408 def autostart(reason, **kwargs):
1409         if reason == 0:
1410                 try:
1411 # at first enigma2 start        
1412                         if config.misc.firstrun.value:
1413                                 print "[DeviceManager] autostart : check devices at first start"
1414                                 if not path.exists("/media/hdd"):
1415                                         cmd = "mkdir -p /media/hdd"
1416                                         print "CMD : ", cmd
1417                                         os.system(cmd)
1418                 except:
1419                         print "[DeviceManager] autostart failed!"
1420         elif reason == 1:
1421                 pass
1422
1423 def menu(menuid, **kwargs):
1424         if menuid == "system":
1425                 return [(_("DeviceManager"), main, "device_manager", 50)]
1426         return []
1427
1428 def main(session, **kwargs):
1429         session.open(DeviceManager)
1430
1431 def Plugins(path, **kwargs):
1432         return [
1433                 PluginDescriptor(name = _("DeviceManager"), description = _("manage block devices of your VU+"), where = PluginDescriptor.WHERE_MENU,fnc=menu),
1434                 PluginDescriptor(where = PluginDescriptor.WHERE_SESSIONSTART, needsRestart = True, fnc = sessionstart),
1435                 PluginDescriptor(where = PluginDescriptor.WHERE_AUTOSTART, needsRestart = True, fnc = autostart)
1436                 ]
1437
1438 class MessageBox_2(MessageBox):
1439         def __init__(self, session, text, type = MessageBox.TYPE_YESNO, timeout = -1, close_on_any_key = False, default = True, enable_input = True, msgBoxID = None):
1440                 MessageBox.__init__(self, session, text, type, timeout, close_on_any_key, default, enable_input, msgBoxID)
1441                 self.skinName = "MessageBox"
1442                 self.closeTimer = eTimer()
1443                 self.closeTimer.callback.append(self.msg_close)
1444                 self.devicemanager_ret = False
1445                 self.devicemanager_msg = ""
1446
1447         def msg_close(self):
1448                 self.close(self.devicemanager_ret, self.devicemanager_msg)
1449
1450         def run_close(self, ret, msg=""):
1451                 self.devicemanager_ret = ret
1452                 self.devicemanager_msg = msg
1453                 self.closeTimer.start(100,True)
1454
1455         def createSummary(self):
1456                 return MessageBox_2_Summary
1457
1458 class MessageBox_2_Summary(Screen):
1459         skin="""
1460                 <screen name="MessageBox_2_Summary" position="0,0" size="%d,%d" id="1">
1461                         <widget source="parent.Text" render="Label" position="0,0" size="%d,%d" font="Regular;%d" halign="center" valign="center" />
1462                 </screen>
1463         """
1464         def __init__(self, session, parent):
1465                 w,h   = session.summary_desktop.size().width(), session.summary_desktop.size().height()
1466                 self.skin = self.skin % (w, h, w, h, h/7)
1467                 Screen.__init__(self, session, parent = parent)