usb_moded-dyn-config.c 9.37 KB
Newer Older
phdeswer's avatar
phdeswer committed
1
/**
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 * @file usb_moded-dyn-mode.c
 *
 * Copyright (C) 2011 Nokia Corporation. All rights reserved.
 * Copyright (C) 2013-2018 Jolla. All rights reserved.
 *
 * @author: Philippe De Swert <philippe.de-swert@nokia.com>
 * @author: Philippe De Swert <philippedeswert@gmail.com>
 * @author: Philippe De Swert <philippe.deswert@jollamobile.com>
 * @author: Thomas Perl <thomas.perl@jolla.com>
 * @author: Slava Monich <slava.monich@jolla.com>
 * @author: Simo Piiroinen <simo.piiroinen@jollamobile.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
 */
phdeswer's avatar
phdeswer committed
28 29

#include "usb_moded-dyn-config.h"
30

phdeswer's avatar
phdeswer committed
31 32
#include "usb_moded-log.h"

33 34
#include <stdlib.h>

35 36 37
/* ========================================================================= *
 * Prototypes
 * ========================================================================= */
phdeswer's avatar
phdeswer committed
38

39 40 41 42 43 44 45 46 47 48 49 50 51
/* -- dynconfig -- */

void                          dynconfig_free_list_item(mode_list_elem *list_item);
void                          dynconfig_free_mode_list(GList *modelist);
static gint                   dynconfig_compare_modes (gconstpointer a, gconstpointer b);
GList                        *dynconfig_read_mode_list(int diag);
static struct mode_list_elem *dynconfig_read_mode_file(const gchar *filename);

/* ========================================================================= *
 * Functions
 * ========================================================================= */

void dynconfig_free_list_item(mode_list_elem *list_item)
52
{
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
    if( list_item ) {
        free(list_item->mode_name);
        free(list_item->mode_module);
        free(list_item->network_interface);
        free(list_item->sysfs_path);
        free(list_item->sysfs_value);
        free(list_item->sysfs_reset_value);
        free(list_item->android_extra_sysfs_path);
        free(list_item->android_extra_sysfs_value);
        free(list_item->android_extra_sysfs_path2);
        free(list_item->android_extra_sysfs_value2);
        free(list_item->android_extra_sysfs_path3);
        free(list_item->android_extra_sysfs_value3);
        free(list_item->android_extra_sysfs_path4);
        free(list_item->android_extra_sysfs_value4);
        free(list_item->idProduct);
        free(list_item->idVendorOverride);
70
#ifdef CONNMAN
71
        free(list_item->connman_tethering);
72
#endif
73 74
        free(list_item);
    }
75 76
}

77
void dynconfig_free_mode_list(GList *modelist)
78
{
79 80 81 82 83 84
    if(modelist)
    {
        g_list_foreach(modelist, (GFunc) dynconfig_free_list_item, NULL);
        g_list_free(modelist);
        modelist = 0;
    }
85 86
}

87
static gint dynconfig_compare_modes(gconstpointer a, gconstpointer b)
88
{
89 90
    struct mode_list_elem *aa = (struct mode_list_elem *)a;
    struct mode_list_elem *bb = (struct mode_list_elem *)b;
91

92
    return g_strcmp0(aa->mode_name, bb->mode_name);
93 94
}

95
GList *dynconfig_read_mode_list(int diag)
phdeswer's avatar
phdeswer committed
96
{
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
    GDir *confdir;
    GList *modelist = NULL;
    const gchar *dirname;
    struct mode_list_elem *list_item;
    gchar *full_filename = NULL;

    if(diag)
        confdir = g_dir_open(DIAG_DIR_PATH, 0, NULL);
    else
        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);
            if(diag)
                full_filename = g_strconcat(DIAG_DIR_PATH, "/", dirname, NULL);
            else
                full_filename = g_strconcat(MODE_DIR_PATH, "/", dirname, NULL);
            list_item = dynconfig_read_mode_file(full_filename);
            /* free full_filename immediately as we do not use it anymore */
            free(full_filename);
            if(list_item)
                modelist = g_list_append(modelist, list_item);
        }
        g_dir_close(confdir);
    }
    else
        log_debug("Mode confdir open failed or file is incomplete/invalid.\n");

    modelist = g_list_sort (modelist, dynconfig_compare_modes);
    return(modelist);
phdeswer's avatar
phdeswer committed
129 130
}

