enigma2 (20120214 rel32 -> 20120309 rel32)
[enigma2.git] / usr / lib / enigma2 / python / Components / Harddisk.py
1 from os import system, listdir, statvfs, popen, makedirs, stat, major, minor, path, access, readlink, symlink, rmdir, unlink, rename, getcwd, chdir, W_OK
2 from Tools.Directories import SCOPE_HDD, resolveFilename
3 from Tools.BoundFunction import boundFunction
4 from Tools.CList import CList
5 from SystemInfo import SystemInfo
6 import time
7 import re, shutil
8 from Components.Console import Console
9 from config import config, configfile, ConfigYesNo, ConfigText, ConfigSubDict, ConfigSubsection, ConfigBoolean
10
11 def MajorMinor(path):
12         rdev = stat(path).st_rdev
13         return (major(rdev),minor(rdev))
14
15 def readFile(filename):
16         file = open(filename)
17         data = file.read().strip()
18         file.close()
19         return data
20
21 DEVTYPE_UDEV = 0
22 DEVTYPE_DEVFS = 1
23
24
25 class Harddisk:
26         def __init__(self, device, removable = False):
27                 self.device = device
28                 self.isRemovable = removable
29
30                 if access("/dev/.udev", 0):
31                         self.type = DEVTYPE_UDEV
32                 elif access("/dev/.devfsd", 0):
33                         self.type = DEVTYPE_DEVFS
34                 else:
35                         print "Unable to determine structure of /dev fallback to udev"
36                         self.type = DEVTYPE_UDEV
37
38
39                 self.is_sleeping = False                
40                 self.max_idle_time = 0
41                 self.idle_running = False
42                 self.timer = None
43
44                 self.dev_path = ''
45                 self.disk_path = ''
46                 self.phys_path = path.realpath(self.sysfsPath('device'))
47
48                 if self.type == DEVTYPE_UDEV:
49                         self.dev_path = '/dev/' + self.device
50                         self.disk_path = self.dev_path
51
52                 elif self.type == DEVTYPE_DEVFS:
53                         tmp = readFile(self.sysfsPath('dev')).split(':')
54                         s_major = int(tmp[0])
55                         s_minor = int(tmp[1])
56                         for disc in listdir("/dev/discs"):
57                                 dev_path = path.realpath('/dev/discs/' + disc)
58                                 disk_path = dev_path + '/disc'
59                                 try:
60                                         rdev = stat(disk_path).st_rdev
61                                 except OSError:
62                                         continue
63                                 if s_major == major(rdev) and s_minor == minor(rdev):
64                                         self.dev_path = dev_path
65                                         self.disk_path = disk_path
66                                         break
67
68                 print "new Harddisk", self.device, '->', self.dev_path, '->', self.disk_path
69                 if not self.isRemovable:
70                         self.startIdle()
71
72         def __lt__(self, ob):
73                 return self.device < ob.device
74
75         def partitionPath(self, n):
76                 if self.type == DEVTYPE_UDEV:
77                         return self.dev_path + n
78                 elif self.type == DEVTYPE_DEVFS:
79                         return self.dev_path + '/part' + n
80
81         def sysfsPath(self, filename):
82                 return path.realpath('/sys/block/' + self.device + '/' + filename)
83
84         def stop(self):
85                 if self.timer:
86                         self.timer.stop()
87                         self.timer.callback.remove(self.runIdle)
88
89         def bus(self):
90                 # CF (7025 specific)
91                 if self.type == DEVTYPE_UDEV:
92                         ide_cf = False  # FIXME
93                 elif self.type == DEVTYPE_DEVFS:
94                         ide_cf = self.device[:2] == "hd" and "host0" not in self.dev_path
95
96                 internal = "pci" in self.phys_path
97
98                 if ide_cf:
99                         ret = "External (CF)"
100                 elif internal:
101                         ret = "Internal"
102                 else:
103                         ret = "External"
104                 return ret
105
106         def bus_type(self):
107                 # CF (7025 specific)
108                 if self.type == DEVTYPE_UDEV:
109                         ide_cf = False  # FIXME
110                 elif self.type == DEVTYPE_DEVFS:
111                         ide_cf = self.device[:2] == "hd" and "host0" not in self.dev_path
112                         
113                 sata = "pci" in self.phys_path
114                 sata_desc = self.bus_description()
115
116                 if ide_cf:
117                         ret = "IDE"
118                 elif sata:
119                         if sata_desc is not None:
120                                 ret = sata_desc
121                         else:
122                                 ret = "SATA"
123                 else:
124                         ret = "USB"
125                 return ret
126
127         def bus_description(self):
128                 phys = self.phys_path[4:]
129                 from Tools.HardwareInfo import HardwareInfo
130                 if self.device.find('sr') == 0 and self.device[2].isdigit():
131                         devicedb = DEVICEDB_SR
132                 else:
133                         devicedb = DEVICEDB
134
135                 for physdevprefix, pdescription in devicedb.get(HardwareInfo().device_name,{}).items():
136                         #print "bus_description:",phys, physdevprefix, pdescription
137                         if phys.startswith(physdevprefix):
138                                 return pdescription
139                 if phys.find('pci') != -1:
140                         return "SATA"
141                 elif phys.find('usb') != -1:
142                         return "USB"
143                 return "External Storage"
144
145         def diskSize(self):
146                 try:
147                         line = readFile(self.sysfsPath('size'))
148                         cap = int(line)
149                 except:
150                         return 0;
151                 return cap / 1000 * 512 / 1000
152
153         def capacity(self):
154                 cap = self.diskSize()
155                 if cap == 0:
156                         return ""
157                 return "%d.%03d GB" % (cap/1000, cap%1000)
158
159         def model(self, model_only = False, vendor_only = False):
160                 if self.device[:2] == "hd":
161                         return readFile('/proc/ide/' + self.device + '/model')
162                 elif self.device[:2] == "sd":
163                         try:
164                                 vendor = readFile(self.sysfsPath('device/vendor'))
165                                 model = readFile(self.sysfsPath('device/model'))
166                         except:
167                                 vendor = ""
168                                 model = ""
169                                 
170                         if vendor_only:
171                                 return vendor
172                         if model_only:
173                                 return model
174                         return vendor + '-' + model
175                 else:
176                         assert False, "no hdX or sdX"
177
178         def free(self):
179                 try:
180                         mounts = open("/proc/mounts")
181                 except IOError:
182                         return -1
183
184                 lines = mounts.readlines()
185                 mounts.close()
186
187                 for line in lines:
188                         parts = line.strip().split(" ")
189                         real_path = path.realpath(parts[0])
190                         if not real_path[-1].isdigit():
191                                 continue
192                         try:
193                                 if MajorMinor(real_path) == MajorMinor(self.partitionPath(real_path[-1])):
194                                         stat = statvfs(parts[1])
195                                         return stat.f_bfree/1000 * stat.f_bsize/1000
196                         except OSError:
197                                 pass
198                 return -1
199
200         def numPartitions(self):
201                 numPart = -1
202                 if self.type == DEVTYPE_UDEV:
203                         try:
204                                 devdir = listdir('/dev')
205                         except OSError:
206                                 return -1
207                         for filename in devdir:
208                                 if filename.startswith(self.device):
209                                         numPart += 1
210
211                 elif self.type == DEVTYPE_DEVFS:
212                         try:
213                                 idedir = listdir(self.dev_path)
214                         except OSError:
215                                 return -1
216                         for filename in idedir:
217                                 if filename.startswith("disc"):
218                                         numPart += 1
219                                 if filename.startswith("part"):
220                                         numPart += 1
221                 return numPart
222
223         def unmount(self, numpart = None):
224                 try:
225                         mounts = open("/proc/mounts")
226                 except IOError:
227                         return -1
228
229                 lines = mounts.readlines()
230                 mounts.close()
231
232                 cmd = "umount"
233                 for line in lines:
234                         parts = line.strip().split(" ")
235                         real_path = path.realpath(parts[0])
236                         if not real_path[-1].isdigit():
237                                 if numpart is not None and numpart == 0:
238                                         if real_path.startswith("/dev/sd"):
239                                                 uuid = harddiskmanager.getPartitionUUID(self.device)
240                                                 if uuid is not None:
241                                                         try:
242                                                                 if MajorMinor(real_path) == MajorMinor(self.dev_path):
243                                                                         cmd = ' ' . join([cmd, parts[1]])
244                                                                         break
245                                                         except OSError:
246                                                                 pass
247                         try:
248                                 if MajorMinor(real_path) == MajorMinor(self.partitionPath(real_path[-1])):
249                                         cmd = ' ' . join([cmd, parts[1]])
250                                         break
251                         except OSError:
252                                 pass
253                 res = system(cmd)
254                 if cmd == "umount": # nothing found to unmount
255                         res = 0
256                 return (res >> 8)
257
258         def createPartition(self, numpart):
259                 #gpt partitiontype support currently disabled.
260                 """devicename = self.device + "1"
261                 if numpart is not None:
262                         if numpart == 0:
263                                 devicename = self.device
264                         if numpart >= 1:
265                                 devicename = self.device + (str(numpart))
266                 type, sys, size, sizeg = harddiskmanager.getFdiskInfo(devicename)"""
267                 
268                 cmd = 'printf "8,\n;0,0\n;0,0\n;0,0\ny\n" | sfdisk -f -uS ' + self.disk_path
269
270                 #if sys is not None and "GPT" in sys:
271                 #       cmd = 'printf "34,,'+type+'\n;0,0\n;0,0\n;0,0\ny\n" | sfdisk -f -uS ' + self.disk_path
272                 res = system(cmd)
273                 return (res >> 8)
274
275         def mkfs(self):
276                 cmd = "mkfs.ext3 "
277                 if self.diskSize() > 4 * 1024:
278                         cmd += "-T largefile "
279                 cmd += "-m0 -O dir_index " + self.partitionPath("1")
280                 res = system(cmd)
281                 return (res >> 8)
282
283         def mount(self):
284                 try:
285                         fstab = open("/etc/fstab")
286                 except IOError:
287                         return -1
288
289                 lines = fstab.readlines()
290                 fstab.close()
291
292                 res = -1
293                 for line in lines:
294                         parts = line.strip().split(" ")
295                         real_path = path.realpath(parts[0])
296                         if not real_path[-1].isdigit():
297                                 continue
298                         try:
299                                 if MajorMinor(real_path) == MajorMinor(self.partitionPath(real_path[-1])):
300                                         cmd = "mount -t auto " + parts[0]
301                                         res = system(cmd)
302                                         break
303                         except OSError:
304                                 pass
305
306                 return (res >> 8)
307
308         def createMovieFolder(self, isFstabMounted = False):
309                 if isFstabMounted:
310                         try:
311                                 makedirs(resolveFilename(SCOPE_HDD))
312                         except OSError:
313                                 return -1
314                 else:
315                         try:
316                                 makedirs("/autofs/" + self.device + "1/movie")
317                         except OSError:
318                                 return -1
319                 return 0
320
321         def fsck(self, numpart):
322                 # We autocorrect any failures and check if the fs is actually one we can check (currently ext2/ext3)
323                 partitionPath = self.partitionPath("1")
324                 if numpart is not None:
325                         if numpart == 0:
326                                 partitionPath = self.dev_path
327                         if numpart >= 1:
328                                 partitionPath = self.partitionPath(str(numpart))
329
330                 partitionType = harddiskmanager.getBlkidPartitionType(partitionPath)                            
331
332                 res = -1
333                 if access(partitionPath, 0):
334                         if partitionType is not None and partitionType in ("ext2", "ext3"):
335                                 cmd = "fsck." + partitionType + " -f -p " + partitionPath
336                                 res = system(cmd)
337                 return (res >> 8)
338
339         def killPartition(self, n):
340                 part = self.partitionPath("1")
341                 if n is not None:
342                         if n == 0:
343                                 part = self.disk_path
344                         if n >= 1:
345                                 part = self.partitionPath(str(n))
346                 if access(part, 0):
347                         #cmd = 'dd bs=512 count=3 if=/dev/zero of=' + part
348                         cmd = 'dd bs=4k count=3 if=/dev/zero of=' + part
349                         res = system(cmd)
350                 else:
351                         res = 0
352                 return (res >> 8)
353
354         errorList = [ _("Everything is fine"), _("Creating partition failed"), _("Mkfs failed"), _("Mount failed"), _("Create movie folder failed"), _("Fsck failed"), _("Please Reboot"), _("Filesystem contains uncorrectable errors"), _("Unmount failed")]
355
356         def initialize(self, isFstabMounted = False, numpart = None):
357                 if self.unmount(numpart) != 0:
358                         return -8
359
360                 # Udev tries to mount the partition immediately if there is an
361                 # old filesystem on it when fdisk reloads the partition table.
362                 # To prevent that, we overwrite the first sectors of the
363                 # partitions, if the partition existed before. This should work
364                 # for ext2/ext3 and also for GPT/EFI partitions.
365                 if numpart is not None:
366                         for p in range(numpart+1):
367                                 self.killPartition(p)
368                 else:
369                         self.killPartition(1)
370                 if self.createPartition(numpart) != 0:
371                         return -1
372                 
373                 if self.mkfs() != 0:
374                         return -2
375
376                 if isFstabMounted:
377                         if self.mount() != 0:
378                                 return -3
379         
380                 if self.createMovieFolder(isFstabMounted) != 0:
381                         return -4
382
383                 return 0
384
385         def check(self, isFstabMounted = False, numpart = None):
386                 
387                 if self.unmount(numpart) != 0:
388                         return -8
389
390                 res = self.fsck(numpart)
391                 if res & 2 == 2:
392                         return -6
393
394                 if res & 4 == 4:
395                         return -7
396
397                 if res != 0 and res != 1:
398                         # A sum containing 1 will also include a failure
399                         return -5
400                 
401                 if isFstabMounted:
402                         if self.mount() != 0:
403                                 return -3
404
405                 return 0
406
407         def getDeviceDir(self):
408                 return self.dev_path
409
410         def getDeviceName(self):
411                 return self.disk_path
412
413         # the HDD idle poll daemon.
414         # as some harddrives have a buggy standby timer, we are doing this by hand here.
415         # first, we disable the hardware timer. then, we check every now and then if
416         # any access has been made to the disc. If there has been no access over a specifed time,
417         # we set the hdd into standby.
418         def readStats(self):
419                 try:
420                         l = open("/sys/block/%s/stat" % self.device).read()
421                 except IOError:
422                         return -1,-1
423                 (nr_read, _, _, _, nr_write) = l.split()[:5]
424                 return int(nr_read), int(nr_write)
425
426         def startIdle(self):
427                 self.last_access = time.time()
428                 self.last_stat = 0
429                 from enigma import eTimer
430
431                 # disable HDD standby timer
432                 if self.bus() == "External":
433                         Console().ePopen(("sdparm", "sdparm", "--set=SCT=0", self.disk_path))
434                 else:
435                         Console().ePopen(("hdparm", "hdparm", "-S0", self.disk_path))
436                 self.timer = eTimer()
437                 self.timer.callback.append(self.runIdle)
438                 self.idle_running = True
439                 self.setIdleTime(self.max_idle_time) # kick the idle polling loop
440
441         def runIdle(self):
442                 if not self.max_idle_time:
443                         return
444                 t = time.time()
445
446                 idle_time = t - self.last_access
447
448                 stats = self.readStats()
449                 print "nr_read", stats[0], "nr_write", stats[1]
450                 l = sum(stats)
451                 print "sum", l, "prev_sum", self.last_stat
452
453                 if l != self.last_stat and l >= 0: # access
454                         print "hdd was accessed since previous check!"
455                         self.last_stat = l
456                         self.last_access = t
457                         idle_time = 0
458                         self.is_sleeping = False
459                 else:
460                         print "hdd IDLE!"
461
462                 print "[IDLE]", idle_time, self.max_idle_time, self.is_sleeping
463                 if idle_time >= self.max_idle_time and not self.is_sleeping:
464                         self.setSleep()
465
466         def setSleep(self):
467                 if self.bus() == "External":
468                         Console().ePopen(("sdparm", "sdparm", "--command=stop", self.disk_path))
469                 else:
470                         Console().ePopen(("hdparm", "hdparm", "-y", self.disk_path))
471                 self.is_sleeping = True
472
473         def setIdleTime(self, idle):
474                 self.max_idle_time = idle
475                 if self.idle_running:
476                         if not idle:
477                                 self.timer.stop()
478                         else:
479                                 self.timer.start(idle * 100, False)  # poll 10 times per period.
480
481         def isSleeping(self):
482                 return self.is_sleeping
483
484         def isIdle(self):
485                 return self.idle_running
486
487 class Partition:
488         def __init__(self, mountpoint, device = None, description = "", force_mounted = False):
489                 self.mountpoint = mountpoint
490                 self.description = description
491                 self.force_mounted = force_mounted
492                 self.is_hotplug = force_mounted # so far; this might change.
493                 self.device = device
494                 self.disc_path = None
495                 self.uuid = None
496                 self.isMountable = False
497                 self.isReadable = False
498                 self.isWriteable = False
499                 self.isInitialized = False
500                 self.fsType = None
501                 if self.device is not None:
502                         self.updatePartitionInfo()
503
504         def updatePartitionInfo(self):
505                 curdir = getcwd()
506                 if self.device is not None:
507                         self.uuid = harddiskmanager.getPartitionUUID(self.device)
508                         try:
509                                 chdir("/autofs/" + self.device)
510                                 self.isMountable = True
511                         except OSError:
512                                 pass
513                         if self.isMountable:
514                                 try:
515                                         listdir("/autofs/" + self.device)
516                                         self.isReadable = True
517                                 except OSError:
518                                         pass
519                         if self.isReadable:
520                                 mountpoint, self.fsType, mountopt = harddiskmanager.getMountInfo("/dev/" + self.device)
521                                 if mountopt is not None and mountopt == 'rw':
522                                         self.isWriteable = True
523                                         if not access("/autofs/" + self.device, W_OK):
524                                                 self.isWriteable = False
525                         if self.uuid is not None:
526                                 if self.fsType is None:
527                                         fstype = harddiskmanager.getBlkidPartitionType("/dev/" + self.device)
528                                         if fstype is not None:
529                                                 self.fsType = fstype
530                         if self.isWriteable:
531                                 if access("/autofs/" + self.device + "/movie", W_OK):
532                                         self.isInitialized = True
533                 else:
534                         self.uuid = None
535                         self.isMountable = False
536                         self.isReadable = False
537                         self.isWriteable = False
538                         self.isInitialized = False
539                         self.fsType = None
540                 chdir(curdir)
541
542         def stat(self):
543                 return statvfs(self.mountpoint)
544
545         def free(self):
546                 try:
547                         s = self.stat()
548                         return s.f_bavail * s.f_bsize
549                 except OSError:
550                         return None
551
552         def total(self):
553                 try:
554                         s = self.stat()
555                         return s.f_blocks * s.f_bsize
556                 except OSError:
557                         return None
558
559         def mounted(self):
560                 # THANK YOU PYTHON FOR STRIPPING AWAY f_fsid.
561                 # TODO: can os.path.ismount be used?
562                 if self.force_mounted:
563                         return True
564                 try:
565                         mounts = open("/proc/mounts")
566                 except IOError:
567                         return False
568
569                 lines = mounts.readlines()
570                 mounts.close()
571
572                 for line in lines:
573                         if line.split(' ')[1] == self.mountpoint:
574                                 return True
575                 return False
576                         
577                 
578 DEVICEDB_SR = \
579         {"dm8000":
580                 {
581                         "/devices/pci0000:01/0000:01:00.0/host0/target0:0:0/0:0:0:0": _("DVD Drive"),
582                         "/devices/pci0000:01/0000:01:00.0/host1/target1:0:0/1:0:0:0": _("DVD Drive"),
583                         "/devices/platform/brcm-ehci-1.1/usb2/2-1/2-1:1.0/host3/target3:0:0/3:0:0:0": _("DVD Drive"),
584                 },
585         "dm800":
586         {
587         },
588         "dm7025":
589         {
590         }
591         }
592
593 DEVICEDB = \
594         {"dm8000":
595                 {
596                         "/devices/pci0000:01/0000:01:00.0/host1/target1:0:0/1:0:0:0": _("SATA"),
597                         "/devices/platform/brcm-ehci.0/usb1/1-1/1-1.1/1-1.1:1.0": _("Front USB"),
598                         "/devices/platform/brcm-ehci.0/usb1/1-1/1-1.1/1-1.1.": _("Front USB"),
599                         "/devices/platform/brcm-ehci.0/usb1/1-1/1-1.2/1-1.2:1.0": _("Back, upper USB"),
600                         "/devices/platform/brcm-ehci.0/usb1/1-1/1-1.2/1-1.2.": _("Back, upper USB"),
601                         "/devices/platform/brcm-ehci.0/usb1/1-1/1-1.3/1-1.3:1.0": _("Back, lower USB"),
602                         "/devices/platform/brcm-ehci.0/usb1/1-1/1-1.3/1-1.3.": _("Back, lower USB"),
603                         "/devices/platform/brcm-ehci-1.1/usb2/2-1/2-1:1.0/": _("Internal USB"),
604                         "/devices/platform/brcm-ohci-1.1/usb4/4-1/4-1:1.0/": _("Internal USB"),
605                         "/devices/platform/brcm-ehci.0/usb1/1-1/1-1.4/1-1.4.": _("Internal USB"),
606                 },
607         "dm7020hd":
608         {
609                 "/devices/pci0000:01/0000:01:00.0/host0/target0:0:0/0:0:0:0": _("SATA"),
610                 "/devices/pci0000:01/0000:01:00.0/host1/target1:0:0/1:0:0:0": _("eSATA"),
611                 "/devices/platform/brcm-ehci-1.1/usb2/2-1/2-1:1.0": _("Front USB"),
612                 "/devices/platform/brcm-ehci-1.1/usb2/2-1/2-1.": _("Front USB"),
613                 "/devices/platform/brcm-ehci.0/usb1/1-2/1-2:1.0": _("Back, upper USB"),
614                 "/devices/platform/brcm-ehci.0/usb1/1-2/1-2.": _("Back, upper USB"),
615                 "/devices/platform/brcm-ehci.0/usb1/1-1/1-1:1.0": _("Back, lower USB"),
616                 "/devices/platform/brcm-ehci.0/usb1/1-1/1-1.": _("Back, lower USB"),
617         },
618         "dm800":
619         {
620                 "/devices/pci0000:01/0000:01:00.0/host0/target0:0:0/0:0:0:0": _("SATA"),
621                 "/devices/platform/brcm-ehci.0/usb1/1-2/1-2:1.0": _("Upper USB"),
622                 "/devices/platform/brcm-ehci.0/usb1/1-1/1-1:1.0": _("Lower USB"),
623         },
624         "dm800se":
625         {
626                 "/devices/pci0000:01/0000:01:00.0/host0/target0:0:0/0:0:0:0": _("SATA"),
627                 "/devices/pci0000:01/0000:01:00.0/host1/target1:0:0/1:0:0:0": _("eSATA"),
628                 "/devices/platform/brcm-ehci.0/usb1/1-2/1-2:1.0": _("Upper USB"),
629                 "/devices/platform/brcm-ehci.0/usb1/1-1/1-1:1.0": _("Lower USB"),
630         },
631         "dm500hd":
632         {
633                 "/devices/pci0000:01/0000:01:00.0/host1/target1:0:0/1:0:0:0": _("eSATA"),
634                 "/devices/pci0000:01/0000:01:00.0/host0/target0:0:0/0:0:0:0": _("eSATA"),
635         },
636         "dm7025":
637         {
638                 "/devices/pci0000:00/0000:00:14.1/ide1/1.0": "Compact Flash", #hdc
639                 "/devices/pci0000:00/0000:00:14.1/ide0/0.0": "Internal Harddisk"
640         }
641         }
642
643 class HarddiskManager:
644         def __init__(self):
645                 config.storage_options = ConfigSubsection()
646                 config.storage_options.default_device = ConfigText(default = "<undefined>")
647                 config.storage = ConfigSubDict()
648                 self.hdd = [ ]
649                 self.cd = ""
650                 self.partitions = [ ]
651                 self.devices_scanned_on_init = [ ]
652                 self.delayed_device_Notifier = [ ]
653
654                 self.on_partition_list_change = CList()
655                 
656                 # currently, this is just an enumeration of what's possible,
657                 # this probably has to be changed to support automount stuff.
658                 # still, if stuff is mounted into the correct mountpoints by
659                 # external tools, everything is fine (until somebody inserts
660                 # a second usb stick.)
661                 p = [
662                                         ("/media/hdd", _("Hard disk")),
663                                         ("/media/card", _("Card")),
664                                         ("/media/cf", _("Compact Flash")),
665                                         ("/media/mmc1", _("SD/MMC")),
666                                         ("/media/net", _("Network Mount")),
667                                         ("/media/ram", _("Ram Disk")),
668                                         ("/media/usb", _("USB Stick")),
669                                         ("/", _("Internal Flash"))
670                                 ]
671                 self.partitions.extend([ Partition(mountpoint = x[0], description = x[1]) for x in p ])
672
673         def getBlockDevInfo(self, blockdev):
674                 devpath = "/sys/block/" + blockdev
675                 error = False
676                 removable = False
677                 blacklisted = False
678                 is_cdrom = False
679                 partitions = []
680                 try:
681                         removable = bool(int(readFile(devpath + "/removable")))
682                         dev = int(readFile(devpath + "/dev").split(':')[0])
683                         if dev in (7, 31): # loop, mtdblock
684                                 blacklisted = True
685                         if blockdev[0:2] == 'sr':
686                                 is_cdrom = True
687                         if blockdev[0:2] == 'hd':
688                                 try:
689                                         media = readFile("/proc/ide/%s/media" % blockdev)
690                                         if "cdrom" in media:
691                                                 is_cdrom = True
692                                 except IOError:
693                                         error = True
694                         # check for partitions
695                         if not is_cdrom:
696                                 for partition in listdir(devpath):
697                                         if partition[0:len(blockdev)] != blockdev:
698                                                 continue
699                                         partitions.append(partition)
700                         else:
701                                 self.cd = blockdev
702                 except IOError:
703                         error = True
704                 # check for medium
705                 medium_found = True
706                 try:
707                         open("/dev/" + blockdev).close()
708                 except IOError, err:
709                         if err.errno == 159: # no medium present
710                                 medium_found = False
711                 return error, blacklisted, removable, is_cdrom, partitions, medium_found
712
713         def enumerateBlockDevices(self):
714                 self.setupConfigEntries(initial_call = True)
715                 print "enumerating block devices..."
716                 for blockdev in listdir("/sys/block"):
717                         error, blacklisted, removable, is_cdrom, partitions, medium_found = self.addHotplugPartition(blockdev)
718                         if not error and not blacklisted:
719                                 if medium_found:
720                                         for part in partitions:
721                                                 self.addHotplugPartition(part)
722                                 self.devices_scanned_on_init.append((blockdev, removable, is_cdrom, medium_found))
723                                 print "[enumerateBlockDevices] devices_scanned_on_init:",self.devices_scanned_on_init
724
725         def getAutofsMountpoint(self, device):
726                 return "/autofs/%s/" % (device)
727
728         def is_hard_mounted(self, device):
729                 mounts = file('/proc/mounts').read().split('\n')
730                 for x in mounts:
731                         if x.find('/autofs') == -1 and x.find(device) != -1:
732                                 #print "is_hard_mounted:",device
733                                 return True
734                 return False
735
736         def get_mountdevice(self, mountpoint):
737                 mounts = file('/proc/mounts').read().split('\n')
738                 for x in mounts:
739                         if not x.startswith('/'):
740                                 continue
741                         device, mp = x.split()[0:2]
742                         if mp == mountpoint:
743                                 #print "get_mountdevice for '%s' -> %s " % (device, mp)
744                                 return device
745                 return None
746
747         def get_mountpoint(self, mountpath):
748                 mounts = file('/proc/mounts').read().split('\n')
749                 for x in mounts:
750                         if not x.startswith('/'):
751                                 continue
752                         path, mp = x.split()[0:2]
753                         if path == mountpath:
754                                 #print "get_mountpoint for '%s' -> %s " % (path, mp)
755                                 return mp
756                 return None
757
758         def is_uuidpath_mounted(self, uuidpath, mountpoint):
759                 mounts = file('/proc/mounts').read().split('\n')
760                 for x in mounts:
761                         if not x.startswith('/'):
762                                 continue
763                         path, mp = x.split()[0:2]
764                         if (path == uuidpath and mp == mountpoint):
765                                 #print "is_uuid_mounted:'%s' for: %s " % (path, mp)
766                                 return True
767                 return False
768
769         def is_fstab_mountpoint(self, device, mountpoint):
770                 mounts = file('/etc/fstab').read().split('\n')
771                 for x in mounts:
772                         if not x.startswith('/'):
773                                 continue
774                         dev, mp = x.split()[0:2]
775                         if (dev == device and mp == mountpoint):
776                                 #print "is_fstab_mountpoint:'%s' for: %s " % (mp, dev)
777                                 return True
778                 return False
779
780         def get_fstab_mountstate(self, device, mountpoint):
781                 mounts = file('/etc/fstab').read().split('\n')
782                 for x in mounts:
783                         if not x.startswith('/'):
784                                 continue
785                         dev, mp, ms = x.split()[0:3]
786                         if (dev == device and mp == mountpoint):
787                                 #print "got_fstab_mountstate:'%s' for: %s - %s" % (ms, dev, mp)
788                                 return ms
789                 return False
790
791         def get_fstab_mountpoint(self, device):
792                 mounts = file('/etc/fstab').read().split('\n')
793                 for x in mounts:
794                         if not x.startswith('/'):
795                                 continue
796                         dev, mp = x.split()[0:2]
797                         if device == dev:
798                                 #print "got_fstab_mountpoint:'%s' for: %s" % (mp, dev)
799                                 return mp
800                 return None
801
802         def modifyFstabEntry(self, partitionPath, mountpoint, mode = "add_deactivated"):
803                 try:
804                         alreadyAdded = self.is_fstab_mountpoint(partitionPath, mountpoint)
805                         oldLine = None
806                         mounts = file('/etc/fstab').read().split('\n')
807                         fp = file("/etc/fstab", 'w')
808                         fp.write("#automatically edited by enigma2, " + str(time.strftime( "%a" + ", " + "%d " + "%b" + " %Y %H:%M:%S", time.localtime(time.time() ))) + "\n")
809                         for x in mounts:
810                                 if (x.startswith(partitionPath) and mountpoint in x):
811                                         oldLine = x
812                                         continue
813                                 if len(x):
814                                         if x.startswith('#automatically'):
815                                                 continue
816                                         fp.write(x + "\n")
817                         if not alreadyAdded:
818                                 if mode == "add_deactivated":
819                                         print "modifyFstabEntry - add_deactivated:", partitionPath, mountpoint
820                                         fp.write(partitionPath + "\t" + mountpoint + "\tnoauto\tdefaults\t0 0\n")
821                         else:
822                                 if mode == "add_deactivated":
823                                         if oldLine is not None:
824                                                 if "noauto" in oldLine:
825                                                         fp.write(oldLine + "\n")
826                                                 else:
827                                                         fp.write(oldLine.replace("auto","noauto") + "\n")
828                         fp.close()
829                 except:
830                         print "error adding fstab entry for: %s" % (partitionPath)
831
832         def addHotplugPartition(self, device, physdev = None):
833                 if not physdev:
834                         dev, part = self.splitDeviceName(device)
835                         try:
836                                 physdev = path.realpath('/sys/block/' + dev + '/device')[4:]
837                         except OSError:
838                                 physdev = dev
839                                 print "couldn't determine blockdev physdev for device", device
840
841                 error, blacklisted, removable, is_cdrom, partitions, medium_found = self.getBlockDevInfo(device)
842                 print "found block device '%s':" % device,
843
844                 if blacklisted:
845                         print "blacklisted"
846                 else:
847                         if error:
848                                 print "error querying properties"
849                         elif not medium_found:
850                                 print "no medium"
851                         else:
852                                 print "ok, removable=%s, cdrom=%s, partitions=%s" % (removable, is_cdrom, partitions)
853
854                         l = len(device)
855                         if l:
856                                 # see if this is a harddrive or removable drive (usb stick/cf/sd)
857                                 if not device[l-1].isdigit() and not is_cdrom:
858                                         if self.getHDD(device) is None and medium_found:
859                                                 if removable:
860                                                         self.hdd.append(Harddisk(device, True))
861                                                 else:
862                                                         self.hdd.append(Harddisk(device, False))
863                                         self.hdd.sort()
864                                         SystemInfo["Harddisk"] = len(self.hdd) > 0
865                                 if (not removable or medium_found):
866                                         self.addDevicePartition(device, physdev)
867
868                 return error, blacklisted, removable, is_cdrom, partitions, medium_found
869
870         def removeHotplugPartition(self, device):
871                 mountpoint = self.getAutofsMountpoint(device)
872                 uuid = self.getPartitionUUID(device)
873                 print "[removeHotplugPartition] for device:'%s' uuid:'%s' and mountpoint:'%s'" % (device, uuid, mountpoint)
874                 p = self.getPartitionbyDevice(device)
875                 if p is None:
876                         p = self.getPartitionbyMountpoint(mountpoint)
877                 if p is not None:
878                         if uuid is None and p.uuid is not None:
879                                 print "[removeHotplugPartition] WE GOT uuid:'%s' but have:'%s'" % (uuid,p.uuid)
880                                 uuid = p.uuid
881                                 harddiskmanager.unmountPartitionbyMountpoint(p.mountpoint)
882                         if uuid is not None and config.storage.get(uuid, None) is not None:
883                                 self.unmountPartitionbyUUID(uuid)
884                                 if not config.storage[uuid]['enabled'].value:
885                                         del config.storage[uuid]
886                                         print "[removeHotplugPartition] - remove uuid %s from temporary drive add" % (uuid)
887                         if p.mountpoint != "/media/hdd":
888                                 self.partitions.remove(p)
889                                 self.on_partition_list_change("remove", p)
890
891                 l = len(device)
892                 if l and not device[l-1].isdigit():
893                         for hdd in self.hdd:
894                                 if hdd.device == device:
895                                         hdd.stop()
896                                         self.hdd.remove(hdd)
897                                         break
898                         SystemInfo["Harddisk"] = len(self.hdd) > 0
899
900                         #call the notifier only after we have fully removed the disconnected drive
901                         for callback in self.delayed_device_Notifier:
902                                 try:
903                                         callback(device, "remove_delayed" )
904                                 except AttributeError:
905                                         self.delayed_device_Notifier.remove(callback)
906
907         def addDevicePartition(self, device, physdev):
908                 # device is the device name, without /dev
909                 # physdev is the physical device path, which we (might) use to determine the userfriendly name
910                 description = self.getUserfriendlyDeviceName(device, physdev)
911                 device_mountpoint = self.getAutofsMountpoint(device)
912                 uuid = self.getPartitionUUID(device)
913                 print "[addDevicePartition] device:'%s' with UUID:'%s'" % (device, uuid)
914                 if config.storage.get(uuid, None) is not None:
915                         if config.storage[uuid]['enabled'].value and config.storage[uuid]['mountpoint'].value != "":
916                                 device_mountpoint = config.storage[uuid]['mountpoint'].value
917
918                 if uuid is not None:
919                         if config.storage.get(uuid, None) is None:
920                                 tmp = self.getPartitionbyDevice(device)
921                                 if tmp is not None:
922                                         if uuid != tmp.uuid and tmp.uuid == config.storage_options.default_device.value and tmp.mountpoint == "/media/hdd": #default hdd re/initialize
923                                                 tmp.device = None
924                                                 tmp.updatePartitionInfo()
925                                 self.setupConfigEntries(initial_call = False, dev = device)
926                         else:
927                                 tmp = self.getPartitionbyMountpoint(device_mountpoint)
928                                 if tmp is not None and (tmp.uuid != uuid or tmp.mountpoint != device_mountpoint):
929                                         self.storageDeviceChanged(uuid)
930
931                 p = self.getPartitionbyMountpoint(device_mountpoint)
932                 if p is not None:
933                         if uuid is not None:
934                                 if p.uuid is not None and p.uuid != uuid:
935                                         if config.storage.get(p.uuid, None) is not None:
936                                                 del config.storage[p.uuid] #delete old uuid reference entries
937                         p.updatePartitionInfo()
938                 else:
939                         forced = True
940                         if uuid is not None:
941                                 cfg_uuid = config.storage.get(uuid, None)
942                                 if cfg_uuid is not None:
943                                         if cfg_uuid['enabled'].value:
944                                                 forced = False
945                                         else:
946                                                 device_mountpoint = self.getAutofsMountpoint(device)
947                         x = self.getPartitionbyDevice(device)
948                         if x is None:
949                                 p = Partition(mountpoint = device_mountpoint, description = description, force_mounted = forced, device = device)
950                                 self.partitions.append(p)
951                                 self.on_partition_list_change("add", p)
952                         else:   # found old partition entry
953                                 if config.storage.get(x.uuid, None) is not None:
954                                         del config.storage[x.uuid] #delete old uuid reference entries
955                                 x.mountpoint = device_mountpoint
956                                 x.force_mounted = True
957                                 x.updatePartitionInfo()
958
959                 for callback in self.delayed_device_Notifier:
960                         try:
961                                 callback(device, "add_delayed" )
962                         except AttributeError:
963                                 self.delayed_device_Notifier.remove(callback)
964
965         def HDDCount(self):
966                 return len(self.hdd)
967
968         def HDDList(self):
969                 list = [ ]
970                 for hd in self.hdd:
971                         hdd = hd.model() + " - " + hd.bus()
972                         cap = hd.capacity()
973                         if cap != "":
974                                 hdd += " (" + cap + ")"
975                         list.append((hdd, hd))
976                 return list
977
978         def HDDEnabledCount(self):
979                 cnt = 0
980                 for uuid, cfg in config.storage.items():
981                         #print "uuid", uuid, "cfg", cfg
982                         if cfg["enabled"].value:
983                                 cnt += 1
984                 return cnt
985
986         def getHDD(self, part):
987                 for hdd in self.hdd:
988                         if hdd.device == part[:3]:
989                                 return hdd
990                 return None
991
992         def getCD(self):
993                 return self.cd
994
995         def getMountInfo(self, device):
996                 dev = mountpoint = fstype = mountopt = None
997                 try:
998                         mounts = file('/proc/mounts').read().split('\n')
999                         for x in mounts:
1000                                 if not x.startswith('/'):
1001                                         continue
1002                                 if x.startswith(device):
1003                                         data = x.split(',')
1004                                         dev, mountpoint, fstype, mountopt = data[0].split(None,4)
1005                 except:
1006                         print "error getting mount info"
1007                 #print "getMountInfo:",mountpoint, fstype, mountopt 
1008                 return mountpoint, fstype, mountopt
1009
1010         def getFdiskInfo(self, devname):
1011                 size = sizeg = fstype = sys = None
1012                 cmd = "fdisk -l /dev/" + devname
1013                 try:
1014                         for line in popen(cmd).read().split('\n'):
1015                                 if line.startswith("Disk"):
1016                                         sizeobj = re.search(r', ((?:[a-zA-Z0-9])*) bytes', line)
1017                                         if sizeobj:
1018                                                 size = sizeobj.group(1)
1019                                         sizegobj = re.search(r': ((?:[0-9.0-9])*) GB', line)
1020                                         if sizegobj:
1021                                                 sizeg = sizegobj.group(1)
1022                                 if not line.startswith('/'):
1023                                         continue
1024                                 if line.startswith("/dev/" + devname):
1025                                         a,b,c,d, fstype, sys = line.split(None,5)
1026                 except:
1027                         print "error getting fdisk device info"
1028                 #print "getFdiskInfo:",devname, fstype, sys, size, sizeg
1029                 return fstype, sys, size, sizeg
1030
1031         def getBlkidPartitionType(self, device):
1032                 #print "getBlkidPartitionType",device
1033                 fstype = None
1034                 if path.exists("/usr/sbin/blkid"):
1035                         cmd = "/usr/sbin/blkid " + str(device)
1036                         try:
1037                                 for line in popen(cmd).read().split('\n'):
1038                                         if not line.startswith(device):
1039                                                 continue
1040                                         print "getBlkidPartitionType",line
1041                                         fstobj = re.search(r' TYPE="((?:[^"\\]|\\.)*)"', line)
1042                                         if fstobj:
1043                                                 fstype = fstobj.group(1)
1044                         except:
1045                                 print "error getting blkid partition type"
1046                 
1047                 #print "getBlkidPartitionType:",device, fstype
1048                 return fstype
1049
1050         def getLinkPath(self,link):
1051                 if path.islink(link):
1052                         p = path.normpath(readlink(link))
1053                         if path.isabs(p):
1054                                 return p
1055                         return path.join(path.dirname(link), p)
1056
1057         def getRealPath(self, dstpath):
1058                 p = self.getLinkPath(dstpath)
1059                 if p:
1060                         return p
1061                 return path.realpath(dstpath)
1062
1063         def isMount(self, mountdir):
1064                 return path.ismount( self.getRealPath(mountdir) )
1065
1066         def _inside_mountpoint(self, filename):
1067                 #print "is mount? '%s'" % filename
1068                 if filename == "":
1069                         return False
1070                 if filename == "/":
1071                         return False
1072                 if path.ismount(filename):
1073                         return True
1074                 return self._inside_mountpoint("/".join(filename.split("/")[:-1]))
1075         
1076         def inside_mountpoint(self,filename):
1077                 return self._inside_mountpoint(path.realpath(filename))
1078         
1079         def isUUIDpathFsTabMount(self, uuid, mountpath):
1080                 uuidpartitionPath = "/dev/disk/by-uuid/" + uuid
1081                 if self.is_hard_mounted(uuidpartitionPath) and self.is_fstab_mountpoint(uuidpartitionPath, mountpath):
1082                         if self.get_fstab_mountstate(uuidpartitionPath, mountpath) == 'auto':
1083                                 return True
1084                 return False
1085
1086         def isPartitionpathFsTabMount(self, uuid, mountpath):
1087                 dev = self.getDeviceNamebyUUID(uuid)
1088                 if dev is not None:
1089                         partitionPath = "/dev/" + str(dev)
1090                         if self.is_hard_mounted(partitionPath) and self.is_fstab_mountpoint(partitionPath, mountpath):
1091                                 if self.get_fstab_mountstate(partitionPath, mountpath) == 'auto':
1092                                         return True                     
1093                 return False
1094
1095         def getPartitionVars(self, hd, partitionNum = False):
1096                 #print "getPartitionVars for hdd:'%s' and partitionNum:'%s'" % (hd.device, partitionNum)
1097                 hdd = hd
1098                 numPartitions = hdd.numPartitions()
1099                 uuid = partitionType = partitionPath = uuidPath = deviceName = None
1100                 if partitionNum is False:
1101                         if numPartitions == 0:
1102                                 deviceName = hdd.device
1103                                 uuid = self.getPartitionUUID(deviceName)
1104                                 partitionPath = hdd.dev_path
1105                         if numPartitions == 1: 
1106                                 deviceName = hdd.device + str(numPartitions)
1107                                 uuid = self.getPartitionUUID(deviceName)
1108                                 partitionPath = hdd.partitionPath(str(numPartitions))
1109                         else: #just in case, we should never get here
1110                                 deviceName = hdd.device
1111                                 partitionPath = hdd.dev_path
1112                 else:
1113                         deviceName = hdd.device + str(partitionNum)
1114                         uuid = self.getPartitionUUID(deviceName)
1115                         partitionPath = hdd.partitionPath(str(partitionNum))
1116                 if uuid is not None:            
1117                         uuidPath = "/dev/disk/by-uuid/" + uuid
1118                 return deviceName, uuid, numPartitions, partitionNum, uuidPath, partitionPath
1119
1120         def suggestDeviceMountpath(self,uuid):
1121                 p = self.getPartitionbyUUID(uuid)
1122                 if p is not None:
1123                         hdd = self.getHDD(p.device)
1124                         if hdd is not None:
1125                                 val = str(hdd.model(model_only = True)).strip().replace(' ','').replace('-','').replace('_','')
1126                                 cnt = 0
1127                                 for dev in self.hdd:
1128                                         tmpval = str(dev.model(model_only = True)).strip().replace(' ','').replace('-','').replace('_','')
1129                                         if tmpval == val:
1130                                                 cnt +=1
1131                                 if cnt <=1:
1132                                         cnt = 0
1133                                         for uid in config.storage.keys():
1134                                                 if uid == uuid:
1135                                                         cnt += 1
1136                                                         continue
1137                                                 data = config.storage[uid]["device_description"].value.split(None,1)
1138                                                 tmpval = data[0].strip().replace(' ','').replace('-','').replace('_','')
1139                                                 if tmpval == val or tmpval.endswith(val):
1140                                                         cnt += 1
1141                                 if cnt >= 2:
1142                                         val += "HDD" + str(cnt)
1143                                 if hdd.numPartitions() >= 2:
1144                                         partNum = p.device[3:]
1145                                         if int(partNum).isdigit():
1146                                                 val += "Part" + str(partNum)
1147                                 print "suggestDeviceMountpath for uuid: '%s' -> '%s'" %(uuid,val)
1148                                 return "/media/" + val
1149                 else:
1150                         mountpath = ""
1151                         uuid_cfg = config.storage.get(uuid, None)
1152                         if uuid_cfg is not None:
1153                                 if uuid_cfg["mountpoint"].value != "" and uuid_cfg["mountpoint"].value != "/media/hdd":
1154                                         mountpath = uuid_cfg["mountpoint"].value
1155                                 else:
1156                                         if uuid_cfg["device_description"].value != "":
1157                                                 tmp = uuid_cfg["device_description"].value.split(None,1)
1158                                                 mountpath = "/media/" + tmp[0].strip().replace(' ','').replace('-','').replace('_','')
1159                         if mountpath != "":
1160                                 cnt = 0
1161                                 for uid in config.storage.keys():
1162                                         if config.storage[uid]["mountpoint"].value != "" and config.storage[uid]["mountpoint"].value != "/media/hdd":
1163                                                 tmp = config.storage[uid]["mountpoint"].value
1164                                         else:
1165                                                 data = config.storage[uid]["device_description"].value.split(None,1)
1166                                                 tmp = "/media/" + data[0].strip().replace(' ','').replace('-','').replace('_','')
1167                                         if tmp == mountpath:
1168                                                 cnt += 1
1169                                 if cnt >= 2:
1170                                         mountpath += "HDD" + str(cnt)
1171                                 return mountpath
1172                 return ""
1173
1174         def changeStorageDevice(self, uuid = None, action = None , mountData = None ):
1175                 # mountData should be [oldenable,oldmountpath, newenable,newmountpath]
1176                 print "[changeStorageDevice] uuid:'%s' - action:'%s' - mountData:'%s'" %(uuid, action, mountData)
1177                 currentDefaultStorageUUID = config.storage_options.default_device.value
1178                 print "[changeStorageDevice]: currentDefaultStorageUUID:",currentDefaultStorageUUID
1179                 successfully = False
1180                 def_mp = "/media/hdd"
1181                 cur_default_newmp = new_default_newmp = old_cur_default_mp = old_new_default_mp = ""
1182                 cur_default = new_default = None
1183                 cur_default_dev = new_default_dev = None
1184                 cur_default_cfg = new_default_cfg = None
1185                 old_cur_default_enabled = old_new_default_enabled = False
1186
1187                 if action == "mount_default":
1188                         if currentDefaultStorageUUID != "<undefined>" and currentDefaultStorageUUID != uuid:
1189                                 cur_default = self.getDefaultStorageDevicebyUUID(currentDefaultStorageUUID)
1190                         new_default = self.getPartitionbyUUID(uuid)
1191                         if cur_default is not None:
1192                                 cur_default_cfg = config.storage.get(currentDefaultStorageUUID, None)
1193                         new_default_cfg = config.storage.get(uuid, None)
1194                         if new_default is not None:
1195                                 new_default_dev = new_default.device
1196                                 if currentDefaultStorageUUID != "<undefined>" and currentDefaultStorageUUID != uuid:
1197                                         cur_default_newmp = self.suggestDeviceMountpath(currentDefaultStorageUUID)
1198                                 if cur_default is not None:
1199                                         cur_default_dev = cur_default.device
1200                                 if new_default_cfg is not None:
1201                                         old_new_default_enabled = new_default_cfg["enabled"].value
1202                                         old_new_default_mp = new_default_cfg["mountpoint"].value
1203                                         #[oldmountpath, oldenable, newmountpath, newenable]
1204                                         if mountData is not None and isinstance(mountData, (list, tuple)):
1205                                                 old_new_default_enabled = mountData[1]
1206                                                 old_new_default_mp = mountData[0]
1207                                         if cur_default_cfg is not None and path.exists(def_mp) and self.isMount(def_mp) and cur_default_cfg["enabled"].value and cur_default_cfg["mountpoint"].value == def_mp:                                 
1208                                                 old_cur_default_enabled = cur_default_cfg["enabled"].value
1209                                                 old_cur_default_mp = cur_default_cfg["mountpoint"].value
1210                                                 self.unmountPartitionbyMountpoint(def_mp)
1211                                         if not path.exists(def_mp) or (path.exists(def_mp) and not self.isMount(def_mp)):
1212                                                 if cur_default_cfg is not None:
1213                                                         cur_default_cfg["mountpoint"].value = cur_default_newmp
1214                                                 if cur_default_dev is not None:
1215                                                         self.setupConfigEntries(initial_call = False, dev = cur_default_dev)
1216                                                 if cur_default_dev is None or (path.exists(cur_default_newmp) and self.isMount(cur_default_newmp)):
1217                                                         if new_default_cfg["enabled"].value and path.exists(new_default_cfg["mountpoint"].value) and self.isMount(new_default_cfg["mountpoint"].value):
1218                                                                 self.unmountPartitionbyMountpoint(new_default_cfg["mountpoint"].value, new_default_dev )
1219                                                         if not new_default_cfg["enabled"].value or (path.exists(new_default_cfg["mountpoint"].value) and not self.isMount(new_default_cfg["mountpoint"].value)):
1220                                                                 new_default_cfg["mountpoint"].value = def_mp
1221                                                                 new_default_cfg["enabled"].value = True
1222                                                                 self.storageDeviceChanged(uuid)
1223                                                                 new_default = self.getPartitionbyMountpoint(def_mp)
1224                                                                 if cur_default_cfg is None and cur_default_newmp is not "": #currentdefault was offline
1225                                                                         cur_default_cfg = config.storage.get(currentDefaultStorageUUID, None)
1226                                                                 if cur_default_cfg is not None:
1227                                                                         old_cur_default_enabled = cur_default_cfg["enabled"].value
1228                                                                         old_cur_default_mp = cur_default_cfg["mountpoint"].value
1229                                                                         cur_default_cfg["mountpoint"].value = cur_default_newmp
1230                                                                 if new_default is not None and new_default_cfg["mountpoint"].value == def_mp and path.exists(def_mp) and self.isMount(def_mp) and new_default.mountpoint == def_mp:
1231                                                                         successfully = True
1232                                                                         config.storage_options.default_device.value = uuid
1233                                                                         if new_default_cfg is not None:
1234                                                                                 new_default_cfg.save()
1235                                                                         if cur_default_cfg is not None:
1236                                                                                 cur_default_cfg.save()
1237                 if action == "mount_only":
1238                         new_default = self.getPartitionbyUUID(uuid)
1239                         new_default_cfg = config.storage.get(uuid, None)
1240                         if new_default is not None:
1241                                 new_default_dev = new_default.device
1242                                 new_default_newmp = self.suggestDeviceMountpath(uuid)
1243                                 if new_default_cfg is not None:
1244                                         old_new_default_enabled = new_default_cfg["enabled"].value
1245                                         old_new_default_mp = new_default_cfg["mountpoint"].value
1246                                         #[oldmountpath, oldenable, newmountpath, newenable]
1247                                         if mountData is not None and isinstance(mountData, (list, tuple)):
1248                                                 old_new_default_enabled = mountData[1]
1249                                                 old_new_default_mp = mountData[0]
1250                                                 new_default_newmp = mountData[2]
1251                                         if old_new_default_enabled and path.exists(def_mp) and self.isMount(def_mp) and old_new_default_mp == def_mp:                                   
1252                                                 if uuid == currentDefaultStorageUUID:
1253                                                         self.unmountPartitionbyMountpoint(def_mp) #current partition is default, unmount!
1254                                         if old_new_default_enabled and old_new_default_mp != "" and old_new_default_mp != def_mp and path.exists(old_new_default_mp) and self.isMount(old_new_default_mp):                                      
1255                                                 self.unmountPartitionbyMountpoint(old_new_default_mp, new_default_dev) #current partition is already mounted atm. unmount!
1256                                         if not new_default_cfg["enabled"].value or old_new_default_mp == "" or (new_default_cfg["enabled"].value and path.exists(old_new_default_mp) and not self.isMount(old_new_default_mp)):
1257                                                 new_default_cfg["enabled"].value = True
1258                                                 new_default_cfg["mountpoint"].value = new_default_newmp
1259                                                 if path.exists(new_default_newmp) and self.isMount(new_default_newmp):
1260                                                         tmppath = self.get_mountdevice(new_default_newmp)
1261                                                         if tmppath is not None and tmppath == "/dev/disk/by-uuid/" + uuid:
1262                                                                 self.unmountPartitionbyMountpoint(new_default_newmp)
1263                                                 else:
1264                                                         x = None
1265                                                         if new_default_dev is not None:
1266                                                                 x = self.getPartitionbyDevice(new_default_dev)
1267                                                         if x is None:
1268                                                                 self.setupConfigEntries(initial_call = False, dev = new_default_dev)
1269                                                         else:
1270                                                                 self.storageDeviceChanged(uuid)
1271                                                 new_default = self.getPartitionbyUUID(uuid)
1272                                                 if new_default is not None and path.exists(new_default_newmp) and self.isMount(new_default_newmp):
1273                                                         successfully = True
1274                                                         if uuid == currentDefaultStorageUUID:
1275                                                                 config.storage_options.default_device.value = "<undefined>"
1276                                                         new_default_cfg.save()
1277                 if action == "unmount":
1278                         new_default = self.getPartitionbyUUID(uuid)
1279                         new_default_cfg = config.storage.get(uuid, None)
1280                         if new_default is not None:
1281                                 new_default_dev = new_default.device
1282                                 if new_default_cfg is not None and new_default_cfg["mountpoint"].value == new_default.mountpoint:
1283                                         old_new_default_mp = new_default_cfg["mountpoint"].value
1284                                         old_new_default_enabled = new_default_cfg["enabled"].value
1285                                         #[oldmountpath, oldenable, newmountpath, newenable]
1286                                         if mountData is not None and isinstance(mountData, (list, tuple)):
1287                                                 old_new_default_enabled = mountData[1]
1288                                                 old_new_default_mp = mountData[0]
1289                                 if new_default_cfg is not None and path.exists(old_new_default_mp) and self.isMount(old_new_default_mp):
1290                                         if uuid == currentDefaultStorageUUID:
1291                                                 self.unmountPartitionbyMountpoint(old_new_default_mp)
1292                                         else:
1293                                                 self.unmountPartitionbyMountpoint(old_new_default_mp, new_default_dev)
1294                                 if path.exists(old_new_default_mp) and not self.isMount(old_new_default_mp):
1295                                         new_default_cfg["mountpoint"].value = ""
1296                                         new_default_cfg["enabled"].value = False
1297                                         self.setupConfigEntries(initial_call = False, dev = new_default_dev)
1298                                         if path.exists(old_new_default_mp) and not self.isMount(old_new_default_mp):
1299                                                 successfully = True
1300                                                 new_default_cfg.save()
1301                                                 if uuid == currentDefaultStorageUUID:
1302                                                         config.storage_options.default_device.value = "<undefined>"
1303                 if not successfully:
1304                         print "<< not successfully >>"
1305                         if cur_default_cfg is not None:
1306                                 cur_default_cfg["mountpoint"].value = old_cur_default_mp
1307                                 cur_default_cfg["enabled"].value = old_cur_default_enabled
1308                                 cur_default_cfg.save()
1309                                 if currentDefaultStorageUUID != "<undefined>":
1310                                         self.storageDeviceChanged(currentDefaultStorageUUID)
1311                         if new_default_cfg is not None:
1312                                 new_default_cfg["mountpoint"].value = old_new_default_mp
1313                                 new_default_cfg["enabled"].value = old_new_default_enabled
1314                                 new_default_cfg.save()
1315                                 self.storageDeviceChanged(uuid)
1316                 config.storage_options.default_device.save()
1317                 config.storage_options.save()
1318                 config.storage.save()
1319                 config.save()
1320                 configfile.save()
1321                 print "changeStorageDevice default is now:",config.storage_options.default_device.value
1322                 return successfully
1323
1324         def isConfiguredStorageDevice(self,uuid):
1325                 cfg_uuid = config.storage.get(uuid, None)
1326                 if cfg_uuid is not None and cfg_uuid["enabled"].value:
1327                         #print "isConfiguredStorageDevice:",uuid
1328                         return True
1329                 return False
1330
1331         def isDefaultStorageDeviceActivebyUUID(self, uuid):
1332                 p = self.getDefaultStorageDevicebyUUID(uuid)
1333                 if p is not None and p.uuid == uuid:
1334                         #print "isDefaultStorageDeviceActivebyUUID--for UUID:->",uuid,p.description, p.device, p.mountpoint, p.uuid
1335                         return True
1336                 return False
1337         
1338         def getDefaultStorageDevicebyUUID(self, uuid):
1339                 for p in self.getConfiguredStorageDevices():
1340                         if p.uuid == uuid:
1341                                 #print "getDefaultStorageDevicebyUUID--p:",uuid, p.description, p.device, p.mountpoint, p.uuid
1342                                 return p
1343                 return None
1344         
1345         def getConfiguredStorageDevices(self):
1346                 parts = [x for x in self.partitions if (x.uuid is not None and x.mounted() and self.isConfiguredStorageDevice(x.uuid))]
1347                 return [x for x in parts]
1348
1349         def getMountedPartitions(self, onlyhotplug = False):
1350                 parts = [x for x in self.partitions if (x.is_hotplug or not onlyhotplug) and x.mounted()]
1351                 devs = set([x.device for x in parts])
1352                 for devname in devs.copy():
1353                         if not devname:
1354                                 continue
1355                         dev, part = self.splitDeviceName(devname)
1356                         if part and dev in devs: # if this is a partition and we still have the wholedisk, remove wholedisk
1357                                 devs.remove(dev)
1358
1359                 # return all devices which are not removed due to being a wholedisk when a partition exists
1360                 return [x for x in parts if not x.device or x.device in devs]
1361
1362         def splitDeviceName(self, devname):
1363                 # this works for: sdaX, hdaX, sr0 (which is in fact dev="sr0", part=""). It doesn't work for other names like mtdblock3, but they are blacklisted anyway.
1364                 dev = devname[:3]
1365                 part = devname[3:]
1366                 for p in part:
1367                         if not p.isdigit():
1368                                 return devname, 0
1369                 return dev, part and int(part) or 0
1370
1371         def getUserfriendlyDeviceName(self, dev, phys):
1372                 #print "getUserfriendlyDeviceName",dev, phys
1373                 dev, part = self.splitDeviceName(dev)
1374                 description = "External Storage %s" % dev
1375                 have_model_descr = False
1376                 try:
1377                         description = readFile("/sys" + phys + "/model")
1378                         have_model_descr = True
1379                 except IOError, s:
1380                         print "couldn't read model: ", s
1381                 from Tools.HardwareInfo import HardwareInfo
1382                 if dev.find('sr') == 0 and dev[2].isdigit():
1383                         devicedb = DEVICEDB_SR
1384                 else:
1385                         devicedb = DEVICEDB
1386                 for physdevprefix, pdescription in devicedb.get(HardwareInfo().device_name,{}).items():
1387                         if phys.startswith(physdevprefix):
1388                                 if have_model_descr:
1389                                         description = pdescription + ' - ' + description
1390                                 else:
1391                                         description = pdescription
1392                 # not wholedisk and not partition 1
1393                 if part and part != 1:
1394                         description += " (Partition %d)" % part
1395                 return description
1396
1397         def addMountedPartition(self, device, desc):
1398                 already_mounted = False
1399                 for x in self.partitions[:]:
1400                         if x.mountpoint == device:
1401                                 already_mounted = True
1402                 if not already_mounted:
1403                         self.partitions.append(Partition(mountpoint = device, description = desc))
1404
1405         def removeMountedPartition(self, mountpoint):
1406                 for x in self.partitions[:]:
1407                         if x.mountpoint == mountpoint:
1408                                 self.partitions.remove(x)
1409                                 self.on_partition_list_change("remove", x)
1410
1411         def removeMountedPartitionbyDevice(self, device):
1412                 p = self.getPartitionbyDevice(device)
1413                 if p is not None:
1414                         #print "[removeMountedPartitionbyDevice] '%s', '%s', '%s', '%s', '%s'" % (p.mountpoint,p.description,p.device,p.force_mounted,p.uuid)
1415                         self.partitions.remove(p)
1416                         self.on_partition_list_change("remove", p)
1417
1418         def trigger_udev(self):
1419                 # We have to trigger udev to rescan sysfs 
1420                 cmd = "udevadm trigger"
1421                 res = system(cmd)
1422                 return (res >> 8)
1423
1424         def getPartitionbyUUID(self, uuid):
1425                 for x in self.partitions[:]:
1426                         if x.uuid == uuid:
1427                                 #print "[getPartitionbyUUID] '%s', '%s', '%s', '%s', '%s'" % (x.mountpoint,x.description,x.device,x.force_mounted,x.uuid)
1428                                 return x
1429                 return None
1430
1431         def getPartitionbyDevice(self, dev):
1432                 for x in self.partitions[:]:
1433                         if x.device == dev:
1434                                 #print "[getPartitionbyDevice] '%s', '%s', '%s', '%s', '%s'" % (x.mountpoint,x.description,x.device,x.force_mounted,x.uuid)
1435                                 return x
1436                 return None
1437
1438         def getPartitionbyMountpoint(self, mountpoint):
1439                 for x in self.partitions[:]:
1440                         if x.mountpoint == mountpoint:
1441                                 #print "[getPartitionbyMountpoint] '%s', '%s', '%s', '%s', '%s'" % (x.mountpoint,x.description,x.device,x.force_mounted,x.uuid)
1442                                 return x
1443                 return None
1444
1445         def getDeviceNamebyUUID(self, uuid):
1446                 if path.exists("/dev/disk/by-uuid/" + uuid):
1447                         return path.basename(path.realpath("/dev/disk/by-uuid/" + uuid))
1448                 return None
1449         
1450         def getPartitionUUID(self, part):
1451                 if not path.exists("/dev/disk/by-uuid"):
1452                         return None
1453                 for uuid in listdir("/dev/disk/by-uuid/"):
1454                         if not path.exists("/dev/disk/by-uuid/" + uuid):
1455                                 return None
1456                         if path.basename(path.realpath("/dev/disk/by-uuid/" + uuid)) == part:
1457                                 #print "[getPartitionUUID] '%s' - '%s'" % (uuid, path.basename(path.realpath("/dev/disk/by-uuid/" + uuid)) )
1458                                 return uuid
1459                 return None
1460
1461         def getDeviceDescription(self, dev):
1462                 physdev = path.realpath('/sys/block/' + dev[:3] + '/device')[4:]
1463                 description = self.getUserfriendlyDeviceName(dev[:3], physdev)
1464                 #print "[getDeviceDescription] -> device:'%s' - desc: '%s' phy:'%s'" % (dev, description, physdev)
1465                 return description
1466
1467         def reloadExports(self):
1468                 if path.exists("/etc/exports") and path.exists("/usr/sbin/exportfs"):
1469                         Console().ePopen(("exportfs -r"))
1470
1471         def unmountPartitionbyMountpoint(self, mountpoint, device = None):
1472                 if path.exists(mountpoint) and path.ismount(mountpoint):
1473                         cmd = "umount" + " " + mountpoint
1474                         print "[unmountPartitionbyMountpoint] %s:" % (cmd)
1475                         system(cmd)
1476                 if path.exists(mountpoint) and not path.ismount(mountpoint):
1477                         part = self.getPartitionbyMountpoint(mountpoint)
1478                         if part is not None:
1479                                 if part.uuid is not None and part.uuid == config.storage_options.default_device.value: #unmounting Default Mountpoint /media/hdd
1480                                         #call the notifier also here if we unmounted the default partition
1481                                         for callback in self.delayed_device_Notifier:
1482                                                 try:
1483                                                         callback(part.device, "remove_default" )
1484                                                 except AttributeError:
1485                                                         self.delayed_device_Notifier.remove(callback)
1486                                         part.device = None
1487                                         part.updatePartitionInfo()
1488                         if device is not None and not path.ismount(mountpoint):
1489                                 self.removeMountedPartitionbyDevice(device)
1490                         self.reloadExports()
1491         
1492         def unmountPartitionbyUUID(self, uuid):
1493                 mountpoint = config.storage[uuid]['mountpoint'].value
1494                 if mountpoint != "":
1495                         if path.exists(mountpoint) and path.ismount(mountpoint):
1496                                 if self.isUUIDpathFsTabMount(uuid, mountpoint) or self.isPartitionpathFsTabMount(uuid, mountpoint):
1497                                         print "[unmountPartitionbyUUID] disabling config entry for external mounted mountpoint %s:" % (mountpoint)
1498                                         config.storage[uuid]["enabled"].value = False
1499                                         config.storage.save()
1500                                 else:
1501                                         cmd = "umount" + " " + mountpoint
1502                                         print "[unmountPartitionbyUUID] %s:" % (mountpoint)
1503                                         system(cmd)
1504                                 self.reloadExports()
1505
1506         def mountPartitionbyUUID(self, uuid):
1507                 if path.exists("/dev/disk/by-uuid/" + uuid):
1508                         cfg_uuid = config.storage.get(uuid, None)
1509                         partitionPath = "/dev/disk/by-uuid/" + uuid
1510                         mountpoint = cfg_uuid['mountpoint'].value
1511                         dev = self.getDeviceNamebyUUID(uuid)
1512                         devicepath = "/dev/" + str(dev)
1513                         #print "[mountPartitionbyUUID] for UUID:'%s' - '%s'" % (uuid,mountpoint)
1514
1515                         #verify if mountpoint is still mounted from elsewhere (e.g fstab)
1516                         if path.exists(mountpoint) and path.ismount(mountpoint):
1517                                 tmppath = self.get_mountdevice(mountpoint)
1518                                 if tmppath is not None and tmppath.startswith("/dev/disk/by-uuid/") and tmppath != partitionPath: #probably different device mounted on our mountpoint
1519                                         tmpuuid = tmppath.rsplit("/",1)[1]
1520                                         if not self.isUUIDpathFsTabMount(tmpuuid, mountpoint) and not self.isPartitionpathFsTabMount(tmpuuid, mountpoint):
1521                                                 self.unmountPartitionbyMountpoint(mountpoint)
1522
1523                         #verify if our device is still mounted to somewhere else
1524                         tmpmount = self.get_mountpoint(partitionPath)
1525                         if tmpmount is not None and tmpmount != mountpoint and path.exists(tmpmount) and path.ismount(tmpmount):
1526                                 if not self.isUUIDpathFsTabMount(uuid, tmpmount) and not self.isPartitionpathFsTabMount(uuid, tmpmount):
1527                                                 self.unmountPartitionbyMountpoint(tmpmount)
1528                                 
1529                         
1530                         if self.isUUIDpathFsTabMount(uuid, mountpoint) or self.isPartitionpathFsTabMount(uuid, mountpoint):
1531                                 print "[unmountPartitionbyUUID] disabling config entry for external mounted mountpoint %s:" % (mountpoint)
1532                                 cfg_uuid["enabled"].value = False
1533                                 config.storage.save()
1534
1535                         if cfg_uuid['enabled'].value:
1536                                 if mountpoint != "":
1537                                         if not path.exists(mountpoint):
1538                                                 try:
1539                                                         makedirs(mountpoint)
1540                                                 except OSError:
1541                                                         print "[mountPartitionbyUUID] could not create mountdir:",mountpoint
1542
1543                                         if path.exists(mountpoint) and not path.ismount(mountpoint) and not path.islink(mountpoint):
1544                                                 cmd = "mount -t auto /dev/disk/by-uuid/" + uuid + " " + mountpoint
1545                                                 system(cmd)
1546                                                 print "[mountPartitionbyUUID]:",cmd
1547
1548                                         if path.ismount(mountpoint):
1549                                                 dev = self.getDeviceNamebyUUID(uuid)
1550                                                 if dev is not None:
1551                                                         p = self.getPartitionbyMountpoint(mountpoint)
1552                                                         if p is not None:
1553                                                                 x = self.getPartitionbyDevice(dev)
1554                                                                 if x is not None and x.mountpoint.startswith('/autofs'):
1555                                                                         self.removeMountedPartitionbyDevice(dev) #remove now obsolete entry
1556                                                                 p.mountpoint = mountpoint
1557                                                                 p.uuid = uuid
1558                                                                 p.device = dev
1559                                                                 p.force_mounted = False
1560                                                                 p.updatePartitionInfo()
1561                                                         else:
1562                                                                 p = self.getPartitionbyDevice(dev)
1563                                                                 if p is not None:
1564                                                                         p.mountpoint = mountpoint
1565                                                                         p.uuid = uuid
1566                                                                         p.device = dev
1567                                                                         p.force_mounted = False
1568                                                                         p.updatePartitionInfo()
1569                                         else:
1570                                                 print "[mountPartitionbyUUID] could not mount mountdir:",mountpoint
1571                 else:
1572                         print "[mountPartitionbyUUID] failed for UUID:'%s'" % (uuid)
1573                         
1574         def storageDeviceChanged(self, uuid):
1575                 if config.storage[uuid]["enabled"].value:
1576                         #print "[storageDeviceChanged] for enabled UUID:'%s'" % (uuid)
1577                         self.mountPartitionbyUUID(uuid)
1578                 else:
1579                         #print "[storageDeviceChanged] for disabled UUID:'%s'" % (uuid)
1580                         self.unmountPartitionbyUUID(uuid)
1581
1582         def setupConfigEntries(self, initial_call = False, dev = None):
1583                 if initial_call and not dev:
1584                         for uuid in config.storage.stored_values:
1585                                 print "[setupConfigEntries] initial_call for stored uuid:",uuid,config.storage.stored_values[uuid]
1586                                 config.storage[uuid] = ConfigSubDict()
1587                                 config.storage[uuid]["enabled"] = ConfigYesNo(default = False)
1588                                 config.storage[uuid]["mountpoint"] = ConfigText(default = "", visible_width = 50, fixed_size = False)
1589                                 config.storage[uuid]["device_description"] = ConfigText(default = "", visible_width = 50, fixed_size = False)
1590                                 config.storage[uuid]["device_info"] = ConfigText(default = "", visible_width = 50, fixed_size = False)
1591                                 config.storage[uuid]["isRemovable"] = ConfigBoolean(default = False)
1592                                 if config.storage[uuid]['enabled'].value:
1593                                         dev = self.getDeviceNamebyUUID(uuid)
1594                                         if uuid == config.storage_options.default_device.value and config.storage[uuid]["mountpoint"].value != "/media/hdd":
1595                                                 print "[setupConfigEntries] initial_call discovered a default storage device misconfiguration, reapplied default storage config for:",uuid
1596                                                 if dev is not None:                                             
1597                                                         self.unmountPartitionbyMountpoint(config.storage[uuid]["mountpoint"].value, dev)
1598                                                 config.storage[uuid]["mountpoint"].value = "/media/hdd"
1599                                         if dev is not None:
1600                                                 p = self.getPartitionbyDevice(dev) or self.getPartitionbyMountpoint(config.storage[uuid]["mountpoint"].value)
1601                                                 if p is None: # manually add partition entry
1602                                                         description = self.getDeviceDescription(dev)
1603                                                         device_mountpoint = self.getAutofsMountpoint(dev)
1604                                                         if config.storage[uuid]['mountpoint'].value != "":
1605                                                                 device_mountpoint = config.storage[uuid]['mountpoint'].value
1606                                                         p = Partition(mountpoint = device_mountpoint, description = description, force_mounted = False, device = dev)
1607                                                         p.uuid = uuid
1608                                                         p.updatePartitionInfo()
1609                                                         self.partitions.append(p)
1610                                                         self.on_partition_list_change("add", p) 
1611                                         if path.exists("/dev/disk/by-uuid/" + uuid):
1612                                                 self.storageDeviceChanged(uuid)
1613                                 else:
1614                                         del config.storage[uuid]
1615                 if dev is not None:
1616                         uuid = self.getPartitionUUID(dev)
1617                         if uuid is not None:
1618                                 if config.storage.get(uuid, None) is None: #new unconfigured device added
1619                                         print "[setupConfigEntries] new device add for '%s' with uuid:'%s'" % (dev, uuid)
1620                                         hdd = self.getHDD(dev)
1621                                         if hdd is not None:
1622                                                 hdd_description = hdd.model()
1623                                                 cap = hdd.capacity()
1624                                                 if cap != "":
1625                                                         hdd_description += " (" + cap + ")"
1626                                                 device_info =  hdd.bus_description()
1627                                         else:
1628                                                 device_info = dev
1629                                                 hdd_description = self.getDeviceDescription(dev)
1630                                         config.storage[uuid] = ConfigSubDict()
1631                                         config.storage[uuid]["enabled"] = ConfigYesNo(default = False)
1632                                         config.storage[uuid]["mountpoint"] = ConfigText(default = "", visible_width = 50, fixed_size = False)
1633                                         config.storage[uuid]["device_description"] = ConfigText(default = "", visible_width = 50, fixed_size = False)
1634                                         config.storage[uuid]["device_info"] = ConfigText(default = "", visible_width = 50, fixed_size = False)
1635                                         config.storage[uuid]["isRemovable"] = ConfigBoolean(default = False)
1636                                         removable = False
1637                                         if hdd is not None:
1638                                                 removable = hdd.isRemovable
1639                                         config.storage[uuid]["device_description"].setValue(hdd_description)
1640                                         config.storage[uuid]["device_info"].setValue(device_info)
1641                                         config.storage[uuid]["isRemovable"].setValue(removable)
1642                                         p = self.getPartitionbyDevice(dev)
1643                                         if p is None: # manually add partition entry (e.g. on long spinup times)
1644                                                 description = self.getDeviceDescription(dev)
1645                                                 device_mountpoint = self.getAutofsMountpoint(dev)
1646                                                 p = Partition(mountpoint = device_mountpoint, description = description, force_mounted = True, device = dev)
1647                                                 p.uuid = uuid
1648                                                 p.updatePartitionInfo()
1649                                                 self.partitions.append(p)
1650                                                 self.on_partition_list_change("add", p) 
1651                                         self.storageDeviceChanged(uuid)
1652                                 else:
1653                                         p = self.getPartitionbyDevice(dev)
1654                                         device_mountpoint = self.getAutofsMountpoint(dev)
1655                                         if config.storage[uuid]['enabled'].value and config.storage[uuid]['mountpoint'].value != "":
1656                                                 device_mountpoint = config.storage[uuid]['mountpoint'].value
1657                                         if p is None: # manually add partition entry (e.g. on default storage device change) !!!!!!!!!!!
1658                                                 description = self.getDeviceDescription(dev)
1659                                                 p = Partition(mountpoint = device_mountpoint, description = description, force_mounted = True, device = dev)
1660                                                 p.uuid = uuid
1661                                                 p.updatePartitionInfo()
1662                                                 self.partitions.append(p)
1663                                                 self.on_partition_list_change("add", p) 
1664                                                 print "[setupConfigEntries] new/changed device add for '%s' with uuid:'%s'" % (dev, uuid)
1665                                                 self.storageDeviceChanged(uuid)
1666                                         else:
1667                                                 tmp = self.getPartitionbyMountpoint(device_mountpoint)
1668                                                 if tmp is not None and (tmp.uuid != uuid or tmp.mountpoint != config.storage[uuid]['mountpoint'].value):
1669                                                         print "[setupConfigEntries] new/changed device add for '%s' with uuid:'%s'" % (dev, uuid)
1670                                                         self.storageDeviceChanged(uuid)
1671                         else:
1672                                 print "[setupConfigEntries] device add for '%s' without uuid !!!" % (dev)
1673
1674         def verifyInstalledStorageDevices(self):
1675                 if config.storage_options.default_device.value == "<undefined>" and self.HDDCount() == 1 and not self.HDDEnabledCount(): #only one installed and unconfigured device
1676                         hdd = self.hdd[0]
1677                         if hdd and hdd.numPartitions() <= 1:
1678                                 numPart = hdd.numPartitions()
1679                                 device = hdd.device
1680                                 partitionPath = hdd.dev_path
1681                                 if numPart == 1:
1682                                         device = hdd.device + "1"
1683                                         partitionPath = hdd.partitionPath(str(numPart))
1684                                 p = self.getPartitionbyDevice(device)
1685                                 if p is not None and p.isInitialized: #only one by e2 initialized partition
1686                                         if not self.inside_mountpoint("/media/hdd") and not path.islink("/media/hdd") and not self.isUUIDpathFsTabMount(p.uuid, "/media/hdd") and not self.isPartitionpathFsTabMount(p.uuid, "/media/hdd"):
1687                                                 print "verifyInstalledStorageDevices: using found %s as default storage device" % device
1688                                                 config.storage_options.default_device.value = p.uuid
1689                                                 config.storage_options.save()
1690                                                 cfg_uuid = config.storage.get(p.uuid, None)
1691                                                 if cfg_uuid is not None and not cfg_uuid["enabled"].value:
1692                                                         cfg_uuid["enabled"].value = True
1693                                                         cfg_uuid["mountpoint"].value = "/media/hdd"
1694                                                         cfg_uuid.save()
1695                                                         config.storage.save()
1696                                                         harddiskmanager.modifyFstabEntry("/dev/disk/by-uuid/" + p.uuid, "/media/hdd", mode = "add_deactivated")
1697                                                         self.storageDeviceChanged(p.uuid)
1698
1699 harddiskmanager = HarddiskManager()
1700 harddiskmanager.enumerateBlockDevices()
1701 harddiskmanager.verifyInstalledStorageDevices() #take sure enumerateBlockdev is finished so we don't miss any at startup installed storage devices
1702