1 #include <stdio.h>
2 #include <stdbool.h>
3 #include <string.h>
4 #include <sys/wait.h>
5 #include <sys/types.h>
6 #include <openbmc_intf.h>
7 #include <openbmc.h>
8 
9 /* ------------------------------------------------------------------------- */
10 static const gchar* dbus_object_path = "/org/openbmc/control/flash";
11 static const gchar* dbus_name = "org.openbmc.control.Flash";
12 static const gchar* FLASHER_BIN = "flasher.exe";
13 
14 static GDBusObjectManagerServer *manager = NULL;
15 
16 void
17 catch_child(int sig_num)
18 {
19 	/* when we get here, we know there's a zombie child waiting */
20 	int child_status;
21 
22 	wait(&child_status);
23 	printf("flasher exited.\n");
24 }
25 
26 int
27 update(Flash* flash, const char* obj_path)
28 {
29 	pid_t pid;
30 	int status=-1;
31 	pid = fork();
32 	if(pid == 0)
33 	{
34 		const gchar* name = flash_get_flasher_name(flash);
35 		const gchar* inst = flash_get_flasher_instance(flash);
36 		const gchar* filename = flash_get_filename(flash);
37 		status = execlp(name, name, inst, filename, obj_path, NULL);
38 		return status;
39 	}
40 	return 0;
41 }
42 
43 static gboolean
44 on_init(Flash *f,
45 		GDBusMethodInvocation *invocation,
46 		gpointer user_data)
47 {
48 	flash_complete_init(f,invocation);
49 
50 	//tune flash
51 	if(strcmp(flash_get_flasher_instance(f),"bios") == 0)
52 	{
53 		flash_set_filename(f,"");
54 		const gchar* obj_path = g_dbus_object_get_object_path((GDBusObject*)user_data);
55 		int rc = update(f,obj_path);
56 		if(rc==-1)
57 		{
58 			printf("ERROR FlashControl: Unable to init\n");
59 		}
60 		sleep(3);
61 		rc = update(f,obj_path);
62 
63 	}
64 	return TRUE;
65 }
66 
67 static gboolean
68 on_lock(SharedResource *lock,
69 		GDBusMethodInvocation *invocation,
70 		gchar* name,
71 		gpointer user_data)
72 {
73 	gboolean locked = shared_resource_get_lock(lock);
74 	if(locked)
75 	{
76 		const gchar* name = shared_resource_get_name(lock);
77 		printf("ERROR: BIOS Flash is already locked: %s\n",name);
78 	}
79 	else
80 	{
81 		printf("Locking BIOS Flash: %s\n",name);
82 		shared_resource_set_lock(lock,true);
83 		shared_resource_set_name(lock,name);
84 	}
85 	shared_resource_complete_lock(lock,invocation);
86 	return TRUE;
87 }
88 
89 static gboolean
90 on_is_locked(SharedResource *lock,
91 		GDBusMethodInvocation *invocation,
92 		gpointer user_data)
93 {
94 	gboolean locked = shared_resource_get_lock(lock);
95 	const gchar* name = shared_resource_get_name(lock);
96 	shared_resource_complete_is_locked(lock,invocation,locked,name);
97 	return TRUE;
98 }
99 
100 static gboolean
101 on_unlock(SharedResource *lock,
102 		GDBusMethodInvocation *invocation,
103 		gpointer user_data)
104 {
105 	printf("Unlocking BIOS Flash\n");
106 	shared_resource_set_lock(lock,false);
107 	shared_resource_set_name(lock,"");
108 	shared_resource_complete_unlock(lock,invocation);
109 	return TRUE;
110 }
111 
112 static gboolean
113 on_update_via_tftp(Flash *flash,
114 		GDBusMethodInvocation *invocation,
115 		gchar* url,
116 		gchar* write_file,
117 		gpointer user_data)
118 {
119 	SharedResource *lock = object_get_shared_resource((Object*)user_data);
120 	gboolean locked = shared_resource_get_lock(lock);
121 	flash_complete_update_via_tftp(flash,invocation);
122 	if(locked)
123 	{
124 		const gchar* name = shared_resource_get_name(lock);
125 		printf("BIOS Flash is locked: %s\n",name);
126 	}
127 	else
128 	{
129 		printf("Flashing BIOS from TFTP: %s,%s\n",url,write_file);
130 		flash_set_filename(flash,write_file);
131 		flash_emit_download(flash,url,write_file);
132 		flash_set_status(flash,"Downloading");
133 	}
134 	return TRUE;
135 }
136 
137 static gboolean
138 on_error(Flash *flash,
139 		GDBusMethodInvocation *invocation,
140 		gchar* error_msg,
141 		gpointer user_data)
142 {
143 	SharedResource *lock = object_get_shared_resource((Object*)user_data);
144 	shared_resource_get_lock(lock);
145 	flash_set_status(flash, error_msg);
146 	flash_complete_error(flash,invocation);
147 	printf("ERROR: %s.  Clearing locks\n",error_msg);
148 	shared_resource_set_lock(lock,false);
149 	shared_resource_set_name(lock,"");
150 
151 	return TRUE;
152 }
153 
154 static gboolean
155 on_done(Flash *flash,
156 		GDBusMethodInvocation *invocation,
157 		gpointer user_data)
158 {
159 	int rc = 0;
160 	SharedResource *lock = object_get_shared_resource((Object*)user_data);
161 	shared_resource_get_lock(lock);
162 	flash_set_status(flash, "Flash Done");
163 	flash_complete_done(flash,invocation);
164 	printf("Flash Done. Clearing locks\n");
165 	shared_resource_set_lock(lock,false);
166 	shared_resource_set_name(lock,"");
167 	const gchar* filename = flash_get_filename(flash);
168 	rc = unlink(filename);
169 	if(rc != 0 )
170 	{
171 		printf("ERROR: Unable to delete file %s (%d)\n",filename,rc);
172 	}
173 
174 	return TRUE;
175 }
176 
177 static gboolean
178 on_update(Flash *flash,
179 		GDBusMethodInvocation *invocation,
180 		gchar* write_file,
181 		gpointer user_data)
182 {
183 	int rc = 0;
184 	SharedResource *lock = object_get_shared_resource((Object*)user_data);
185 	gboolean locked = shared_resource_get_lock(lock);
186 	flash_set_status(flash,"Flashing");
187 	flash_complete_update(flash,invocation);
188 	if(locked)
189 	{
190 		const gchar* name = shared_resource_get_name(lock);
191 		printf("BIOS Flash is locked: %s\n",name);
192 	}
193 	else
194 	{
195 		printf("Flashing BIOS from: %s\n",write_file);
196 		flash_set_status(flash, "Flashing");
197 		shared_resource_set_lock(lock,true);
198 		shared_resource_set_name(lock,dbus_object_path);
199 		flash_set_filename(flash,write_file);
200 		const gchar* obj_path = g_dbus_object_get_object_path((GDBusObject*)user_data);
201 		rc = update(flash,obj_path);
202 		if(!rc)
203 		{
204 			shared_resource_set_lock(lock,false);
205 			shared_resource_set_name(lock,"");
206 		}
207 	}
208 	return TRUE;
209 }
210 
211 static void
212 on_flash_progress(GDBusConnection* connection,
213 		const gchar* sender_name,
214 		const gchar* object_path,
215 		const gchar* interface_name,
216 		const gchar* signal_name,
217 		GVariant* parameters,
218 		gpointer user_data)
219 {
220 	Flash *flash = object_get_flash((Object*)user_data);
221 	object_get_shared_resource((Object*)user_data);
222 	GVariantIter *iter = g_variant_iter_new(parameters);
223 	g_variant_iter_next_value(iter);
224 	GVariant* v_progress = g_variant_iter_next_value(iter);
225 
226 	uint8_t progress = g_variant_get_byte(v_progress);
227 
228 	gchar *s;
229 	s = g_strdup_printf("Flashing: %d%%",progress);
230 	flash_set_status(flash,s);
231 	g_free(s);
232 }
233 
234 static void
235 on_bus_acquired(GDBusConnection *connection,
236 		const gchar *name,
237 		gpointer user_data)
238 {
239 	ObjectSkeleton *object;
240 	cmdline *cmd = user_data;
241 	manager = g_dbus_object_manager_server_new(dbus_object_path);
242 	int i=0;
243 
244 	gchar *flasher_file = g_strdup_printf("%s", FLASHER_BIN);
245 
246 	const char* inst[] = {"bios"};
247 	for(i=0;i<1;i++)
248 	{
249 		gchar* s;
250 		s = g_strdup_printf("%s/%s",dbus_object_path,inst[i]);
251 		object = object_skeleton_new(s);
252 		g_free(s);
253 
254 		Flash* flash = flash_skeleton_new();
255 		object_skeleton_set_flash(object, flash);
256 		g_object_unref(flash);
257 
258 		SharedResource* lock = shared_resource_skeleton_new();
259 		object_skeleton_set_shared_resource(object, lock);
260 		g_object_unref(lock);
261 
262 		shared_resource_set_lock(lock,false);
263 		shared_resource_set_name(lock,"");
264 
265 		flash_set_flasher_name(flash,FLASHER_BIN);
266 		flash_set_flasher_instance(flash,inst[i]);
267 		//g_free (s);
268 
269 
270 		//define method callbacks here
271 		g_signal_connect(lock,
272 				"handle-lock",
273 				G_CALLBACK(on_lock),
274 				NULL); /* user_data */
275 		g_signal_connect(lock,
276 				"handle-unlock",
277 				G_CALLBACK(on_unlock),
278 				NULL); /* user_data */
279 		g_signal_connect(lock,
280 				"handle-is-locked",
281 				G_CALLBACK(on_is_locked),
282 				NULL); /* user_data */
283 
284 		g_signal_connect(flash,
285 				"handle-update",
286 				G_CALLBACK(on_update),
287 				object); /* user_data */
288 
289 		g_signal_connect(flash,
290 				"handle-error",
291 				G_CALLBACK(on_error),
292 				object); /* user_data */
293 
294 		g_signal_connect(flash,
295 				"handle-done",
296 				G_CALLBACK(on_done),
297 				object); /* user_data */
298 
299 		g_signal_connect(flash,
300 				"handle-update-via-tftp",
301 				G_CALLBACK(on_update_via_tftp),
302 				object); /* user_data */
303 
304 		g_signal_connect(flash,
305 				"handle-init",
306 				G_CALLBACK(on_init),
307 				object); /* user_data */
308 
309 		s = g_strdup_printf("/org/openbmc/control/%s",inst[i]);
310 		g_dbus_connection_signal_subscribe(connection,
311 				NULL,
312 				"org.openbmc.FlashControl",
313 				"Progress",
314 				s,
315 				NULL,
316 				G_DBUS_SIGNAL_FLAGS_NONE,
317 				(GDBusSignalCallback) on_flash_progress,
318 				object,
319 				NULL );
320 
321 		g_free(s);
322 
323 
324 		flash_set_filename(flash,"");
325 		/* Export the object (@manager takes its own reference to @object) */
326 		g_dbus_object_manager_server_set_connection(manager, connection);
327 		g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object));
328 		g_object_unref(object);
329 	}
330 	g_free(flasher_file);
331 }
332 
333 static void
334 on_name_acquired(GDBusConnection *connection,
335 		const gchar *name,
336 		gpointer user_data)
337 {
338 	//  g_print ("Acquired the name %s\n", name);
339 }
340 
341 static void
342 on_name_lost(GDBusConnection *connection,
343 		const gchar *name,
344 		gpointer user_data)
345 {
346 	//g_print ("Lost the name %s\n", name);
347 }
348 
349 gint
350 main(gint argc, gchar *argv[])
351 {
352 	GMainLoop *loop;
353 	cmdline cmd;
354 	cmd.argc = argc;
355 	cmd.argv = argv;
356 	guint id;
357 	loop = g_main_loop_new(NULL, FALSE);
358 
359 	signal(SIGCHLD, catch_child);
360 	id = g_bus_own_name(DBUS_TYPE,
361 			dbus_name,
362 			G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
363 			G_BUS_NAME_OWNER_FLAGS_REPLACE,
364 			on_bus_acquired,
365 			on_name_acquired,
366 			on_name_lost,
367 			&cmd,
368 			NULL);
369 
370 	g_main_loop_run(loop);
371 
372 	g_bus_unown_name(id);
373 	g_main_loop_unref(loop);
374 	return 0;
375 }
376