xref: /openbmc/skeleton/pyflashbmc/bmc_update.py (revision b6cfc545)
1#!/usr/bin/python -u
2
3import gobject
4import dbus
5import dbus.service
6import dbus.mainloop.glib
7import shutil
8import tarfile
9import os
10from obmc.dbuslib.bindings import get_dbus, DbusProperties, DbusObjectManager
11
12DBUS_NAME = 'org.openbmc.control.BmcFlash'
13OBJ_NAME = '/org/openbmc/control/flash/bmc'
14FLASH_INTF = 'org.openbmc.Flash'
15DOWNLOAD_INTF = 'org.openbmc.managers.Download'
16
17UPDATE_PATH = '/run/initramfs'
18
19
20def doExtract(members,files):
21    for tarinfo in members:
22        if files.has_key(tarinfo.name) == True:
23            yield tarinfo
24
25
26class BmcFlashControl(DbusProperties,DbusObjectManager):
27	def __init__(self,bus,name):
28		self.dbus_objects = { }
29		DbusProperties.__init__(self)
30		DbusObjectManager.__init__(self)
31		dbus.service.Object.__init__(self,bus,name)
32
33		self.Set(DBUS_NAME,"status","Idle")
34		self.Set(DBUS_NAME,"filename","")
35		self.Set(DBUS_NAME,"preserve_network_settings",True)
36		self.Set(DBUS_NAME,"restore_application_defaults",False)
37		self.Set(DBUS_NAME,"update_kernel_and_apps",False)
38		self.Set(DBUS_NAME,"clear_persistent_files",False)
39
40		bus.add_signal_receiver(self.download_error_handler,signal_name = "DownloadError")
41		bus.add_signal_receiver(self.download_complete_handler,signal_name = "DownloadComplete")
42
43		self.InterfacesAdded(name,self.properties)
44
45
46	@dbus.service.method(DBUS_NAME,
47		in_signature='ss', out_signature='')
48	def updateViaTftp(self,ip,filename):
49		self.TftpDownload(ip,filename)
50		self.Set(DBUS_NAME,"status","Downloading")
51
52	@dbus.service.method(DBUS_NAME,
53		in_signature='s', out_signature='')
54	def update(self,filename):
55		self.Set(DBUS_NAME,"filename",filename)
56		self.download_complete_handler(filename, filename)
57
58	@dbus.service.signal(DOWNLOAD_INTF,signature='ss')
59	def TftpDownload(self,ip,filename):
60		self.Set(DBUS_NAME,"filename",filename)
61		pass
62
63
64	## Signal handler
65	def download_error_handler(self,filename):
66		if (filename == self.Get(DBUS_NAME,"filename")):
67			self.Set(DBUS_NAME,"status","Download Error")
68
69	def download_complete_handler(self,outfile,filename):
70		## do update
71		if (filename != self.Get(DBUS_NAME,"filename")):
72			return
73
74		print "Download complete. Updating..."
75
76		self.Set(DBUS_NAME,"status","Download Complete")
77		copy_files = {}
78
79		## determine needed files
80		if (self.Get(DBUS_NAME,"update_kernel_and_apps") == False):
81			copy_files["image-bmc"] = True
82		else:
83			copy_files["image-kernel"] = True
84			copy_files["image-initramfs"] = True
85			copy_files["image-rofs"] = True
86
87		if (self.Get(DBUS_NAME,"restore_application_defaults") == True):
88			copy_files["image-rwfs"] = True
89
90
91		## make sure files exist in archive
92		try:
93			tar = tarfile.open(outfile,"r")
94			files = {}
95			for f in tar.getnames():
96				files[f] = True
97			tar.close()
98			for f in copy_files.keys():
99				if (files.has_key(f) == False):
100					raise Exception("ERROR: File not found in update archive: "+f)
101
102		except Exception as e:
103			print e
104			self.Set(DBUS_NAME,"status","Update Error")
105			return
106
107		try:
108			tar = tarfile.open(outfile,"r")
109			tar.extractall(UPDATE_PATH,members=doExtract(tar,copy_files))
110			tar.close()
111
112			if (self.Get(DBUS_NAME,"clear_persistent_files") == True):
113				print "Removing persistent files"
114				try:
115					os.unlink(UPDATE_PATH+"/whitelist")
116				except OSError as e:
117					if (e.errno == errno.EISDIR):
118						pass
119					elif (e.errno == errno.ENOENT):
120						pass
121					else:
122						raise
123
124				try:
125					wldir = UPDATE_PATH + "/whitelist.d"
126
127					for file in os.listdir(wldir):
128						os.unlink(os.path.join(wldir,file))
129				except OSError as e:
130					if (e.errno == errno.EISDIR):
131						pass
132					else:
133						raise
134
135			if (self.Get(DBUS_NAME,"preserve_network_settings") == True):
136				print "Preserving network settings"
137				shutil.copy2("/run/fw_env",UPDATE_PATH+"/image-u-boot-env")
138
139		except Exception as e:
140			print e
141			self.Set(DBUS_NAME,"status","Update Error")
142
143
144
145		self.Set(DBUS_NAME,"status","Update Success.  Please reboot.")
146
147
148if __name__ == '__main__':
149    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
150
151    bus = get_dbus()
152    name = dbus.service.BusName(DBUS_NAME, bus)
153    obj = BmcFlashControl(bus, OBJ_NAME)
154    mainloop = gobject.MainLoop()
155
156    print "Running Bmc Flash Control"
157    mainloop.run()
158
159