Skip to content

Commit

Permalink
[usb-moded] Always merge ini files in order. Contributes to JB#34609
Browse files Browse the repository at this point in the history
Always merge ini files in the order of [0-9][A-Z][a-z]

Signed-off-by: Jarko Poutiainen <jarko.poutiainen@jollamobile.com>
  • Loading branch information
Jarko Poutiainen committed Apr 6, 2016
1 parent f703dcb commit cc7b237
Showing 1 changed file with 142 additions and 116 deletions.
258 changes: 142 additions & 116 deletions src/usb_moded-config.c
Expand Up @@ -31,6 +31,7 @@
#include <sys/types.h>

#include <glib.h>
#include <glob.h>
/*
#include <glib/gkeyfile.h>
#include <glib/gstdio.h>
Expand Down Expand Up @@ -585,134 +586,159 @@ char * get_network_setting(const char *config)
return(ret);
}

int conf_file_merge(void)
/**
* Merge value from one keyfile to another
*
* Existing values will be overridden
*
* @param dest keyfile to modify
* @param srce keyfile to merge from
* @param grp value group to merge
* @param key value key to merge
*/
static void merge_key(GKeyFile *dest, GKeyFile *srce,
const char *grp, const char *key)
{
gchar *val = g_key_file_get_value(srce, grp, key, 0);
if( val ) {
log_debug("[%s] %s = %s", grp, key, val);
g_key_file_set_value(dest, grp, key, val);
g_free(val);
}
}

/**
* Merge group of values from one keyfile to another
*
* @param dest keyfile to modify
* @param srce keyfile to merge from
* @param grp value group to merge
*/
static void merge_group(GKeyFile *dest, GKeyFile *srce,
const char *grp)
{
gchar **key = g_key_file_get_keys(srce, grp, 0, 0);
if( key ) {
for( size_t i = 0; key[i]; ++i )
merge_key(dest, srce, grp, key[i]);
g_strfreev(key);
}
}

/**
* Merge all groups and values from one keyfile to another
*
* @param dest keyfile to modify
* @param srce keyfile to merge from
*/
static void merge_file(GKeyFile *dest, GKeyFile *srce)
{
GDir *confdir;
struct stat fileinfo, dir;
char *mode = 0, *ip = 0, *gateway = 0, *udev = 0, *hide = 0;
gchar *filename_full;
const gchar *filename;
GString *keyfile_string = NULL;
GKeyFile *settingsfile;
int ret = 0, test = 0, conffile_created = 0;
gchar **grp = g_key_file_get_groups(srce, 0);

confdir = g_dir_open(CONFIG_FILE_DIR, 0, NULL);
if(!confdir)
{
log_debug("No configuration. Creating defaults.\n");
create_conf_file();
/* since there was no configuration at all there is no info to be merged */
return (ret);
}
if( grp ) {
for( size_t i = 0; grp[i]; ++i )
merge_group(dest, srce, grp[i]);
g_strfreev(grp);
}
}

if (stat(FS_MOUNT_CONFIG_FILE, &fileinfo) == -1)
{
/* conf file not created yet, make default and merge all */
create_conf_file();
conffile_created = 1;
}
/**
* Callback function for logging errors within glob()
*
* @param path path to file/dir where error occurred
* @param err errno that occurred
*
* @return 0 (= do not stop glob)
*/
static int glob_error_cb(const char *path, int err)
{
log_debug("%s: glob: %s", path, g_strerror(err));
return 0;
}

