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