| #include <stdio.h> |
| #include <stdbool.h> |
| #include <string.h> |
| #include <sys/wait.h> |
| #include <sys/types.h> |
| #include <openbmc_intf.h> |
| #include <openbmc.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 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"); |
| } |
| sleep(3); |
| rc = update(f,obj_path); |
| |
| } |
| 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) |
| { |
| SharedResource *lock = object_get_shared_resource((Object*)user_data); |
| 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); |
| 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,""); |
| const gchar* filename = flash_get_filename(flash); |
| rc = unlink(filename); |
| if(rc != 0 ) |
| { |
| printf("ERROR: Unable to delete file %s (%d)\n",filename,rc); |
| } |
| |
| 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); |
| object_get_shared_resource((Object*)user_data); |
| GVariantIter *iter = g_variant_iter_new(parameters); |
| 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_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)); |
| gchar *flasher_file = NULL; |
| 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"}; |
| for(i=0;i<1;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); |
| |
| 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_set_connection(manager, connection); |
| g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object)); |
| g_object_unref(object); |
| } |
| g_free(flasher_file); |
| } |
| |
| 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; |
| } |