/* config file is created, so the dir must exists */
if(stat(CONFIG_FILE_DIR, &dir))
{
log_warning("Directory still does not exists. FS might be ro/corrupted!\n");
ret = 1;
goto end;
}
/**
* Read *.ini files on CONFIG_FILE_DIR in the order of [0-9][A-Z][a-z]
*
* @return the in memory value-pair file.
*/
static GKeyFile *read_ini_files(void)
{
static const char pattern[] = CONFIG_FILE_DIR"/*.ini";
/* st_mtime is changed by file modifications, st_mtime of a directory is changed by the creation or deletion of files in that directory.
So if the st_mtime of the config file is equal to the directory time we can be sure the config is untouched and we do not need
to re-merge the config.
*/
if(fileinfo.st_mtime == dir.st_mtime)
{
/* if a conffile was created, the st_mtime would have been updated so this check will miss information that might be there already,
like after a config file removal for example. So we run a merge anyway if we needed to create the conf file */
if(!conffile_created)
goto end;
}
log_debug("Merging/creating configuration.\n");
keyfile_string = g_string_new(NULL);
/* check each ini file and get contents */
while((filename = g_dir_read_name(confdir)) != NULL)
{
if(!strstr(filename, ".ini"))
{
/* skip this file as it might be a dir or not an ini file */
continue;
}
filename_full = g_strconcat(CONFIG_FILE_DIR, "/", filename, NULL);
log_debug("filename = %s\n", filename_full);
if(!strcmp(filename_full, FS_MOUNT_CONFIG_FILE))
{
/* store mode info to add it later as we want to keep it */
mode = get_mode_setting();
/* store udev path (especially important for the upgrade path */
udev = find_udev_path();
/* store network info */
ip = get_conf_string(NETWORK_ENTRY, NETWORK_IP_KEY);
gateway = get_conf_string(NETWORK_ENTRY, NETWORK_GATEWAY_KEY);
/* store hidden modes */
hide = get_hidden_modes();
continue;
GKeyFile *ini = g_key_file_new();
glob_t gb;
memset(&gb, 0, sizeof gb);
if( glob(pattern, 0, glob_error_cb, &gb) != 0 ) {
log_debug("no configuration ini-files found");
g_key_file_free(ini);
ini = NULL;
goto exit;
}
/* load contents of file, if it fails skip to next one */
settingsfile = g_key_file_new();
test = g_key_file_load_from_file(settingsfile, filename_full, G_KEY_FILE_KEEP_COMMENTS, NULL);
if(!test)
{
log_debug("%d failed loading config file %s\n", test, filename_full);
goto next;
for( size_t i = 0; i < gb.gl_pathc; ++i ) {
const char *path = gb.gl_pathv[i];
GError *err = 0;
GKeyFile *tmp = g_key_file_new();
if( !g_key_file_load_from_file(tmp, path, 0, &err) ) {
log_debug("%s: can't load: %s", path, err->message);
} else {
log_debug("processing %s ...", path);
merge_file(ini, tmp);
}
g_clear_error(&err);
g_key_file_free(tmp);
}
log_debug("file data = %s\n", g_key_file_to_data(settingsfile, NULL, NULL));
keyfile_string = g_string_append(keyfile_string, g_key_file_to_data(settingsfile, NULL, NULL));
log_debug("keyfile_string = %s\n", keyfile_string->str);
g_key_file_free(settingsfile);
exit:
globfree(&gb);
return ini;
}
next:
g_free(filename_full);
}
/**
* Read the *.ini files and create/overwrite FS_MOUNT_CONFIG_FILE with
* the merged data.
*
* @return 0 on failure
*/
int conf_file_merge(void)
{
GString *keyfile_string = NULL;
GKeyFile *settingsfile,*tempfile;
int ret = 0;

if(keyfile_string)
{
/* write out merged config file */
/* g_file_set_contents returns 1 on succes, this function returns 0 */
ret = !g_file_set_contents(FS_MOUNT_CONFIG_FILE, keyfile_string->str, -1, NULL);
g_string_free(keyfile_string, TRUE);
if(mode)
settingsfile = read_ini_files();
if (!settingsfile)
{
set_mode_setting(mode);
log_debug("No configuration. Creating defaults.");
create_conf_file();
/* There was no configuration so no info to be merged */
return ret;
}
if(udev)
{
set_config_setting(UDEV_PATH_ENTRY, UDEV_PATH_KEY, udev);

tempfile = g_key_file_new();
if (g_key_file_load_from_file(tempfile, FS_MOUNT_CONFIG_FILE,
G_KEY_FILE_NONE,NULL)) {
if (!g_strcmp0(g_key_file_to_data(settingsfile, NULL, NULL),
g_key_file_to_data(tempfile, NULL, NULL)))
goto out;
}
/* check if no network data came from an ini file */
if( get_conf_string(NETWORK_ENTRY, NETWORK_IP_KEY))
goto cleanup;
if(ip)
set_network_setting(NETWORK_IP_KEY, ip);
if(gateway)
set_network_setting(NETWORK_GATEWAY_KEY, gateway);
/* re-add hidden modes info */
if(hide)
set_hide_mode_setting(hide);
}
else
ret = 1;
cleanup:
if(mode)
free(mode);
if(udev)
free(udev);
if(ip)
free(ip);
if(gateway)
free(gateway);

end:
g_dir_close(confdir);
return(ret);

log_debug("Merging configuration");
keyfile_string = g_string_new(NULL);
keyfile_string = g_string_append(keyfile_string,
g_key_file_to_data(settingsfile,
NULL, NULL));
if (keyfile_string) {
ret = !g_file_set_contents(FS_MOUNT_CONFIG_FILE,
keyfile_string->str,-1, NULL);
g_string_free(keyfile_string, TRUE);
}
out:
g_key_file_free(tempfile);
g_key_file_free(settingsfile);
return ret;
}

char * get_android_manufacturer(void)
Expand Down

0 comments on commit cc7b237

Please sign in to comment.