1#!/usr/bin/python -u 2 3import sys 4import subprocess 5import gobject 6import dbus 7import dbus.service 8import dbus.mainloop.glib 9import os 10import time 11import obmc.dbuslib.propertycacher as PropertyCacher 12from obmc.dbuslib.bindings import DbusProperties, DbusObjectManager, get_dbus 13import obmc.enums 14import obmc_system_config as System 15import obmc.dbuslib.introspection 16import obmc.utils.misc 17 18DBUS_NAME = 'org.openbmc.managers.System' 19OBJ_NAME = '/org/openbmc/managers/System' 20HEARTBEAT_CHECK_INTERVAL = 20000 21STATE_START_TIMEOUT = 10 22INTF_SENSOR = 'org.openbmc.SensorValue' 23INTF_ITEM = 'org.openbmc.InventoryItem' 24INTF_CONTROL = 'org.openbmc.Control' 25 26 27class SystemManager(DbusProperties,DbusObjectManager): 28 def __init__(self,bus,obj_name): 29 DbusProperties.__init__(self) 30 DbusObjectManager.__init__(self) 31 dbus.service.Object.__init__(self,bus,obj_name) 32 self.bus = bus 33 34 bus.add_signal_receiver( 35 self.bus_handler, 36 dbus_interface=dbus.BUS_DAEMON_IFACE, 37 signal_name='NameOwnerChanged') 38 bus.add_signal_receiver(self.NewObjectHandler, 39 signal_name = "InterfacesAdded", sender_keyword = 'bus_name') 40 bus.add_signal_receiver(self.SystemStateHandler,signal_name = "GotoSystemState") 41 42 self.Set(DBUS_NAME,"current_state","") 43 self.system_states = {} 44 self.bus_name_lookup = {} 45 self.bin_path = os.path.dirname(os.path.realpath(sys.argv[0])) 46 47 for name in System.APPS.keys(): 48 sys_state = System.APPS[name]['system_state'] 49 if (self.system_states.has_key(sys_state) == False): 50 self.system_states[sys_state] = [] 51 self.system_states[sys_state].append(name) 52 53 ## replace symbolic path in ID_LOOKUP 54 for category in System.ID_LOOKUP: 55 for key in System.ID_LOOKUP[category]: 56 val = System.ID_LOOKUP[category][key] 57 new_val = val.replace("<inventory_root>",System.INVENTORY_ROOT) 58 System.ID_LOOKUP[category][key] = new_val 59 60 self.SystemStateHandler(System.SYSTEM_STATES[0]) 61 62 if not os.path.exists(PropertyCacher.CACHE_PATH): 63 print "Creating cache directory: "+PropertyCacher.CACHE_PATH 64 os.makedirs(PropertyCacher.CACHE_PATH) 65 66 for s in self.bus.list_names(): 67 if obmc.utils.misc.org_dot_openbmc_match(s): 68 self.bus_handler(s, '', s) 69 70 print "SystemManager Init Done" 71 72 73 def try_next_state(self): 74 current_state = self.Get(DBUS_NAME,"current_state") 75 if current_state not in System.EXIT_STATE_DEPEND: 76 return 77 78 if all(System.EXIT_STATE_DEPEND[current_state].values()): 79 print "All required objects started for "+current_state 80 self.gotoNextState() 81 82 83 def SystemStateHandler(self,state_name): 84 ## clearing object started flags 85 current_state = self.Get(DBUS_NAME,"current_state") 86 try: 87 for obj_path in System.EXIT_STATE_DEPEND[current_state]: 88 System.EXIT_STATE_DEPEND[current_state][obj_path] = 0 89 except: 90 pass 91 92 print "Running System State: "+state_name 93 if (self.system_states.has_key(state_name)): 94 for name in self.system_states[state_name]: 95 self.start_process(name) 96 97 if (state_name == "BMC_INIT"): 98 ## Add poll for heartbeat 99 gobject.timeout_add(HEARTBEAT_CHECK_INTERVAL, self.heartbeat_check) 100 101 try: 102 cb = System.ENTER_STATE_CALLBACK[state_name] 103 for methd in cb.keys(): 104 obj = bus.get_object(cb[methd]['bus_name'],cb[methd]['obj_name'],introspect=False) 105 method = obj.get_dbus_method(methd,cb[methd]['interface_name']) 106 method() 107 except: 108 pass 109 110 self.Set(DBUS_NAME,"current_state",state_name) 111 112 def gotoNextState(self): 113 s = 0 114 current_state = self.Get(DBUS_NAME,"current_state") 115 for i in range(len(System.SYSTEM_STATES)): 116 if (System.SYSTEM_STATES[i] == current_state): 117 s = i+1 118 119 if (s == len(System.SYSTEM_STATES)): 120 print "ERROR SystemManager: No more system states" 121 else: 122 new_state_name = System.SYSTEM_STATES[s] 123 print "SystemManager Goto System State: "+new_state_name 124 self.SystemStateHandler(new_state_name) 125 126 127 @dbus.service.method(DBUS_NAME, 128 in_signature='', out_signature='s') 129 def getSystemState(self): 130 return self.Get(DBUS_NAME,"current_state") 131 132 def doObjectLookup(self,category,key): 133 bus_name = "" 134 obj_path = "" 135 intf_name = INTF_ITEM 136 try: 137 obj_path = System.ID_LOOKUP[category][key] 138 bus_name = self.bus_name_lookup[obj_path] 139 parts = obj_path.split('/') 140 if (parts[3] == 'sensors'): 141 intf_name = INTF_SENSOR 142 except Exception as e: 143 print "ERROR SystemManager: "+str(e)+" not found in lookup" 144 145 return [bus_name,obj_path,intf_name] 146 147 @dbus.service.method(DBUS_NAME, 148 in_signature='ss', out_signature='(sss)') 149 def getObjectFromId(self,category,key): 150 return self.doObjectLookup(category,key) 151 152 @dbus.service.method(DBUS_NAME, 153 in_signature='sy', out_signature='(sss)') 154 def getObjectFromByteId(self,category,key): 155 byte = int(key) 156 return self.doObjectLookup(category,byte) 157 158 # Get the FRU area names defined in ID_LOOKUP table given a fru_id. 159 # If serval areas are defined for a fru_id, the areas are returned 160 # together as a string with each area name seperated with ','. 161 # If no fru area defined in ID_LOOKUP, an empty string will be returned. 162 @dbus.service.method(DBUS_NAME, 163 in_signature='y', out_signature='s') 164 def getFRUArea(self,fru_id): 165 ret_str = '' 166 fru_id = '_' + str(fru_id) 167 area_list = [area for area in System.ID_LOOKUP['FRU_STR'].keys() \ 168 if area.endswith(fru_id)] 169 for area in area_list: 170 ret_str = area + ',' + ret_str 171 # remove the last ',' 172 return ret_str[:-1] 173 174 def start_process(self,name): 175 if (System.APPS[name]['start_process'] == True): 176 app = System.APPS[name] 177 process_name = self.bin_path+"/"+app['process_name'] 178 cmdline = [ ] 179 cmdline.append(process_name) 180 if (app.has_key('args')): 181 for a in app['args']: 182 cmdline.append(a) 183 try: 184 print "Starting process: "+" ".join(cmdline)+": "+name 185 if (app['monitor_process'] == True): 186 app['popen'] = subprocess.Popen(cmdline) 187 else: 188 subprocess.Popen(cmdline) 189 190 except Exception as e: 191 ## TODO: error 192 print "ERROR: starting process: "+" ".join(cmdline) 193 194 def heartbeat_check(self): 195 for name in System.APPS.keys(): 196 app = System.APPS[name] 197 if (app['start_process'] == True and app.has_key('popen')): 198 ## make sure process is still alive 199 p = app['popen'] 200 p.poll() 201 if (p.returncode != None): 202 print "Process for "+name+" appears to be dead" 203 self.start_process(name) 204 205 return True 206 207 def bus_handler(self, owned_name, old, new): 208 if obmc.dbuslib.bindings.is_unique(owned_name) or not new: 209 return 210 211 if owned_name == DBUS_NAME: 212 return 213 214 objs = obmc.dbuslib.introspection.find_dbus_interfaces( 215 self.bus, owned_name, '/', bool) 216 current_state = self.Get(DBUS_NAME,"current_state") 217 for o in objs.keys(): 218 if o in self.bus_name_lookup: 219 continue 220 self.bus_name_lookup[o] = owned_name 221 222 if current_state not in System.EXIT_STATE_DEPEND: 223 continue 224 if o in System.EXIT_STATE_DEPEND[current_state]: 225 print "New object: "+o+" ("+owned_name+")" 226 System.EXIT_STATE_DEPEND[current_state][o] = 1 227 228 self.try_next_state() 229 230 def NewObjectHandler(self, obj_path, iprops, bus_name = None): 231 current_state = self.Get(DBUS_NAME,"current_state") 232 if (self.bus_name_lookup.has_key(obj_path)): 233 if (self.bus_name_lookup[obj_path] == bus_name): 234 return 235 self.bus_name_lookup[obj_path] = bus_name 236 if current_state not in System.EXIT_STATE_DEPEND: 237 return 238 239 if obj_path in System.EXIT_STATE_DEPEND[current_state]: 240 print "New object: "+obj_path+" ("+bus_name+")" 241 System.EXIT_STATE_DEPEND[current_state][obj_path] = 1 242 ## check if all required objects are 243 # started to move to next state 244 self.try_next_state() 245 246 @dbus.service.method(DBUS_NAME, 247 in_signature='s', out_signature='sis') 248 def gpioInit(self,name): 249 gpio_path = '' 250 gpio_num = -1 251 r = ['',gpio_num,''] 252 if (System.GPIO_CONFIG.has_key(name) == False): 253 # TODO: Error handling 254 print "ERROR: "+name+" not found in GPIO config table" 255 else: 256 257 gpio_num = -1 258 gpio = System.GPIO_CONFIG[name] 259 if (System.GPIO_CONFIG[name].has_key('gpio_num')): 260 gpio_num = gpio['gpio_num'] 261 else: 262 if (System.GPIO_CONFIG[name].has_key('gpio_pin')): 263 gpio_num = System.convertGpio(gpio['gpio_pin']) 264 else: 265 print "ERROR: SystemManager - GPIO lookup failed for "+name 266 267 if (gpio_num != -1): 268 r = [obmc.enums.GPIO_DEV, gpio_num, gpio['direction']] 269 return r 270 271 272 273if __name__ == '__main__': 274 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 275 bus = get_dbus() 276 obj = SystemManager(bus,OBJ_NAME) 277 mainloop = gobject.MainLoop() 278 obj.unmask_signals() 279 name = dbus.service.BusName(DBUS_NAME,bus) 280 281 print "Running SystemManager" 282 mainloop.run() 283 284