131
static struct mode_list_elem *dynconfig_read_mode_file(const gchar *filename)
phdeswer's avatar
phdeswer committed
132
{
133 134
    bool success = false;
    GKeyFile *settingsfile = g_key_file_new();
135 136
    struct mode_list_elem *list_item = NULL;

137 138 139
    if( !g_key_file_load_from_file(settingsfile, filename, G_KEY_FILE_NONE, NULL) ) {
        log_err("%s: can't read mode configuration file", filename);
        goto EXIT;
140
    }
141 142

    list_item = calloc(1, sizeof *list_item);
143 144 145 146 147

    // [MODE_ENTRY = "mode"]
    list_item->mode_name         = g_key_file_get_string(settingsfile, MODE_ENTRY, MODE_NAME_KEY, NULL);
    list_item->mode_module       = g_key_file_get_string(settingsfile, MODE_ENTRY, MODE_MODULE_KEY, NULL);

148 149
    log_debug("Dynamic mode name = %s\n", list_item->mode_name);
    log_debug("Dynamic mode module = %s\n", list_item->mode_module);
150 151 152 153

    list_item->appsync           = g_key_file_get_integer(settingsfile, MODE_ENTRY, MODE_NEEDS_APPSYNC_KEY, NULL);
    list_item->mass_storage      = g_key_file_get_integer(settingsfile, MODE_ENTRY, MODE_MASS_STORAGE_KEY, NULL);
    list_item->network           = g_key_file_get_integer(settingsfile, MODE_ENTRY, MODE_NETWORK_KEY, NULL);
154
    list_item->network_interface = g_key_file_get_string(settingsfile, MODE_ENTRY, MODE_NETWORK_INTERFACE_KEY, NULL);
155 156 157 158 159

    // [MODE_OPTIONS_ENTRY = "options"]
    list_item->sysfs_path                 = g_key_file_get_string(settingsfile, MODE_OPTIONS_ENTRY, MODE_SYSFS_PATH, NULL);
    list_item->sysfs_value                = g_key_file_get_string(settingsfile, MODE_OPTIONS_ENTRY, MODE_SYSFS_VALUE, NULL);
    list_item->sysfs_reset_value          = g_key_file_get_string(settingsfile, MODE_OPTIONS_ENTRY, MODE_SYSFS_RESET_VALUE, NULL);
160

161 162 163 164 165
    list_item->android_extra_sysfs_path   = g_key_file_get_string(settingsfile, MODE_OPTIONS_ENTRY, MODE_ANDROID_EXTRA_SYSFS_PATH, NULL);
    list_item->android_extra_sysfs_path2  = g_key_file_get_string(settingsfile, MODE_OPTIONS_ENTRY, MODE_ANDROID_EXTRA_SYSFS_PATH2, NULL);
    list_item->android_extra_sysfs_path3  = g_key_file_get_string(settingsfile, MODE_OPTIONS_ENTRY, MODE_ANDROID_EXTRA_SYSFS_PATH3, NULL);
    list_item->android_extra_sysfs_path4  = g_key_file_get_string(settingsfile, MODE_OPTIONS_ENTRY, MODE_ANDROID_EXTRA_SYSFS_PATH4, NULL);
    list_item->android_extra_sysfs_value  = g_key_file_get_string(settingsfile, MODE_OPTIONS_ENTRY, MODE_ANDROID_EXTRA_SYSFS_VALUE, NULL);
166 167 168
    list_item->android_extra_sysfs_value2 = g_key_file_get_string(settingsfile, MODE_OPTIONS_ENTRY, MODE_ANDROID_EXTRA_SYSFS_VALUE2, NULL);
    list_item->android_extra_sysfs_value3 = g_key_file_get_string(settingsfile, MODE_OPTIONS_ENTRY, MODE_ANDROID_EXTRA_SYSFS_VALUE3, NULL);
    list_item->android_extra_sysfs_value4 = g_key_file_get_string(settingsfile, MODE_OPTIONS_ENTRY, MODE_ANDROID_EXTRA_SYSFS_VALUE4, NULL);
169

170 171 172 173
    list_item->idProduct                  = g_key_file_get_string(settingsfile, MODE_OPTIONS_ENTRY, MODE_IDPRODUCT, NULL);
    list_item->idVendorOverride           = g_key_file_get_string(settingsfile, MODE_OPTIONS_ENTRY, MODE_IDVENDOROVERRIDE, NULL);
    list_item->nat                        = g_key_file_get_integer(settingsfile, MODE_OPTIONS_ENTRY, MODE_HAS_NAT, NULL);
    list_item->dhcp_server                = g_key_file_get_integer(settingsfile, MODE_OPTIONS_ENTRY, MODE_HAS_DHCP_SERVER, NULL);
174
#ifdef CONNMAN
175
    list_item->connman_tethering          = g_key_file_get_string(settingsfile, MODE_OPTIONS_ENTRY, MODE_CONNMAN_TETHERING, NULL);
176
#endif
177

178 179 180 181 182
    //log_debug("Dynamic mode sysfs path = %s\n", list_item->sysfs_path);
    //log_debug("Dynamic mode sysfs value = %s\n", list_item->sysfs_value);
    //log_debug("Android extra mode sysfs path2 = %s\n", list_item->android_extra_sysfs_path2);
    //log_debug("Android extra value2 = %s\n", list_item->android_extra_sysfs_value2);

183 184 185
    if( list_item->mode_name == NULL || list_item->mode_module == NULL ) {
        log_err("%s: mode_name or mode_module not defined", filename);
        goto EXIT;
186
    }
187 188 189 190

    if( list_item->network && list_item->network_interface == NULL) {
        log_err("%s: network not fully defined", filename);
        goto EXIT;
191
    }
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206

    if( (list_item->sysfs_path && !list_item->sysfs_value) ||
        (list_item->sysfs_reset_value && !list_item->sysfs_path) ) {
        /* In theory all of this is optional.
         *
         * In most cases 'sysfs_value' holds a list of functions to enable,
         * and 'sysfs_path' or 'sysfs_reset_value' values are simply ignored.
         *
         * However, for the benefit of existing special configuration files
         * like the one for host mode:
         * - having sysfs_path implies that sysfs_value should be set too
         * - having sysfs_reset_value implies that sysfs_path should be set
         */
        log_err("%s: sysfs_value not fully defined", filename);
        goto EXIT;
207
    }
208 209 210 211 212 213 214 215 216 217 218

    log_debug("%s: successfully loaded", filename);
    success = true;

EXIT:
    g_key_file_free(settingsfile);

    if( !success )
        dynconfig_free_list_item(list_item), list_item = 0;

    return list_item;
phdeswer's avatar
phdeswer committed
219
}