From 408170be70ac39317c831706717ea0e6b7e56489 Mon Sep 17 00:00:00 2001 From: Philippe De Swert Date: Thu, 21 Apr 2011 18:43:14 +0300 Subject: [PATCH] * More robust udev (especially for N900) * Improved and faster appsync courtesy of Simo Piiroinen Signed-off-by: Philippe De Swert --- src/usb_moded-appsync-dbus-private.h | 5 +- src/usb_moded-appsync-dbus.c | 322 ++++++++++++++++++--------- src/usb_moded-appsync.c | 265 ++++++++++++---------- src/usb_moded-appsync.h | 6 +- src/usb_moded-modesetting.c | 64 ++++-- src/usb_moded-modesetting.h | 3 +- src/usb_moded-modules.c | 27 ++- src/usb_moded-udev.c | 2 +- src/usb_moded.c | 8 +- 9 files changed, 433 insertions(+), 269 deletions(-) diff --git a/src/usb_moded-appsync-dbus-private.h b/src/usb_moded-appsync-dbus-private.h index 26642fd..516b14d 100644 --- a/src/usb_moded-appsync-dbus-private.h +++ b/src/usb_moded-appsync-dbus-private.h @@ -18,6 +18,7 @@ 02110-1301 USA */ -gboolean usb_moded_app_sync_init(GList *list); -void usb_moded_appsync_cleanup(GList *list); +gboolean usb_moded_app_sync_init(void); +void usb_moded_appsync_cleanup(void); int usb_moded_dbus_app_launch(const char *launch); +gboolean usb_moded_app_sync_init_connection(void); diff --git a/src/usb_moded-appsync-dbus.c b/src/usb_moded-appsync-dbus.c index 878525b..85971f7 100644 --- a/src/usb_moded-appsync-dbus.c +++ b/src/usb_moded-appsync-dbus.c @@ -6,14 +6,14 @@ @author: Philippe De Swert This program is free software; you can redistribute it and/or - modify it under the terms of the Lesser GNU General Public License - version 2 as published by the Free Software Foundation. + modify it under the terms of the Lesser GNU General Public License + version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the Lesser GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA @@ -37,75 +37,172 @@ #include "usb_moded-appsync-dbus.h" #include "usb_moded-appsync-dbus-private.h" -static DBusConnection *dbus_connection_ses = NULL; +static DBusConnection *dbus_connection_ses = NULL; // connection +static gboolean dbus_connection_name = FALSE; // have name +static gboolean dbus_connection_disc = FALSE; // got disconnected + +static void usb_moded_app_sync_cleanup_connection(void); + +static DBusHandlerResult handle_disconnect(DBusConnection *conn, DBusMessage *msg, void *user_data); +static DBusHandlerResult msg_handler(DBusConnection *const connection, DBusMessage *const msg, gpointer const user_data); + +/** + * Handle USB_MODE_INTERFACE method calls + */ static DBusHandlerResult msg_handler(DBusConnection *const connection, DBusMessage *const msg, gpointer const user_data) { DBusHandlerResult status = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - DBusMessage *reply = 0; + int type = dbus_message_get_type(msg); const char *interface = dbus_message_get_interface(msg); const char *member = dbus_message_get_member(msg); const char *object = dbus_message_get_path(msg); - int type = dbus_message_get_type(msg); - - if(!interface || !member || !object) goto EXIT; + if(!interface || !member || !object) goto IGNORE; + + if( type == DBUS_MESSAGE_TYPE_METHOD_CALL && + !strcmp(interface, USB_MODE_INTERFACE) && + !strcmp(object, USB_MODE_OBJECT) ) - if( type == DBUS_MESSAGE_TYPE_METHOD_CALL && !strcmp(interface, USB_MODE_INTERFACE) && !strcmp(object, USB_MODE_OBJECT)) { - status = DBUS_HANDLER_RESULT_HANDLED; - - if(!strcmp(member, USB_MODE_APP_STATE)) - { - char *use = 0; - DBusError err = DBUS_ERROR_INIT; - - if(!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID)) - reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member); - else - { - - if(mark_active((GList *)user_data, use)) - goto error_reply; - else - { - if((reply = dbus_message_new_method_return(msg))) - { - dbus_message_append_args (reply, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID); - } - else -error_reply: - reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member); - } - dbus_error_free(&err); - } - } + DBusMessage *reply = 0; + + status = DBUS_HANDLER_RESULT_HANDLED; + + if(!strcmp(member, USB_MODE_APP_STATE)) + { + char *use = 0; + DBusError err = DBUS_ERROR_INIT; + + if(!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID)) + { + // could not parse method call args + reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member); + } + else if( mark_active(use) < 0 ) + { + // name could not be marked active + reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member); + } + else if((reply = dbus_message_new_method_return(msg))) + { + // generate normal reply + dbus_message_append_args (reply, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID); + } + dbus_error_free(&err); + } + else + { + /*unknown methods are handled here */ + reply = dbus_message_new_error(msg, DBUS_ERROR_UNKNOWN_METHOD, member); + } + + if( !dbus_message_get_no_reply(msg) ) + { + if( !reply ) + { + // we failed to generate reply above -> generate one + reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, member); + } + if( !reply || !dbus_connection_send(connection, reply, 0) ) + { + log_debug("Failed sending reply. Out Of Memory!\n"); + } + } + + if( reply ) dbus_message_unref(reply); } - else - { - /*unknown methods are handled here */ - reply = dbus_message_new_error(msg, DBUS_ERROR_UNKNOWN_METHOD, member); + +IGNORE: + + return status; +} + +/** + * Handle disconnect signals + */ +static DBusHandlerResult handle_disconnect(DBusConnection *conn, DBusMessage *msg, void *user_data) +{ + if( dbus_message_is_signal(msg, DBUS_INTERFACE_LOCAL, "Disconnected") ) + { + log_warning("disconnected from session bus - expecting restart/stop soon\n"); + dbus_connection_disc = TRUE; + usb_moded_app_sync_cleanup_connection(); } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} - if( !reply ) +/** + * Detach from session bus + */ +static void usb_moded_app_sync_cleanup_connection(void) +{ + if( dbus_connection_ses != 0 ) { - reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, member); + /* Remove message filters */ + dbus_connection_remove_filter(dbus_connection_ses, msg_handler, 0); + dbus_connection_remove_filter(dbus_connection_ses, handle_disconnect, 0); + + /* Release name, if we can still talk to dbus daemon */ + if( !dbus_connection_disc ) + { + DBusError error = DBUS_ERROR_INIT; + dbus_bus_release_name(dbus_connection_ses, USB_MODE_SERVICE, &error); + dbus_error_free(&error); + } + + dbus_connection_unref(dbus_connection_ses); + dbus_connection_ses = NULL; + //dbus_connection_disc = FALSE; } + log_debug("succesfully cleaned up appsync dbus\n"); +} +/** + * Attach to session bus + */ +gboolean usb_moded_app_sync_init_connection(void) +{ + gboolean result = FALSE; + DBusError error = DBUS_ERROR_INIT; -EXIT: + if( dbus_connection_ses != 0 ) + { + result = TRUE; + goto EXIT; + } - if(reply) + if( dbus_connection_disc ) { - if( !dbus_message_get_no_reply(msg) ) - { - if( !dbus_connection_send(connection, reply, 0) ) - log_debug("Failed sending reply. Out Of Memory!\n"); - } - dbus_message_unref(reply); + // we've already observed death of session + goto EXIT; } - return status; + /* Connect to session bus */ + if ((dbus_connection_ses = dbus_bus_get(DBUS_BUS_SESSION, &error)) == NULL) + { + log_err("Failed to open connection to session message bus; %s\n", error.message); + goto EXIT; + } + + /* Add disconnect handler */ + dbus_connection_add_filter(dbus_connection_ses, handle_disconnect, 0, 0); + + /* Add method call handler */ + dbus_connection_add_filter(dbus_connection_ses, msg_handler, 0, 0); + + /* Make sure we do not get forced to exit if dbus session dies or stops */ + dbus_connection_set_exit_on_disconnect(dbus_connection_ses, FALSE); + + /* Connect D-Bus to the mainloop */ + dbus_connection_setup_with_g_main(dbus_connection_ses, NULL); + + /* everything went fine */ + result = TRUE; + +EXIT: + dbus_error_free(&error); + return result; } /** @@ -113,71 +210,84 @@ static DBusHandlerResult msg_handler(DBusConnection *const connection, DBusMessa * * @return TRUE when everything went ok */ -gboolean usb_moded_app_sync_init(GList *list) +gboolean usb_moded_app_sync_init(void) { gboolean status = FALSE; - DBusError error; + DBusError error = DBUS_ERROR_INIT; int ret; - dbus_error_init(&error); - - /* connect to session bus */ - if ((dbus_connection_ses = dbus_bus_get_private(DBUS_BUS_SESSION, &error)) == NULL) + if( !usb_moded_app_sync_init_connection() ) { - log_err("Failed to open connection to session message bus; %s\n", error.message); - goto EXIT; + goto EXIT; } - /* make sure we do not get forced to exit if dbus session dies or stops */ - dbus_connection_set_exit_on_disconnect(dbus_connection_ses, FALSE); + /* Acquire D-Bus service name */ + ret = dbus_bus_request_name(dbus_connection_ses, USB_MODE_SERVICE, DBUS_NAME_FLAG_DO_NOT_QUEUE , &error); - /* Initialise message handlers */ - if (!dbus_connection_add_filter(dbus_connection_ses, msg_handler, list, NULL)) - { - log_err("failed to add filter\n"); - goto EXIT; - } - /* Acquire D-Bus service */ - ret = dbus_bus_request_name(dbus_connection_ses, USB_MODE_SERVICE, DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_ALLOW_REPLACEMENT , &error); - if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + switch( ret ) { - log_err("failed claiming dbus name\n"); - if( dbus_error_is_set(&error) ) - log_debug("DBUS ERROR: %s, %s \n", error.name, error.message); - goto EXIT; + case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: + // expected result + break; + + case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: + // functionally ok, but we do have a logic error somewhere + log_warning("already owning '%s'", USB_MODE_SERVICE); + break; + + default: + // something odd + log_err("failed claiming dbus name\n"); + if( dbus_error_is_set(&error) ) + log_debug("DBUS ERROR: %s, %s \n", error.name, error.message); + goto EXIT; } - /* Connect D-Bus to the mainloop */ - dbus_connection_setup_with_g_main(dbus_connection_ses, NULL); + dbus_connection_name = TRUE; /* everything went fine */ status = TRUE; -EXIT: +EXIT: dbus_error_free(&error); return status; } /** - * Clean up the dbus connections for the application + * Clean up the dbus connections for the application * synchronisation after sync is done */ -void usb_moded_appsync_cleanup(GList *list) +void usb_moded_appsync_cleanup(void) { - DBusError error; - - dbus_error_init(&error); - /* clean up system bus connection */ - if (dbus_connection_ses != NULL) + /* Drop the service name - if we have it */ + if (dbus_connection_ses != NULL ) { - dbus_bus_release_name(dbus_connection_ses, USB_MODE_SERVICE, &error); - dbus_connection_remove_filter(dbus_connection_ses, msg_handler, list); - dbus_connection_close(dbus_connection_ses); - dbus_connection_unref(dbus_connection_ses); - dbus_connection_ses = NULL; - log_debug("succesfully cleaned up appsync dbus\n"); + if( dbus_connection_name ) + { + DBusError error = DBUS_ERROR_INIT; + int ret = dbus_bus_release_name(dbus_connection_ses, USB_MODE_SERVICE, &error); + + switch( ret ) + { + case DBUS_RELEASE_NAME_REPLY_RELEASED: + // as expected + break; + case DBUS_RELEASE_NAME_REPLY_NON_EXISTENT: + // weird, but since nobody owns the name ... + break; + case DBUS_RELEASE_NAME_REPLY_NOT_OWNER: + log_warning("somebody else owns '%s'", USB_MODE_SERVICE); + } + + dbus_connection_name = FALSE; + + if( dbus_error_is_set(&error) ) + { + log_debug("DBUS ERROR: %s, %s \n", error.name, error.message); + dbus_error_free(&error); + } + } } - dbus_error_free(&error); } /** @@ -185,20 +295,24 @@ void usb_moded_appsync_cleanup(GList *list) */ int usb_moded_dbus_app_launch(const char *launch) { - DBusConnection *dbus_conn = NULL; - DBusError error; - int ret = 0; + int ret = -1; // assume failure - dbus_error_init(&error); - - if( (dbus_conn = dbus_bus_get(DBUS_BUS_SESSION, &error)) == 0 ) + if( dbus_connection_ses == 0 ) { - log_err("Could not connect to dbus session\n"); + log_err("could not start '%s': no session bus connection", launch); } - - dbus_bus_start_service_by_name(dbus_conn, launch, 0, NULL, &error); - - dbus_connection_unref(dbus_conn); - - return(ret); + else + { + DBusError error = DBUS_ERROR_INIT; + if( !dbus_bus_start_service_by_name(dbus_connection_ses, launch, 0, NULL, &error) ) + { + log_err("could not start '%s': %s: %s", launch, error.name, error.message); + dbus_error_free(&error); + } + else + { + ret = 0; // success + } + } + return ret; } diff --git a/src/usb_moded-appsync.c b/src/usb_moded-appsync.c index e1858bf..dbc2471 100644 --- a/src/usb_moded-appsync.c +++ b/src/usb_moded-appsync.c @@ -1,29 +1,33 @@ /** @file usb_moded-appsync.c - + Copyright (C) 2010 Nokia Corporation. All rights reserved. @author: Philippe De Swert This program is free software; you can redistribute it and/or - modify it under the terms of the Lesser GNU General Public License - version 2 as published by the Free Software Foundation. + modify it under the terms of the Lesser GNU General Public License + version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the Lesser GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#define _GNU_SOURCE + #include #include #include #include +#include +#include #include #include @@ -31,176 +35,191 @@ #include "usb_moded-appsync.h" #include "usb_moded-appsync-dbus.h" #include "usb_moded-appsync-dbus-private.h" +#include "usb_moded-modesetting.h" #include "usb_moded-log.h" static struct list_elem *read_file(const gchar *filename); -GList *readlist(void) +static GList *sync_list = NULL; + +static void free_elem(gpointer aptr) { - GDir *confdir; - GList *applist = NULL; - const gchar *dirname; - struct list_elem *list_item; + struct list_elem *elem = aptr; + free(elem->name); + free(elem->launch); + free(elem); +} - confdir = g_dir_open(CONF_DIR_PATH, 0, NULL); - if(confdir) +static void free_list(void) +{ + if( sync_list != 0 ) { - while((dirname = g_dir_read_name(confdir)) != NULL) - { - log_debug("Read file %s\n", dirname); - list_item = read_file(dirname); - if(list_item) - applist = g_list_append(applist, list_item); - } - g_dir_close(confdir); + g_list_free_full(sync_list, free_elem); + sync_list = 0; } - else - log_debug("confdir open failed.\n"); - return(applist); } -static struct list_elem *read_file(const gchar *filename) +void readlist(void) { - GKeyFile *settingsfile; - gboolean test = FALSE; - gchar **keys; - struct list_elem *list_item = NULL; - gchar *full_filename = NULL; + GDir *confdir = 0; + + const gchar *dirname; + struct list_elem *list_item; + + free_list(); - full_filename = g_strconcat(CONF_DIR_PATH, "/", filename, NULL); + if( !(confdir = g_dir_open(CONF_DIR_PATH, 0, NULL)) ) + goto cleanup; - settingsfile = g_key_file_new(); - test = g_key_file_load_from_file(settingsfile, full_filename, G_KEY_FILE_NONE, NULL); - /* free full_filename immediately as we do not use it anymore */ - free(full_filename); - if(!test) + while( (dirname = g_dir_read_name(confdir)) ) { - return(NULL); + log_debug("Read file %s\n", dirname); + if( (list_item = read_file(dirname)) ) + sync_list = g_list_append(sync_list, list_item); } - list_item = malloc(sizeof(struct list_elem)); - keys = g_key_file_get_keys (settingsfile, APP_INFO_ENTRY , NULL, NULL); - while (*keys != NULL) + +cleanup: + if( confdir ) g_dir_close(confdir); + + /* set up session bus connection if app sync in use + * so we do not need to make the time consuming connect + * operation at enumeration time ... */ + + if( sync_list ) { - if(!strcmp(*keys, APP_INFO_NAME_KEY)) - { - list_item->name = g_key_file_get_string(settingsfile, APP_INFO_ENTRY, *keys, NULL); - log_debug("Appname = %s\n", list_item->name); - } - else if(!strcmp(*keys, APP_INFO_LAUNCH_KEY)) - { - list_item->launch = g_key_file_get_string(settingsfile, APP_INFO_ENTRY, *keys, NULL); - log_debug("launch path = %s\n", list_item->launch); - } - keys++; + usb_moded_app_sync_init_connection(); } - g_strfreev(keys); - g_key_file_free(settingsfile); - if(list_item->launch == NULL || list_item->name == NULL) +} + +static struct list_elem *read_file(const gchar *filename) +{ + gchar *full_filename = NULL; + GKeyFile *settingsfile = NULL; + struct list_elem *list_item = NULL; + + if( !(full_filename = g_strconcat(CONF_DIR_PATH, "/", filename, NULL)) ) + goto cleanup; + + if( !(settingsfile = g_key_file_new()) ) + goto cleanup; + + if( !g_key_file_load_from_file(settingsfile, full_filename, G_KEY_FILE_NONE, NULL) ) + goto cleanup; + + if( !(list_item = calloc(1, sizeof *list_item)) ) + goto cleanup; + + list_item->name = g_key_file_get_string(settingsfile, APP_INFO_ENTRY, APP_INFO_NAME_KEY, NULL); + log_debug("Appname = %s\n", list_item->name); + list_item->launch = g_key_file_get_string(settingsfile, APP_INFO_ENTRY, APP_INFO_LAUNCH_KEY, NULL); + log_debug("Launch = %s\n", list_item->name); + +cleanup: + + if(settingsfile) + g_key_file_free(settingsfile); + g_free(full_filename); + + /* if not all the elements are filled in we discard the list_item */ + if( list_item && !(list_item->launch && list_item->name) ) { - /* free list_item as it will not be used */ - free(list_item); - return NULL; + free_elem(list_item), list_item = 0; } - else - return(list_item); + + return list_item; } -int activate_sync(GList *list) +int activate_sync(void) { - GList *list_iter; + GList *iter; - list_iter = list; - /* set list to inactive */ - do - { - struct list_elem *data = list_iter->data; - data->active = 0; - list_iter = g_list_next(list_iter); - } - while(list_iter != NULL); + if( sync_list == 0 ) + { + enumerate_usb(NULL); + return 0; + } + + /* set list to inactive */ + for( iter = sync_list; iter; iter = g_list_next(iter) ) + { + struct list_elem *data = iter->data; + data->active = 0; + } /* add dbus filter. Use session bus for ready method call? */ - if(!usb_moded_app_sync_init(list)) - { + if(!usb_moded_app_sync_init()) + { log_debug("dbus setup failed => activate immediately \n"); enumerate_usb(NULL); return(1); } /* go through list and launch apps */ - list_iter = list; - do - { - struct list_elem *data = list_iter->data; - log_debug("launching app %s\n", data->launch); - usb_moded_dbus_app_launch(data->launch); - list_iter = g_list_next(list_iter); - } - while(list_iter != NULL); + for( iter = sync_list; iter; iter = g_list_next(iter) ) + { + struct list_elem *data = iter->data; + log_debug("launching app %s\n", data->launch); + usb_moded_dbus_app_launch(data->launch); + } /* start timer */ log_debug("Starting timer\n"); - g_timeout_add_seconds(2, enumerate_usb, list); + g_timeout_add_seconds(2, enumerate_usb, NULL); return(0); } -int mark_active(GList *list, const gchar *name) +int mark_active(const gchar *name) { - int ret = 0; - static int list_length=0; - int counter=0; - GList *list_iter; + int ret = -1; // assume name not found + int missing = 0; + + GList *iter; log_debug("app %s notified it is ready\n", name); - if(list_length == 0) - list_length = g_list_length(list); - - list_iter = list; - do + + for( iter = sync_list; iter; iter = g_list_next(iter) ) + { + struct list_elem *data = iter->data; + if(!strcmp(data->name, name)) { - struct list_elem *data = list_iter->data; - if(!strcmp(data->name, name)) - { - if(!data->active) - { - data->active = 1; - counter++; - - if(list_length == counter) - { - counter = 0; - log_debug("All apps active. Let's enumerate\n"); - enumerate_usb(list); - } - ret = 0; - break; - } - else - { - ret = 1; - } - } - list_iter = g_list_next(list_iter); + /* TODO: do we need to worry about duplicate names in the list? */ + ret = !data->active; + data->active = 1; + + /* updated + missing -> not going to enumerate */ + if( missing ) break; } - while(list_iter != NULL); + else if( data->active == 0 ) + { + missing = 1; - return(ret); + /* updated + missing -> not going to enumerate */ + if( ret != -1 ) break; + } + } + if( !missing ) + { + log_debug("All apps active. Let's enumerate\n"); + enumerate_usb(NULL); + } + + /* -1=not found, 0=already active, 1=activated now */ + return ret; } gboolean enumerate_usb(gpointer data) { - + /* We arrive here twice: when app sync is done + * and when the app sync timeout gets triggered */ + /* activate usb connection/enumeration */ - system("echo 1 > /sys/devices/platform/musb_hdrc/gadget/softconnect"); + write_to_file("/sys/devices/platform/musb_hdrc/gadget/softconnect", "1"); log_debug("Softconnect enumeration done\n"); - /* no need to remove timer */ - - /* remove dbus filter */ - if(data != NULL) - usb_moded_appsync_cleanup((GList *)data); + /* remove dbus service */ + usb_moded_appsync_cleanup(); /* return false to stop the timer from repeating */ - return(FALSE); + return FALSE; } diff --git a/src/usb_moded-appsync.h b/src/usb_moded-appsync.h index 230d164..ea08829 100644 --- a/src/usb_moded-appsync.h +++ b/src/usb_moded-appsync.h @@ -32,7 +32,7 @@ typedef struct list_elem int active; }list_elem; -GList *readlist(void); -int activate_sync(GList *list); -int mark_active(GList *list, const gchar *name); +void readlist(void); +int activate_sync(void); +int mark_active(const gchar *name); gboolean enumerate_usb(gpointer data); diff --git a/src/usb_moded-modesetting.c b/src/usb_moded-modesetting.c index 39f389b..92590f9 100644 --- a/src/usb_moded-modesetting.c +++ b/src/usb_moded-modesetting.c @@ -20,6 +20,7 @@ 02110-1301 USA */ +#define _GNU_SOURCE #include #include #include @@ -57,6 +58,43 @@ int find_number_of_mounts(void) } #endif /* MAYBE_NEEDED */ +int write_to_file(const char *path, const char *text) +{ + int err = -1; + int fd = -1; + size_t todo = strlen(text); + + /* no O_CREAT -> writes only to already existing files */ + if( (fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY))) == -1 ) + { + /* gcc -pedantic does not like "%m" + log_warning("open(%s): %m", path); */ + log_warning("open(%s): %s", path, strerror(errno)); + goto cleanup; + } + + while( todo > 0 ) + { + ssize_t n = TEMP_FAILURE_RETRY(write(fd, text, todo)); + if( n < 0 ) + { + log_warning("write(%s): %s", path, strerror(errno)); + goto cleanup; + } + todo -= n; + text += n; + } + + err = 0; + +cleanup: + + if( fd != -1 ) TEMP_FAILURE_RETRY(close(fd)); + + return err; +} + + int set_mass_storage_mode(void) { gchar *command; @@ -137,11 +175,11 @@ umount: command = g_strconcat("mount | grep ", mounts[i], NULL); sprintf(command2, "echo %i > /sys/devices/platform/musb_hdrc/gadget/gadget-lun%d/nofua", fua, i); log_debug("usb lun = %s active\n", command2); system(command2); - sprintf(command2, "echo %s > /sys/devices/platform/musb_hdrc/gadget/gadget-lun%d/file", mounts[i], i); + sprintf(command2, "/sys/devices/platform/musb_hdrc/gadget/gadget-lun%d/file", i); log_debug("usb lun = %s active\n", command2); - system(command2); - } - g_strfreev(mounts); + write_to_file(command2, mounts[i]); + } + g_strfreev(mounts); } /* only send data in use signal in case we actually succeed */ @@ -153,7 +191,7 @@ umount: command = g_strconcat("mount | grep ", mounts[i], NULL); } #ifdef N900 -int set_ovi_suite_mode(GList *applist) +int set_ovi_suite_mode(void) { #ifdef NOKIA int timeout = 1; @@ -161,13 +199,10 @@ int set_ovi_suite_mode(GList *applist) #ifdef APP_SYNC - /* do not go through the appsync routine if there is no applist */ - if(applist) - activate_sync(applist); - else - enumerate_usb(NULL); + activate_sync(); #else - system("echo 1 > /sys/devices/platform/musb_hdrc/gadget/softconnect"); + //system("echo 1 > /sys/devices/platform/musb_hdrc/gadget/softconnect"); + write_to_file("/sys/devices/platform/musb_hdrc/gadget/softconnect", "1"); #endif /* APP_SYNC */ /* bring network interface up in case no other network is up */ system("ifdown usb0 ; ifup usb0"); @@ -186,7 +221,7 @@ int set_ovi_suite_mode(GList *applist) #ifdef NOKIA gboolean export_cdrom(gpointer data) { - const char *path = NULL, *command = NULL; + const char *path = NULL; path = find_cdrom_path(); @@ -196,8 +231,7 @@ gboolean export_cdrom(gpointer data) } if(access(path, F_OK) == 0) { - command = g_strconcat("echo ", path, " > /sys/devices/platform/musb_hdrc/gadget/gadget-lun0/file", NULL); - system(command); + write_to_file("/sys/devices/platform/musb_hdrc/gadget/gadget-lun0/file", path); } else log_debug("Cdrom image file does not exist => no export.\n"); @@ -277,7 +311,7 @@ int usb_moded_mode_cleanup(const char *module) /* bring network down immediately */ system("ifdown usb0"); /* do soft disconnect */ - system("echo 0 > /sys/devices/platform/musb_hdrc/gadget/softconnect"); + write_to_file("/sys/devices/platform/musb_hdrc/gadget/softconnect", "0"); /* DIRTY WORKAROUND: acm/phonet does not work as it should, remove when it does */ system("killall -SIGTERM acm"); } diff --git a/src/usb_moded-modesetting.h b/src/usb_moded-modesetting.h index 6295e97..9fb3cbc 100644 --- a/src/usb_moded-modesetting.h +++ b/src/usb_moded-modesetting.h @@ -23,8 +23,9 @@ #ifdef MAYBE_NEEDED int find_number_of_mounts(void); #endif +int write_to_file(const char *path, const char *text); int set_mass_storage_mode(void); -int set_ovi_suite_mode(GList *applist); +int set_ovi_suite_mode(void); int usb_moded_mode_cleanup(const char *module); #ifdef NOKIA gboolean export_cdrom (gpointer data); diff --git a/src/usb_moded-modules.c b/src/usb_moded-modules.c index a5fe765..be13564 100644 --- a/src/usb_moded-modules.c +++ b/src/usb_moded-modules.c @@ -118,8 +118,8 @@ const char * usb_moded_find_module(void) */ int usb_moded_module_cleanup(const char *module) { - int retry = 0, success; - + int retry = 0, failure; + if(!strcmp(module, MODULE_NONE)) goto END; /* wait a bit for all components listening on dbus to clean up their act @@ -129,22 +129,21 @@ int usb_moded_module_cleanup(const char *module) return(0); */ - success = usb_moded_unload_module(module); - // SP: variable 'success' holds error value? - while(success) + failure = usb_moded_unload_module(module); + while(failure) { + // SP: up to 2 second sleep -> worth a warning log? /* module did not get unloaded. We will wait a bit and try again */ sleep(1); - success = usb_moded_unload_module(module); - log_debug("unloading success = %d\n", success); - if(!success) + failure = usb_moded_unload_module(module); + log_debug("unloading failure = %d\n", failure); + if(!failure) break; if(!usb_moded_find_module()) goto END; retry++; if(retry == 2) break; - // SP: up to 2 second sleep -> worth a warning log? } if(!strcmp(module, MODULE_NETWORK)) { @@ -167,8 +166,8 @@ int usb_moded_module_cleanup(const char *module) // SP: system("kill -s SIGTERM $(lsof -t /dev/ttyGS* /dev/gc* /dev/mtp*") ? // SP: or popen + kill loop? /* try to unload again and give up if it did not work yet */ - success = usb_moded_unload_module(module); - if(success && retry < 10) + failure = usb_moded_unload_module(module); + if(failure && retry < 10) { retry++; // SP: NOTE: we have a root process in busyloop sending kill signals to @@ -176,7 +175,7 @@ int usb_moded_module_cleanup(const char *module) goto kill; // SP: IMHO backwards goto is bad - a loop perhaps? } - if(success && retry == 10) + if(failure && retry == 10) { system("for i in `lsof -t /dev/ttyGS*`; do kill -9 $i ; done"); system("for i in `lsof -t /dev/gc*`; do kill -9 $i ; done"); @@ -184,12 +183,12 @@ int usb_moded_module_cleanup(const char *module) /* try again since there seem to be hard to kill processes there */ system("killall -9 obexd"); system("killall -9 msycnd"); - success = usb_moded_unload_module(module); + failure = usb_moded_unload_module(module); } } } - if(!success) + if(!failure) log_info("Module %s unloaded successfully\n", module); else { diff --git a/src/usb_moded-udev.c b/src/usb_moded-udev.c index 93adb0c..6e34130 100644 --- a/src/usb_moded-udev.c +++ b/src/usb_moded-udev.c @@ -54,7 +54,7 @@ gboolean hwal_init(void) else { dev_name = udev_device_get_sysname(dev); - udev_device_unref(dev); + log_debug("device name = %s\n", dev_name); } mon = udev_monitor_new_from_netlink (udev, "udev"); if (!mon) diff --git a/src/usb_moded.c b/src/usb_moded.c index a282f6b..009f768 100644 --- a/src/usb_moded.c +++ b/src/usb_moded.c @@ -57,10 +57,6 @@ gboolean special_mode = FALSE; guint timeout_source = 0; #endif /* NOKIA */ -/*#ifdef APP_SYNC */ -GList *applist = NULL; -/*#endif APP_SYNC */ - /* static helper functions */ static void usb_moded_init(void); static gboolean charging_fallback(gpointer data); @@ -214,7 +210,7 @@ void set_usb_mode(const char *mode) set_usb_module(MODULE_NETWORK); ret = usb_moded_load_module(MODULE_NETWORK_MTP); if(!ret) - ret = set_ovi_suite_mode(applist); + ret = set_ovi_suite_mode(); } #endif /* N900 */ @@ -309,7 +305,7 @@ static void usb_moded_init(void) #endif /* NOKIA */ #ifdef APP_SYNC - applist = readlist(); + readlist(); #endif /* APP_SYNC */ /* TODO: add more start-up clean-up and init here if needed */