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