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