#include <stdio.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#include "interfaces/openbmc_intf.h" | |
#include "openbmc.h" | |
#include "object_mapper.h" | |
/* ---------------------------------------------------------------------------------------------------- */ | |
static const gchar* dbus_object_path = "/org/openbmc/control/flash"; | |
static const gchar* dbus_name = "org.openbmc.control.Flash"; | |
static const gchar* FLASHER_BIN = "flasher.exe"; | |
static const gchar* DLOAD_BUS = "org.openbmc.managers.Download"; | |
static const gchar* DLOAD_OBJ = "/org/openbmc/managers/Download"; | |
static GDBusObjectManagerServer *manager = NULL; | |
void catch_child(int sig_num) | |
{ | |
/* when we get here, we know there's a zombie child waiting */ | |
int child_status; | |
wait(&child_status); | |
printf("flasher exited.\n"); | |
} | |
int update(Flash* flash, const char* obj_path) | |
{ | |
pid_t pid; | |
int status=-1; | |
pid = fork(); | |
if (pid == 0) | |
{ | |
const gchar* path = flash_get_flasher_path(flash); | |
const gchar* name = flash_get_flasher_name(flash); | |
const gchar* inst = flash_get_flasher_instance(flash); | |
const gchar* filename = flash_get_filename(flash); | |
status = execl(path, name, inst, filename, obj_path, NULL); | |
return status; | |
} | |
return 0; | |
} | |
static gboolean | |
on_init (Flash *f, | |
GDBusMethodInvocation *invocation, | |
gpointer user_data) | |
{ | |
flash_complete_init(f,invocation); | |
//tune flash | |
if (strcmp(flash_get_flasher_instance(f),"bios") == 0) | |
{ | |
flash_set_filename(f,""); | |
const gchar* obj_path = g_dbus_object_get_object_path((GDBusObject*)user_data); | |
int rc = update(f,obj_path); | |
if (rc==-1) | |
{ | |
printf("ERROR FlashControl: Unable to init\n"); | |
} | |
} | |
return TRUE; | |
} | |
static gboolean | |
on_lock (SharedResource *lock, | |
GDBusMethodInvocation *invocation, | |
gchar* name, | |
gpointer user_data) | |
{ | |
gboolean locked = shared_resource_get_lock(lock); | |
if (locked) | |
{ | |
const gchar* name = shared_resource_get_name(lock); | |
printf("ERROR: BIOS Flash is already locked: %s\n",name); | |
} | |
else | |
{ | |
printf("Locking BIOS Flash: %s\n",name); | |
shared_resource_set_lock(lock,true); | |
shared_resource_set_name(lock,name); | |
} | |
shared_resource_complete_lock(lock,invocation); | |
return TRUE; | |
} | |
static gboolean | |
on_is_locked (SharedResource *lock, | |
GDBusMethodInvocation *invocation, | |
gpointer user_data) | |
{ | |
gboolean locked = shared_resource_get_lock(lock); | |
const gchar* name = shared_resource_get_name(lock); | |
shared_resource_complete_is_locked(lock,invocation,locked,name); | |
return TRUE; | |
} | |
static gboolean | |
on_unlock (SharedResource *lock, | |
GDBusMethodInvocation *invocation, | |
gpointer user_data) | |
{ | |
printf("Unlocking BIOS Flash\n"); | |
shared_resource_set_lock(lock,false); | |
shared_resource_set_name(lock,""); | |
shared_resource_complete_unlock(lock,invocation); | |
return TRUE; | |
} | |
static gboolean | |
on_update_via_tftp (Flash *flash, | |
GDBusMethodInvocation *invocation, | |
gchar* url, | |
gchar* write_file, | |
gpointer user_data) | |
{ | |
SharedResource *lock = object_get_shared_resource((Object*)user_data); | |
gboolean locked = shared_resource_get_lock(lock); | |
flash_complete_update_via_tftp(flash,invocation); | |
if (locked) | |
{ | |
const gchar* name = shared_resource_get_name(lock); | |
printf("BIOS Flash is locked: %s\n",name); | |
} | |
else | |
{ | |
printf("Flashing BIOS from TFTP: %s,%s\n",url,write_file); | |
flash_set_filename(flash,write_file); | |
flash_emit_download(flash,url,write_file); | |
flash_set_status(flash,"Downloading"); | |
} | |
return TRUE; | |
} | |
static gboolean | |
on_error (Flash *flash, | |
GDBusMethodInvocation *invocation, | |
gchar* error_msg, | |
gpointer user_data) | |
{ | |
int rc = 0; | |
SharedResource *lock = object_get_shared_resource((Object*)user_data); | |
gboolean locked = shared_resource_get_lock(lock); | |
flash_set_status(flash, error_msg); | |
flash_complete_error(flash,invocation); | |
printf("ERROR: %s. Clearing locks\n",error_msg); | |
shared_resource_set_lock(lock,false); | |
shared_resource_set_name(lock,""); | |
return TRUE; | |
} | |
static gboolean | |
on_done (Flash *flash, | |
GDBusMethodInvocation *invocation, | |
gpointer user_data) | |
{ | |
int rc = 0; | |
SharedResource *lock = object_get_shared_resource((Object*)user_data); | |
gboolean locked = shared_resource_get_lock(lock); | |
flash_set_status(flash, "Flash Done"); | |
flash_complete_done(flash,invocation); | |
printf("Flash Done. Clearing locks\n"); | |
shared_resource_set_lock(lock,false); | |
shared_resource_set_name(lock,""); | |
return TRUE; | |
} | |
static gboolean | |
on_update (Flash *flash, | |
GDBusMethodInvocation *invocation, | |
gchar* write_file, | |
gpointer user_data) | |
{ | |
int rc = 0; | |
SharedResource *lock = object_get_shared_resource((Object*)user_data); | |
gboolean locked = shared_resource_get_lock(lock); | |
flash_set_status(flash,"Flashing"); | |
flash_complete_update(flash,invocation); | |
if (locked) | |
{ | |
const gchar* name = shared_resource_get_name(lock); | |
printf("BIOS Flash is locked: %s\n",name); | |
} | |
else | |
{ | |
printf("Flashing BIOS from: %s\n",write_file); | |
flash_set_status(flash, "Flashing"); | |
shared_resource_set_lock(lock,true); | |
shared_resource_set_name(lock,dbus_object_path); | |
flash_set_filename(flash,write_file); | |
const gchar* obj_path = g_dbus_object_get_object_path((GDBusObject*)user_data); | |
rc = update(flash,obj_path); | |
if (!rc) | |
{ | |
shared_resource_set_lock(lock,false); | |
shared_resource_set_name(lock,""); | |
} | |
} | |
return TRUE; | |
} | |
static void | |
on_flash_progress (GDBusConnection* connection, | |
const gchar* sender_name, | |
const gchar* object_path, | |
const gchar* interface_name, | |
const gchar* signal_name, | |
GVariant* parameters, | |
gpointer user_data) | |
{ | |
Flash *flash = object_get_flash((Object*)user_data); | |
SharedResource *lock = object_get_shared_resource((Object*)user_data); | |
GVariantIter *iter = g_variant_iter_new(parameters); | |
GVariant* v_filename = g_variant_iter_next_value(iter); | |
GVariant* v_progress = g_variant_iter_next_value(iter); | |
uint8_t progress = g_variant_get_byte(v_progress); | |
gchar *s; | |
s = g_strdup_printf ("Flashing: %d%%",progress); | |
flash_set_status(flash,s); | |
g_free(s); | |
} | |
static void | |
on_flash_done (GDBusConnection* connection, | |
const gchar* sender_name, | |
const gchar* object_path, | |
const gchar* interface_name, | |
const gchar* signal_name, | |
GVariant* parameters, | |
gpointer user_data) | |
{ | |
Flash *flash = object_get_flash((Object*)user_data); | |
SharedResource *lock = object_get_shared_resource((Object*)user_data); | |
printf("Flash succeeded; unlocking flash\n"); | |
shared_resource_set_lock(lock,false); | |
shared_resource_set_name(lock,""); | |
flash_set_status(flash,"Flash Done"); | |
} | |
static void | |
on_flash_error (GDBusConnection* connection, | |
const gchar* sender_name, | |
const gchar* object_path, | |
const gchar* interface_name, | |
const gchar* signal_name, | |
GVariant* parameters, | |
gpointer user_data) | |
{ | |
Flash *flash = object_get_flash((Object*)user_data); | |
SharedResource *lock = object_get_shared_resource((Object*)user_data); | |
printf("Flash Error; unlocking flash\n"); | |
shared_resource_set_lock(lock,false); | |
shared_resource_set_name(lock,""); | |
} | |
static void | |
on_download_error (GDBusConnection* connection, | |
const gchar* sender_name, | |
const gchar* object_path, | |
const gchar* interface_name, | |
const gchar* signal_name, | |
GVariant* parameters, | |
gpointer user_data) | |
{ | |
Flash *flash = object_get_flash((Object*)user_data); | |
SharedResource *lock = object_get_shared_resource((Object*)user_data); | |
printf("ERROR: FlashBios: Download error; clearing flash lock\n"); | |
shared_resource_set_lock(lock,false); | |
shared_resource_set_name(lock,""); | |
} | |
static void | |
on_bus_acquired (GDBusConnection *connection, | |
const gchar *name, | |
gpointer user_data) | |
{ | |
ObjectSkeleton *object; | |
cmdline *cmd = user_data; | |
manager = g_dbus_object_manager_server_new (dbus_object_path); | |
int i=0; | |
//TODO: don't use fixed buffer | |
char flasher_path[512]; | |
memset(flasher_path, '\0', sizeof(flasher_path)); | |
bool found = false; | |
gchar *flasher_file; | |
int c = strlen(cmd->argv[0]); | |
while(c>0) | |
{ | |
if (cmd->argv[0][c] == '/') | |
{ | |
strncpy(flasher_path,cmd->argv[0],c); | |
flasher_file = g_strdup_printf ("%s/%s",flasher_path,FLASHER_BIN); | |
break; | |
} | |
c--; | |
} | |
const char* inst[] = {"bios","bmc","bmc_ramdisk","bmc_kernel"}; | |
for (i=0;i<4;i++) | |
{ | |
gchar* s; | |
s = g_strdup_printf ("%s/%s",dbus_object_path,inst[i]); | |
object = object_skeleton_new (s); | |
g_free (s); | |
Flash* flash = flash_skeleton_new (); | |
object_skeleton_set_flash (object, flash); | |
g_object_unref (flash); | |
SharedResource* lock = shared_resource_skeleton_new (); | |
object_skeleton_set_shared_resource (object, lock); | |
g_object_unref (lock); | |
ObjectMapper* mapper = object_mapper_skeleton_new (); | |
object_skeleton_set_object_mapper (object, mapper); | |
g_object_unref (mapper); | |
shared_resource_set_lock(lock,false); | |
shared_resource_set_name(lock,""); | |
flash_set_flasher_path(flash,flasher_file); | |
flash_set_flasher_name(flash,FLASHER_BIN); | |
flash_set_flasher_instance(flash,inst[i]); | |
//g_free (s); | |
//define method callbacks here | |
g_signal_connect (lock, | |
"handle-lock", | |
G_CALLBACK (on_lock), | |
NULL); /* user_data */ | |
g_signal_connect (lock, | |
"handle-unlock", | |
G_CALLBACK (on_unlock), | |
NULL); /* user_data */ | |
g_signal_connect (lock, | |
"handle-is-locked", | |
G_CALLBACK (on_is_locked), | |
NULL); /* user_data */ | |
g_signal_connect (flash, | |
"handle-update", | |
G_CALLBACK (on_update), | |
object); /* user_data */ | |
g_signal_connect (flash, | |
"handle-error", | |
G_CALLBACK (on_error), | |
object); /* user_data */ | |
g_signal_connect (flash, | |
"handle-done", | |
G_CALLBACK (on_done), | |
object); /* user_data */ | |
g_signal_connect (flash, | |
"handle-update-via-tftp", | |
G_CALLBACK (on_update_via_tftp), | |
object); /* user_data */ | |
g_signal_connect (flash, | |
"handle-init", | |
G_CALLBACK (on_init), | |
object); /* user_data */ | |
s = g_strdup_printf ("/org/openbmc/control/%s",inst[i]); | |
g_dbus_connection_signal_subscribe(connection, | |
NULL, | |
"org.openbmc.FlashControl", | |
"Progress", | |
s, | |
NULL, | |
G_DBUS_SIGNAL_FLAGS_NONE, | |
(GDBusSignalCallback) on_flash_progress, | |
object, | |
NULL ); | |
g_free (s); | |
flash_set_filename(flash,""); | |
/* Export the object (@manager takes its own reference to @object) */ | |
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object)); | |
g_object_unref (object); | |
} | |
g_free(flasher_file); | |
/* Export all objects */ | |
g_dbus_object_manager_server_set_connection (manager, connection); | |
emit_object_added((GDBusObjectManager*)manager); | |
} | |
static void | |
on_name_acquired (GDBusConnection *connection, | |
const gchar *name, | |
gpointer user_data) | |
{ | |
// g_print ("Acquired the name %s\n", name); | |
} | |
static void | |
on_name_lost (GDBusConnection *connection, | |
const gchar *name, | |
gpointer user_data) | |
{ | |
//g_print ("Lost the name %s\n", name); | |
} | |
gint | |
main (gint argc, gchar *argv[]) | |
{ | |
GMainLoop *loop; | |
cmdline cmd; | |
cmd.argc = argc; | |
cmd.argv = argv; | |
guint id; | |
loop = g_main_loop_new (NULL, FALSE); | |
signal(SIGCHLD, catch_child); | |
id = g_bus_own_name (DBUS_TYPE, | |
dbus_name, | |
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | | |
G_BUS_NAME_OWNER_FLAGS_REPLACE, | |
on_bus_acquired, | |
on_name_acquired, | |
on_name_lost, | |
&cmd, | |
NULL); | |
g_main_loop_run (loop); | |
g_bus_unown_name (id); | |
g_main_loop_unref (loop); | |
return 0; | |
} |