add support for cyclic garbage collection to eTimer and eSocketNotifier
[vuplus_dvbapp] / lib / python / Components / Harddisk.py
1 from os import system, listdir, statvfs, popen, makedirs
2
3 from Tools.Directories import SCOPE_HDD, resolveFilename
4 from Tools.CList import CList
5
6 from SystemInfo import SystemInfo
7
8 def tryOpen(filename):
9         try:
10                 procFile = open(filename)
11         except IOError:
12                 return ""
13         return procFile
14
15 def num2prochdx(num):
16         return "/proc/ide/hd" + ("a","b","c","d","e","f","g","h","i")[num] + "/"
17
18 class Harddisk:
19         def __init__(self, index):
20                 self.index = index
21
22                 host = (self.index & 2) >> 1
23                 bus = 0
24                 target = (self.index & 1)
25
26                 self.prochdx = num2prochdx(index)
27                 self.devidex = "/dev/ide/host%d/bus%d/target%d/lun0/" % (host, bus, target)
28
29         def getIndex(self):
30                 return self.index
31
32         def bus(self):
33                 ret = ""
34
35                 if self.index & 2:
36                         ret = "External (CF) - "
37                 else:
38                         ret = "Internal - "
39                 
40                 if self.index & 1:
41                         return ret + "Slave"
42                 else:
43                         return ret + "Master"
44
45         def capacity(self):
46                 procfile = tryOpen(self.prochdx + "capacity")
47                 
48                 if procfile == "":
49                         return ""
50
51                 line = procfile.readline()
52                 procfile.close()
53                 
54                 try:
55                         cap = int(line)
56                 except:
57                         return ""
58                 
59                 cap = cap / 1000 * 512 / 1000
60                 
61                 return "%d.%03d GB" % (cap/1024, cap%1024)
62                                                                 
63         def model(self):
64                 procfile = tryOpen(self.prochdx + "model")
65
66                 if procfile == "":
67                         return ""
68
69                 line = procfile.readline()
70                 procfile.close()
71
72                 return line.strip()
73
74         def free(self):
75                 procfile = tryOpen("/proc/mounts")
76                 
77                 if procfile == "":
78                         return -1
79
80                 free = -1
81                 while 1:
82                         line = procfile.readline()
83                         if line == "":
84                                 break
85                         if line.startswith(self.devidex):
86                                 parts = line.strip().split(" ")
87                                 try:
88                                         stat = statvfs(parts[1])
89                                 except OSError:
90                                         continue
91                                 free = stat.f_bfree/1000 * stat.f_bsize/1000
92                                 break
93                 procfile.close()
94                 return free             
95
96         def numPartitions(self):
97                 try:
98                         idedir = listdir(self.devidex)
99                 except OSError:
100                         return -1
101                 numPart = -1
102                 for filename in idedir:
103                         if filename.startswith("disc"):
104                                 numPart += 1
105                         if filename.startswith("part"):
106                                 numPart += 1
107                 return numPart
108
109         def unmount(self):
110                 procfile = tryOpen("/proc/mounts")
111
112                 if procfile == "":
113                         return -1
114
115                 cmd = "/bin/umount"
116
117                 for line in procfile:
118                         if line.startswith(self.devidex):
119                                 parts = line.split()
120                                 cmd = ' '.join([cmd, parts[1]])
121
122                 procfile.close()
123
124                 res = system(cmd)
125                 return (res >> 8)
126
127         def createPartition(self):
128                 cmd = "/sbin/sfdisk -f " + self.devidex + "disc"
129                 sfdisk = popen(cmd, "w")
130                 sfdisk.write("0,\n;\n;\n;\ny\n")
131                 sfdisk.close()
132                 return 0
133
134         def mkfs(self):
135                 cmd = "/sbin/mkfs.ext3 -T largefile -m0 " + self.devidex + "part1"
136                 res = system(cmd)
137                 return (res >> 8)
138
139         def mount(self):
140                 cmd = "/bin/mount -t ext3 " + self.devidex + "part1"
141                 res = system(cmd)
142                 return (res >> 8)
143
144         def createMovieFolder(self):
145                 try:
146                         makedirs(resolveFilename(SCOPE_HDD))
147                 except OSError:
148                         return -1
149                 return 0
150
151         def fsck(self):
152                 # We autocorrect any failures
153                 # TODO: we could check if the fs is actually ext3
154                 cmd = "/sbin/fsck.ext3 -f -p " + self.devidex + "part1"
155                 res = system(cmd)
156                 return (res >> 8)
157
158         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")]
159
160         def initialize(self):
161                 self.unmount()
162
163                 if self.createPartition() != 0:
164                         return -1
165
166                 if self.mkfs() != 0:
167                         return -2
168
169                 if self.mount() != 0:
170                         return -3
171
172                 #only create a movie folder on the internal hdd
173                 if not self.index & 2 and self.createMovieFolder() != 0:
174                         return -4
175                 
176                 return 0
177
178         def check(self):
179                 self.unmount()
180
181                 res = self.fsck()
182                 if res & 2 == 2:
183                         return -6
184
185                 if res & 4 == 4:
186                         return -7
187
188                 if res != 0 and res != 1:
189                         # A sum containing 1 will also include a failure
190                         return -5
191
192                 if self.mount() != 0:
193                         return -3
194
195                 return 0
196
197 def existHDD(num):
198         mediafile = tryOpen(num2prochdx(num) + "media")
199
200         if mediafile == "":
201                 return -1
202
203         line = mediafile.readline()
204         mediafile.close()
205         
206         if line.startswith("disk"):
207                 return 1
208         
209         return -1
210
211 class Partition:
212         def __init__(self, mountpoint, description = "", force_mounted = False):
213                 self.mountpoint = mountpoint
214                 self.description = description
215                 self.force_mounted = force_mounted
216
217         def stat(self):
218                 return statvfs(self.mountpoint)
219
220         def free(self):
221                 try:
222                         s = self.stat()
223                         return s.f_bavail * s.f_bsize
224                 except OSError:
225                         return None
226         
227         def total(self):
228                 try:
229                         s = self.stat()
230                         return s.f_blocks * s.f_bsize
231                 except OSError:
232                         return None
233
234         def mounted(self):
235                 # THANK YOU PYTHON FOR STRIPPING AWAY f_fsid.
236                 # TODO: can os.path.ismount be used?
237                 if self.force_mounted:
238                         return True
239                 procfile = tryOpen("/proc/mounts")
240                 for n in procfile.readlines():
241                         if n.split(' ')[1] == self.mountpoint:
242                                 return True
243                 return False
244
245 class HarddiskManager:
246         def __init__(self):
247                 hddNum = 0
248                 self.hdd = [ ]
249                 
250                 self.partitions = [ ]
251                 
252                 self.on_partition_list_change = CList()
253                 
254                 for hddNum in range(8):
255                         if existHDD(hddNum):
256                                 hdd = Harddisk(hddNum)
257                                 self.hdd.append(hdd)
258
259                 SystemInfo["Harddisc"] = len(self.hdd) > 0
260
261                 # currently, this is just an enumeration of what's possible,
262                 # this probably has to be changed to support automount stuff.
263                 # still, if stuff is mounted into the correct mountpoints by
264                 # external tools, everything is fine (until somebody inserts 
265                 # a second usb stick.)
266                 p = [
267                                         ("/media/hdd", _("Harddisk")), 
268                                         ("/media/card", _("Card")), 
269                                         ("/media/cf", _("Compact Flash")),
270                                         ("/media/mmc1", _("MMC Card")),
271                                         ("/media/net", _("Network Mount")),
272                                         ("/media/ram", _("Ram Disk")),
273                                         ("/media/usb", _("USB Stick")),
274                                         ("/", _("Internal Flash"))
275                                 ]
276                 
277                 for x in p:
278                         self.partitions.append(Partition(mountpoint = x[0], description = x[1]))
279
280         def getAutofsMountpoint(self, device):
281                 return "/autofs/%s/" % (device)
282
283         def addHotplugPartition(self, device, description):
284                 p = Partition(mountpoint = self.getAutofsMountpoint(device), description = description, force_mounted = True)
285                 self.partitions.append(p)
286                 self.on_partition_list_change("add", p)
287
288         def removeHotplugPartition(self, device):
289                 mountpoint = self.getAutofsMountpoint(device)
290                 for x in self.partitions[:]:
291                         if x.mountpoint == mountpoint:
292                                 self.partitions.remove(x)
293                                 self.on_partition_list_change("remove", x)
294
295         def HDDCount(self):
296                 return len(self.hdd)
297
298         def HDDList(self):
299                 list = [ ]
300                 for hd in self.hdd:
301                         hdd = hd.model() + " (" 
302                         hdd += hd.bus()
303                         cap = hd.capacity()     
304                         if cap != "":
305                                 hdd += ", " + cap
306                         hdd += ")"
307                         list.append((hdd, hd))
308
309                 return list
310
311         def getMountedPartitions(self):
312                 return [x for x in self.partitions if x.mounted()]
313
314 harddiskmanager = HarddiskManager()