Commit ac296c87 authored by phdeswer's avatar phdeswer

dynamic config added

Signed-off-by: phdeswer's avatarPhilippe De Swert <philippedeswert@gmail.com>
parent 408170be
AC_INIT([usb_moded], [0.36])
AC_INIT([usb_moded], [0.38])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AM_CONFIG_HEADER([config.h])
......@@ -95,7 +95,7 @@ AM_CONDITIONAL([UDEV], [test x$udev = xtrue])
PKG_CHECK_MODULES([USB_MODED], [
glib-2.0 >= 2.2.0
glib-2.0 >= 2.28.0
dbus-1 >= 1.2.1
dbus-glib-1 >= 0.78
gobject-2.0 >= 2.16.6
......
usb-moded (0.38) unstable; urgency=low
* Fix lintian warning
* Fix doxygen warnings and improve documentation
* Add dynamic mode support
* Add debug printing for finding who keeps the mass-storage device busy
-- Philippe De Swert <philippe.de-swert@nokia.com> Tue, 03 May 2011 14:57:38 +0300
usb-moded (0.37) unstable; urgency=low
* Aegis introspection fix patch by Alexander Schertz. Fixes: NB#248291
* Fix sysfs path for cdrom export.
-- Philippe De Swert <philippe.de-swert@nokia.com> Thu, 21 Apr 2011 18:38:11 +0300
usb-moded (0.36) unstable; urgency=low
* Do not check for default gateway anymore. Network config
has been fixed. Fixes: NB#246401
* Echo "" to the lun to disable mass-storage exports instead of 0
* Improved appsync by Simo Piiroinen
* More robust udev
-- Philippe De Swert <philippe.de-swert@nokia.com> Tue, 19 Apr 2011 15:04:43 +0300
-- Philippe De Swert <philippe.de-swert@nokia.com> Thu, 21 Apr 2011 18:38:11 +0300
usb-moded (0.35) unstable; urgency=low
......
......@@ -3,7 +3,7 @@ Section: misc
Priority: optional
Maintainer: Philippe De Swert <philippe.de-swert@nokia.com>
Build-Depends: debhelper (>= 5), autoconf, automake, libdbus-1-dev, libdbus-glib-1-dev, libglib2.0-dev, libgconf2-dev, doxygen, aegis-builder, libudev-dev
Standards-Version: 3.8.0
Standards-Version: 3.9.1
Package: usb-moded
Architecture: any
......
......@@ -20,6 +20,9 @@
<annotation name="com.maemo.Aegis" value="USBControl"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
<annotation name="com.maemo.Aegis" value=""/>
</interface>
</node>
</dbus>
</provide>
......
......@@ -27,7 +27,7 @@ usb_moded_SOURCES = \
usb_moded-config.c \
usb_moded-config.h \
usb_moded-modesetting.c \
usb_moded-modesetting.h
usb_moded-modesetting.h
if HAL
usb_moded_SOURCES += \
usb_moded-hal.c
......@@ -55,6 +55,8 @@ usb_moded_SOURCES += \
usb_moded-appsync.h \
usb_moded-appsync-dbus.c \
usb_moded-appsync-dbus.h \
usb_moded-appsync-dbus-private.h
usb_moded-appsync-dbus-private.h \
usb_moded-dyn-config.c \
usb_moded-dyn-config.h
endif
......@@ -46,6 +46,88 @@ 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);
static void usb_moded_app_sync_release_name(void)
{
/* Drop the service name - if we have it */
if( dbus_connection_ses && 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
log_debug("released name: %s", USB_MODE_SERVICE);
break;
case DBUS_RELEASE_NAME_REPLY_NON_EXISTENT:
// weird, but since nobody owns the name ...
log_debug("nonexisting name: %s", USB_MODE_SERVICE);
break;
case DBUS_RELEASE_NAME_REPLY_NOT_OWNER:
log_warning("somebody else owns: %s", USB_MODE_SERVICE);
}
if( dbus_error_is_set(&error) )
{
log_debug("DBUS ERROR: %s, %s \n", error.name, error.message);
dbus_error_free(&error);
}
}
dbus_connection_name = FALSE;
}
static gboolean usb_moded_app_sync_obtain_name(void)
{
DBusError error = DBUS_ERROR_INIT;
int ret;
if( dbus_connection_name )
{
goto EXIT;
}
if( dbus_connection_ses == 0 )
{
goto EXIT;
}
/* Acquire D-Bus service name */
ret = dbus_bus_request_name(dbus_connection_ses, USB_MODE_SERVICE, DBUS_NAME_FLAG_DO_NOT_QUEUE , &error);
switch( ret )
{
case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
// expected result
log_debug("primary owner of: %s", USB_MODE_SERVICE);
break;
case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
// functionally ok, but we do have a logic error somewhere
log_warning("already owner of: %s", USB_MODE_SERVICE);
break;
default:
// something odd
log_err("failed to claim: %s", USB_MODE_SERVICE);
goto EXIT;
}
dbus_connection_name = TRUE;
EXIT:
if( dbus_error_is_set(&error) )
{
log_debug("DBUS ERROR: %s, %s \n", error.name, error.message);
dbus_error_free(&error);
}
return dbus_connection_name;
}
/**
* Handle USB_MODE_INTERFACE method calls
*/
......@@ -143,12 +225,10 @@ static void usb_moded_app_sync_cleanup_connection(void)
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 */
/* Release name, but only 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);
usb_moded_app_sync_release_name();
}
dbus_connection_unref(dbus_connection_ses);
......@@ -197,6 +277,12 @@ gboolean usb_moded_app_sync_init_connection(void)
/* Connect D-Bus to the mainloop */
dbus_connection_setup_with_g_main(dbus_connection_ses, NULL);
/* Request service name */
if( !usb_moded_app_sync_obtain_name() )
{
goto EXIT;
}
/* everything went fine */
result = TRUE;
......@@ -213,43 +299,16 @@ EXIT:
gboolean usb_moded_app_sync_init(void)
{
gboolean status = FALSE;
DBusError error = DBUS_ERROR_INIT;
int ret;
if( !usb_moded_app_sync_init_connection() )
{
goto EXIT;
}
/* Acquire D-Bus service name */
ret = dbus_bus_request_name(dbus_connection_ses, USB_MODE_SERVICE, DBUS_NAME_FLAG_DO_NOT_QUEUE , &error);
switch( ret )
{
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;
}
dbus_connection_name = TRUE;
/* everything went fine */
status = TRUE;
EXIT:
dbus_error_free(&error);
return status;
}
......@@ -259,36 +318,106 @@ EXIT:
*/
void usb_moded_appsync_cleanup(void)
{
/* Drop the service name - if we have it */
if (dbus_connection_ses != NULL )
// NOP
}
#if 0
static void startservicebyname_cb(DBusPendingCall *pc, void *data)
{
const char *name = data;
DBusMessage *rsp = dbus_pending_call_steal_reply(pc);
int res = -1;
DBusError err = DBUS_ERROR_INIT;
const char *tag = "FAILED";
if( rsp != 0 )
{
if( dbus_connection_name )
dbus_uint32_t dta = 0;
if( dbus_message_get_args(rsp, &err,
DBUS_TYPE_UINT32, &dta,
DBUS_TYPE_INVALID) )
{
DBusError error = DBUS_ERROR_INIT;
int ret = dbus_bus_release_name(dbus_connection_ses, USB_MODE_SERVICE, &error);
res = (int)dta;
}
dbus_message_unref(rsp);
}
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);
}
if( dbus_error_is_set(&err) )
{
log_err("ERR: %s: %s @ %s()\n", err.name, err.message, __FUNCTION__);
dbus_error_free(&err);
}
dbus_connection_name = FALSE;
switch( res )
{
case DBUS_START_REPLY_SUCCESS: tag = "STARTED"; break;
case DBUS_START_REPLY_ALREADY_RUNNING: tag = "RUNNING"; break;
}
if( dbus_error_is_set(&error) )
{
log_debug("DBUS ERROR: %s, %s \n", error.name, error.message);
dbus_error_free(&error);
}
}
log_debug("%s: app=%s, res=%s (%d)", __FUNCTION__, name, tag, res);
}
static gboolean startservicebyname(const char *name)
{
gboolean res = FALSE;
dbus_uint32_t flg = 0;
DBusMessage *req = 0;
DBusPendingCall *pc = 0;
if( !dbus_connection_ses )
{
log_warning("%s: %s", __FUNCTION__, "no session bus connection");
goto cleanup;
}
if( !(req = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS,
"StartServiceByName")) )
{
log_warning("%s: %s", __FUNCTION__, "method call alloc failed");
goto cleanup;
}
if( !dbus_message_append_args(req,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_UINT32, &flg,
DBUS_TYPE_INVALID) )
{
log_warning("%s: %s", __FUNCTION__, "method call add args failed");
goto cleanup;
}
if( !dbus_connection_send_with_reply(dbus_connection_ses, req, &pc, -1) )
{
log_warning("%s: %s", __FUNCTION__, "send with reply failed");
goto cleanup;
}
if( pc == 0 )
{
log_warning("%s: %s", __FUNCTION__, "no pending call handle");
goto cleanup;
}
if( !dbus_pending_call_set_notify(pc, startservicebyname_cb,
strdup(name), free) )
{
log_warning("%s: %s", __FUNCTION__, "pending call notify failed");
goto cleanup;
}
/* we have succesfully started the asynchronous request */
res = TRUE;
cleanup:
if( pc ) dbus_pending_call_unref(pc);
if( req ) dbus_message_unref(req);
return res;
}
#endif
/**
* Launch applications over dbus that need to be synchronized
......@@ -303,6 +432,13 @@ int usb_moded_dbus_app_launch(const char *launch)
}
else
{
#if 0
if( startservicebyname(launch) )
{
// started request, actual results from startservicebyname_cb()
ret = 0;
}
#else
DBusError error = DBUS_ERROR_INIT;
if( !dbus_bus_start_service_by_name(dbus_connection_ses, launch, 0, NULL, &error) )
{
......@@ -313,6 +449,8 @@ int usb_moded_dbus_app_launch(const char *launch)
{
ret = 0; // success
}
#endif
}
return ret;
}
......@@ -28,6 +28,7 @@
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <glib.h>
#include <glib/gstdio.h>
......@@ -39,9 +40,14 @@
#include "usb_moded-log.h"
static struct list_elem *read_file(const gchar *filename);
static gboolean enumerate_usb(gpointer data);
static GList *sync_list = NULL;
static unsigned sync_tag = 0;
static unsigned enum_tag = 0;
static struct timeval sync_tv;
static void free_elem(gpointer aptr)
{
struct list_elem *elem = aptr;
......@@ -112,7 +118,9 @@ static struct list_elem *read_file(const gchar *filename)
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);
log_debug("Launch = %s\n", list_item->launch);
list_item->mode = g_key_file_get_string(settingsfile, APP_INFO_ENTRY, APP_INFO_MODE_KEY, NULL);
log_debug("Launch mode = %s\n", list_item->mode);
cleanup:
......@@ -121,7 +129,7 @@ cleanup:
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) )
if( list_item && !(list_item->launch && list_item->name && list_item->mode) )
{
free_elem(list_item), list_item = 0;
}
......@@ -129,21 +137,29 @@ cleanup:
return list_item;
}
int activate_sync(void)
int activate_sync(const char *mode)
{
GList *iter;
log_debug("activate sync");
/* Bump tag, see enumerate_usb() */
++sync_tag; gettimeofday(&sync_tv, 0);
if( sync_list == 0 )
{
enumerate_usb(NULL);
return 0;
}
/* set list to inactive */
/* set list to inactive, mark other modes as active already */
for( iter = sync_list; iter; iter = g_list_next(iter) )
{
struct list_elem *data = iter->data;
data->active = 0;
if(!strcmp(data->mode, mode))
data->active = 0;
else
data->active = 1;
}
/* add dbus filter. Use session bus for ready method call? */
......@@ -154,18 +170,21 @@ int activate_sync(void)
return(1);
}
/* start timer */
log_debug("Starting timer\n");
g_timeout_add_seconds(2, enumerate_usb, NULL);
/* go through list and launch apps */
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);
if(!strcmp(mode, data->mode))
{
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, NULL);
return(0);
}
......@@ -176,7 +195,7 @@ int mark_active(const gchar *name)
GList *iter;
log_debug("app %s notified it is ready\n", name);
log_debug("App %s notified it is ready\n", name);
for( iter = sync_list; iter; iter = g_list_next(iter) )
{
......@@ -208,18 +227,35 @@ int mark_active(const gchar *name)
return ret;
}
gboolean enumerate_usb(gpointer data)
static gboolean enumerate_usb(gpointer data)
{
struct timeval tv;
/* We arrive here twice: when app sync is done
* and when the app sync timeout gets triggered */
* and when the app sync timeout gets triggered.
* The tags are used to filter out these repeats.
*/
/* activate usb connection/enumeration */
write_to_file("/sys/devices/platform/musb_hdrc/gadget/softconnect", "1");
log_debug("Softconnect enumeration done\n");
if( enum_tag == sync_tag )
{
log_debug("ignoring enumeration trigger");
}
else
{
/* activate usb connection/enumeration */
write_to_file("/sys/devices/platform/musb_hdrc/gadget/softconnect", "1");
log_debug("Softconnect enumeration done\n");
/* remove dbus service */
usb_moded_appsync_cleanup();
enum_tag = sync_tag;
/* Debug: how long it took from sync start to get here */
gettimeofday(&tv, 0);
timersub(&tv, &sync_tv, &tv);
log_debug("sync to enum: %.3f seconds", tv.tv_sec + tv.tv_usec * 1e-6);
/* remove dbus service */
usb_moded_appsync_cleanup();
}
/* return false to stop the timer from repeating */
return FALSE;
}
......@@ -22,17 +22,23 @@
#define CONF_DIR_PATH "/etc/usb-moded/run"
#define APP_INFO_ENTRY "info"
#define APP_INFO_MODE_KEY "mode"
#define APP_INFO_NAME_KEY "name"
#define APP_INFO_LAUNCH_KEY "launch"
/**
* keep all the needed info together for launching an app
*/
typedef struct list_elem
{
char *name;
char *launch;
int active;
/*@{*/
char *name; /* name of the app to launch */
char *mode; /* mode in which to launch the app */
char *launch; /* dbus launch command/address */
int active; /* marker to check if the app has started sucessfully */
/*@}*/
}list_elem;
void readlist(void);
int activate_sync(void);
int activate_sync(const char *mode);
int mark_active(const gchar *name);
gboolean enumerate_usb(gpointer data);
......@@ -78,6 +78,18 @@ int find_cdrom_timeout(void)
}
#endif /* NOKIA */
#ifdef APP_SYNC
const char * check_trigger(void)
{
return(get_conf_string(TRIGGER_ENTRY, TRIGGER_PATH_KEY));
}
const char * check_trigger_mode(void)
{
return(get_conf_string(TRIGGER_ENTRY, TRIGGER_MODE_KEY));
}
#endif /* APP_SYNC */
static int get_conf_int(const gchar *entry, const gchar *key)
{
GKeyFile *settingsfile;
......
......@@ -34,10 +34,14 @@
#define CDROM_ENTRY "cdrom"
#define CDROM_PATH_KEY "path"
#define CDROM_TIMEOUT_KEY "timeout"
#define TRIGGER_ENTRY "trigger"
#define TRIGGER_PATH_KEY "path"
#define TRIGGER_MODE_KEY "mode"
const char * find_mounts(void);
int find_sync(void);
const char * find_alt_mount(void);
#ifdef UDEV
const char * find_udev_path(void);
#endif
......@@ -46,3 +50,8 @@ const char * find_udev_path(void);
const char * find_cdrom_path(void);
int find_cdrom_timeout(void);
#endif
#ifdef APP_SYNC
const char * check_trigger(void);
const char * check_trigger_mode(void);
#endif /* APP_SYNC */
......@@ -89,21 +89,20 @@ static DBusHandlerResult msg_handler(DBusConnection *const connection, DBusMessa
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
else
{
/* check for valid USB MODES in the request */
if(!strcmp(MODE_MASS_STORAGE, use) || !strcmp(MODE_OVI_SUITE, use) || !strcmp(MODE_CHARGING, use) || !strcmp(MODE_WINDOWS_NET, use))
{
/* check if usb is connected, since it makes no sense to change mode if it isn't */
if(!get_usb_connection_state())
goto error_reply;
/* check if the mode exists */
if(valid_mode(use))
goto error_reply;
/* do not change mode if the mode requested is the one already set */
if(strcmp(use, get_usb_mode()) != 0)
set_usb_mode(use);
if((reply = dbus_message_new_method_return(msg)))
dbus_message_append_args (reply, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID);
}
else
else
error_reply:
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
}
dbus_error_free(&err);
}
......
......@@ -65,7 +65,6 @@ int usb_moded_get_export_permission(void)
{
dbus_message_get_args(reply, NULL, DBUS_TYPE_INT32, &ret, DBUS_TYPE_INVALID);
dbus_message_unref(reply);
log_debug("Got reply from devicelock\n");
}
dbus_message_unref(msg);
}
......
/**
@file usb_moded-dyn-mode.c
Copyright (C) 2011 Nokia Corporation. All rights reserved.
@author: Philippe De Swert <philippe.de-swert@nokia.com>
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.
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
*/
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <glib.h>
#include <glib/gstdio.h>
#include "usb_moded-dyn-config.h"
#include "usb_moded-log.h"
static struct mode_list_elem *read_mode_file(const gchar *filename);
GList *read_mode_list(void)
{
GDir *confdir;
GList *modelist = NULL;
const gchar *dirname;
struct mode_list_elem *list_item;
confdir = g_dir_open(MODE_DIR_PATH, 0, NULL);
if(confdir)
{
while((dirname = g_dir_read_name(confdir)) != NULL)
{
log_debug("Read file %s\n", dirname);
list_item = read_mode_file(dirname);
if(list_item)
modelist = g_list_append(modelist, list_item);
}
g_dir_close(confdir);
}
else
log_debug("confdir open failed.\n");
return(modelist);
}
static struct mode_list_elem *read_mode_file(const gchar *filename)
{
GKeyFile *settingsfile;
gboolean test = FALSE;
struct mode_list_elem *list_item = NULL;
gchar *full_filename = NULL;
full_filename = g_strconcat(MODE_DIR_PATH, "/", filename, NULL);
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)
{
return(NULL);
}
list_item = malloc(sizeof(struct mode_list_elem));
list_item->mode_name = g_key_file_get_string(settingsfile, MODE_ENTRY, MODE_NAME_KEY, NULL);
log_debug("Dynamic mode name = %s\n", list_item->mode_name);
list_item->mode_module = g_key_file_get_string(settingsfile, MODE_ENTRY, MODE_MODULE_KEY, NULL);
log_debug("Dynamic mode module = %s\n", list_item->mode_module);
list_item->appsync = g_key_file_get_integer(settingsfile, MODE_ENTRY, MODE_NEEDS_APPSYNC_KEY, NULL);
list_item->network = g_key_file_get_integer(settingsfile, MODE_ENTRY, MODE_NETWORK_KEY, NULL);
list_item->network_interface = g_key_file_get_string(settingsfile, MODE_ENTRY, MODE_NETWORK_INTERFACE_KEY, NULL);
g_key_file_free(settingsfile);
if(list_item->mode_name == NULL || list_item->mode_module == NULL)
{
/* free list_item as it will not be used */
free(list_item);
return NULL;
}
if(list_item->network && list_item->network_interface == NULL)
{
/* free list_item as it will not be used */
free(list_item);
return NULL;