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