usb_moded-config.c 27.7 KB
Newer Older
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 28 29 30 31 32
 * @file usb_moded-config.c
 *
 * Copyright (C) 2010 Nokia Corporation. All rights reserved.
 * Copyright (C) 2012-2018 Jolla. All rights reserved.
 *
 * @author: Philippe De Swert <philippe.de-swert@nokia.com>
 * @author: Philippe De Swert <phdeswer@lumi.maa>
 * @author: Philippe De Swert <philippedeswert@gmail.com>
 * @author: Philippe De Swert <philippe.deswert@jollamobile.com>
 * @author: Reto Zingg <reto.zingg@jollamobile.com>
 * @author: Thomas Perl <m@thp.io>
 * @author: Slava Monich <slava.monich@jolla.com>
 * @author: Martin Jones <martin.jones@jollamobile.com>
 * @author: Jarko Poutiainen <jarko.poutiainen@jollamobile.com>
 * @author: Simo Piiroinen <simo.piiroinen@jollamobile.com>
 * @author: Andrew den Exter <andrew.den.exter@jolla.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
 */
33

34
#include "usb_moded-config-private.h"
35 36 37 38

#include "usb_moded-control.h"
#include "usb_moded-dbus-private.h"
#include "usb_moded-dyn-config.h"
39
#include "usb_moded-log.h"
40
#include "usb_moded-modes.h"
41
#include "usb_moded-worker.h"
42

43 44 45 46
#ifdef USE_MER_SSU
# include "usb_moded-ssu.h"
#endif

47 48 49 50 51 52 53 54
#include <sys/stat.h>

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <glob.h>

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
/* ========================================================================= *
 * Prototypes
 * ========================================================================= */

/* -- config -- */

static int           config_validate_ip              (const char *ipadd);
char                *config_find_mounts              (void);
int                  config_find_sync                (void);
char                *config_find_alt_mount           (void);
char                *config_find_udev_path           (void);
char                *config_find_udev_subsystem      (void);
char                *config_check_trigger            (void);
char                *config_get_trigger_subsystem    (void);
char                *config_get_trigger_mode         (void);
char                *config_get_trigger_property     (void);
char                *config_get_trigger_value        (void);
static char         *config_get_network_ip           (void);
static char         *config_get_network_interface    (void);
static char         *config_get_network_gateway      (void);
static char         *config_get_network_netmask      (void);
static char         *config_get_network_nat_interface(void);
static void          config_create_conf_file         (void);
static int           config_get_conf_int             (const gchar *entry, const gchar *key);
static char         *config_get_conf_string          (const gchar *entry, const gchar *key);
static char         *config_get_kcmdline_string      (const char *entry);
char                *config_get_mode_setting         (void);
int                  config_value_changed            (GKeyFile *settingsfile, const char *entry, const char *key, const char *new_value);
set_config_result_t  config_set_config_setting       (const char *entry, const char *key, const char *value);
set_config_result_t  config_set_mode_setting         (const char *mode);
static char         *config_make_modes_string        (const char *key, const char *mode_name, int include);
set_config_result_t  config_set_hide_mode_setting    (const char *mode);
set_config_result_t  config_set_unhide_mode_setting  (const char *mode);
set_config_result_t  config_set_mode_whitelist       (const char *whitelist);
set_config_result_t  config_set_mode_in_whitelist    (const char *mode, int allowed);
set_config_result_t  config_set_network_setting      (const char *config, const char *setting);
char                *config_get_network_setting      (const char *config);
static void          config_merge_key                (GKeyFile *dest, GKeyFile *srce, const char *grp, const char *key);
static void          config_merge_group              (GKeyFile *dest, GKeyFile *srce, const char *grp);
static void          config_merge_file               (GKeyFile *dest, GKeyFile *srce);
static int           config_glob_error_cb            (const char *path, int err);
static GKeyFile     *config_read_ini_files           (void);
int                  config_merge_conf_file          (void);
char                *config_get_android_manufacturer (void);
char                *config_get_android_vendor_id    (void);
char                *config_get_android_product      (void);
char                *config_get_android_product_id   (void);
char                *config_get_hidden_modes         (void);
char                *config_get_mode_whitelist       (void);
int                  config_is_roaming_not_allowed   (void);

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

static int config_validate_ip(const char *ipadd)
{
    unsigned int b1, b2, b3, b4;
    unsigned char c;

    if (sscanf(ipadd, "%3u.%3u.%3u.%3u%c", &b1, &b2, &b3, &b4, &c) != 4)
116 117
        return(-1);

118
    if ((b1 | b2 | b3 | b4) > 255)
119
        return(-1);
120
    if (strspn(ipadd, "0123456789.") < strlen(ipadd))
121
        return(-1);
122 123
    /* all ok */
    return 0;
124 125
}

126
char *config_find_mounts(void)
127 128
{

129 130 131 132 133 134 135 136 137
    char *ret = NULL;

    ret = config_get_conf_string(FS_MOUNT_ENTRY, FS_MOUNT_KEY);
    if(ret == NULL)
    {
        ret = g_strdup(FS_MOUNT_DEFAULT);
        log_debug("Default mount = %s\n", ret);
    }
    return(ret);
138 139
}

140
int config_find_sync(void)
141 142
{

143
    return(config_get_conf_int(FS_SYNC_ENTRY, FS_SYNC_KEY));
144 145
}

146
char * config_find_alt_mount(void)
147
{
148
    return(config_get_conf_string(ALT_MOUNT_ENTRY, ALT_MOUNT_KEY));
149 150
}

151
char * config_find_udev_path(void)
152
{
153
    return(config_get_conf_string(UDEV_PATH_ENTRY, UDEV_PATH_KEY));
154
}
155

156
char * config_find_udev_subsystem(void)
157
{
158
    return(config_get_conf_string(UDEV_PATH_ENTRY, UDEV_SUBSYSTEM_KEY));
159
}
160

161
char * config_check_trigger(void)
phdeswer's avatar
phdeswer committed
162
{
163
    return(config_get_conf_string(TRIGGER_ENTRY, TRIGGER_PATH_KEY));
phdeswer's avatar
phdeswer committed
164 165
}

166
char * config_get_trigger_subsystem(void)
167
{
168
    return(config_get_conf_string(TRIGGER_ENTRY, TRIGGER_UDEV_SUBSYSTEM));
169 170
}

171
char * config_get_trigger_mode(void)
phdeswer's avatar
phdeswer committed
172
{
173
    return(config_get_conf_string(TRIGGER_ENTRY, TRIGGER_MODE_KEY));
phdeswer's avatar
phdeswer committed
174
}
175

176
char * config_get_trigger_property(void)
177
{
178
    return(config_get_conf_string(TRIGGER_ENTRY, TRIGGER_PROPERTY_KEY));
179 180
}

181
char * config_get_trigger_value(void)
182
{
183
    return(config_get_conf_string(TRIGGER_ENTRY, TRIGGER_PROPERTY_VALUE_KEY));
184
}
phdeswer's avatar
phdeswer committed
185

186
static char * config_get_network_ip(void)
187
{
188 189 190 191
    char * ip = config_get_kcmdline_string(NETWORK_IP_KEY);
    if (ip != NULL)
        if(!config_validate_ip(ip))
            return(ip);
192

193
    return(config_get_conf_string(NETWORK_ENTRY, NETWORK_IP_KEY));
194 195
}

196
static char * config_get_network_interface(void)
197
{
198
    return(config_get_conf_string(NETWORK_ENTRY, NETWORK_INTERFACE_KEY));
199 200
}

201
static char * config_get_network_gateway(void)
202
{
203 204 205
    char * gw = config_get_kcmdline_string(NETWORK_GATEWAY_KEY);
    if (gw != NULL)
        return(gw);
206

207
    return(config_get_conf_string(NETWORK_ENTRY, NETWORK_GATEWAY_KEY));
208 209
}

210
static char * config_get_network_netmask(void)
211
{
212 213 214
    char * netmask = config_get_kcmdline_string(NETWORK_NETMASK_KEY);
    if (netmask != NULL)
        return(netmask);
215

216
    return(config_get_conf_string(NETWORK_ENTRY, NETWORK_NETMASK_KEY));
217 218
}

219
static char * config_get_network_nat_interface(void)
220
{
221
    return(config_get_conf_string(NETWORK_ENTRY, NETWORK_NAT_INTERFACE_KEY));
222 223
}

224
/* create basic conffile with sensible defaults */
225
static void config_create_conf_file(void)
226
{
227 228 229 230
    GKeyFile *settingsfile;
    gchar *keyfile;
    int dir = 1;
    struct stat dir_stat;
231

232
    /* since this function can also be called when the dir exists we only create
233
     * it if it is missing */
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    if(stat(CONFIG_FILE_DIR, &dir_stat))
    {
        dir = mkdir(CONFIG_FILE_DIR, 0755);
        if(dir < 0)
        {
            log_warning("Could not create confdir, continuing without configuration!\n");
            /* no point in trying to generate the config file if the dir cannot be created */
            return;
        }
    }

    settingsfile = g_key_file_new();

    g_key_file_set_string(settingsfile, MODE_SETTING_ENTRY, MODE_SETTING_KEY, MODE_DEVELOPER );
    keyfile = g_key_file_to_data (settingsfile, NULL, NULL);
    if(g_file_set_contents(FS_MOUNT_CONFIG_FILE, keyfile, -1, NULL) == 0)
        log_debug("Conffile creation failed. Continuing without configuration!\n");
    free(keyfile);
    g_key_file_free(settingsfile);
}

static int config_get_conf_int(const gchar *entry, const gchar *key)
{
    GKeyFile *settingsfile;
    gboolean test = FALSE;
    gchar **keys, **origkeys;
    int ret = 0;

    settingsfile = g_key_file_new();
    test = g_key_file_load_from_file(settingsfile, FS_MOUNT_CONFIG_FILE, G_KEY_FILE_NONE, NULL);
    if(!test)
    {
        log_debug("no conffile, Creating\n");
        config_create_conf_file();
    }
    keys = g_key_file_get_keys (settingsfile, entry, NULL, NULL);
    if(keys == NULL)
271
        return ret;
272 273 274
    origkeys = keys;
    while (*keys != NULL)
    {
275 276
        if(!strcmp(*keys, key))
        {
277 278
            ret = g_key_file_get_integer(settingsfile, entry, *keys, NULL);
            log_debug("%s key value  = %d\n", key, ret);
279 280
        }
        keys++;
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
    }
    g_strfreev(origkeys);
    g_key_file_free(settingsfile);
    return(ret);

}

static char * config_get_conf_string(const gchar *entry, const gchar *key)
{
    GKeyFile *settingsfile;
    gboolean test = FALSE;
    gchar **keys, **origkeys, *tmp_char = NULL;
    settingsfile = g_key_file_new();
    test = g_key_file_load_from_file(settingsfile, FS_MOUNT_CONFIG_FILE, G_KEY_FILE_NONE, NULL);
    if(!test)
    {
        log_debug("No conffile. Creating\n");
        config_create_conf_file();
        /* should succeed now */
        g_key_file_load_from_file(settingsfile, FS_MOUNT_CONFIG_FILE, G_KEY_FILE_NONE, NULL);
    }
    keys = g_key_file_get_keys (settingsfile, entry, NULL, NULL);
    if(keys == NULL)
304
        goto end;
305 306 307
    origkeys = keys;
    while (*keys != NULL)
    {
308 309
        if(!strcmp(*keys, key))
        {
310 311 312 313 314
            tmp_char = g_key_file_get_string(settingsfile, entry, *keys, NULL);
            if(tmp_char)
            {
                log_debug("key %s value  = %s\n", key, tmp_char);
            }
315 316
        }
        keys++;
317 318
    }
    g_strfreev(origkeys);
319
end:
320 321
    g_key_file_free(settingsfile);
    return(tmp_char);
322

323
}
324

325
static char * config_get_kcmdline_string(const char *entry)
326
{
327 328 329 330 331 332 333 334 335
    int fd;
    char cmdLine[1024];
    char *ret = NULL;
    int len;
    gint argc = 0;
    gchar **argv = NULL;
    gchar **arg_tokens = NULL, **network_tokens = NULL;
    GError *optErr = NULL;
    int i;
336

337 338 339 340 341
    if ((fd = open("/proc/cmdline", O_RDONLY)) < 0)
    {
        log_debug("could not read /proc/cmdline");
        return(ret);
    }
342

343 344
    len = read(fd, cmdLine, sizeof(cmdLine) - 1);
    close(fd);
345

346 347 348 349 350
    if (len <= 0)
    {
        log_debug("kernel command line was empty");
        return(ret);
    }
351

352
    cmdLine[len] = '\0';
353

354
    /* we're looking for a piece of the kernel command line matching this:
355
     * ip=192.168.3.100::192.168.3.1:255.255.255.0::usb0:on */
356 357 358 359 360
    if (!g_shell_parse_argv(cmdLine, &argc, &argv, &optErr))
    {
        g_error_free(optErr);
        return(ret);
    }
361

362 363
    /* find the ip token */
    for (i=0; i < argc; i++)
364
    {
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
        arg_tokens = g_strsplit(argv[i], "=", 2);
        if (!g_ascii_strcasecmp(arg_tokens[0], "usb_moded_ip"))
        {
            network_tokens = g_strsplit(arg_tokens[1], ":", 7);
            /* check if it is for the usb or rndis interface */
            if(g_strrstr(network_tokens[5], "usb")|| (g_strrstr(network_tokens[5], "rndis")))
            {
                if(!strcmp(entry, NETWORK_IP_KEY))
                {
                    g_free(ret), ret = g_strdup(network_tokens[0]);
                    log_debug("Command line ip = %s\n", ret);
                }
                if(!strcmp(entry, NETWORK_GATEWAY_KEY))
                {
                    /* gateway might be empty, so we do not want to return an empty string */
                    if(strlen(network_tokens[2]) > 2)
                    {
                        g_free(ret), ret = g_strdup(network_tokens[2]);
                        log_debug("Command line gateway = %s\n", ret);
                    }
                }
                if(!strcmp(entry, NETWORK_NETMASK_KEY))
                {
                    g_free(ret), ret = g_strdup(network_tokens[3]);
                    log_debug("Command line netmask = %s\n", ret);
                }
            }
        }
        g_strfreev(arg_tokens);
    }
    g_strfreev(argv);
    g_strfreev(network_tokens);

    return(ret);
}

char * config_get_mode_setting(void)
{
    char * mode = config_get_kcmdline_string(MODE_SETTING_KEY);
    if (mode != NULL)
        return(mode);

    return(config_get_conf_string(MODE_SETTING_ENTRY, MODE_SETTING_KEY));
408
}
409 410 411 412 413 414
/*
 *  @param settingsfile: already opened settingsfile we want to read an entry from
 *  @param entry: entry we want to read
 *  @param key: key value of the entry we want to read
 *  @new_value: potentially new value we want to compare against
 *
415
 *  @return: 0 when the old value is the same as the new one, 1 otherwise
416 417 418
 */
int config_value_changed(GKeyFile *settingsfile, const char *entry, const char *key, const char *new_value)
{
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
    char *old_value = g_key_file_get_string(settingsfile, entry, key, NULL);
    int changed = (g_strcmp0(old_value, new_value) != 0);
    g_free(old_value);
    return changed;
}

set_config_result_t config_set_config_setting(const char *entry, const char *key, const char *value)
{
    GKeyFile *settingsfile;
    gboolean test = FALSE;
    set_config_result_t ret = SET_CONFIG_ERROR;
    gchar *keyfile;

    settingsfile = g_key_file_new();
    test = g_key_file_load_from_file(settingsfile, FS_MOUNT_CONFIG_FILE, G_KEY_FILE_NONE, NULL);
    if(test)
    {
        if(!config_value_changed(settingsfile, entry, key, value))
        {
            g_key_file_free(settingsfile);
            return SET_CONFIG_UNCHANGED;
        }
    }
    else
    {
        log_debug("No conffile. Creating.\n");
        config_create_conf_file();
    }

    g_key_file_set_string(settingsfile, entry, key, value);
    keyfile = g_key_file_to_data (settingsfile, NULL, NULL);
    /* free the settingsfile before writing things out to be sure
451 452
     * the contents will be correctly written to file afterwards.
     * Just a precaution. */
453 454 455 456 457 458
    g_key_file_free(settingsfile);
    if (g_file_set_contents(FS_MOUNT_CONFIG_FILE, keyfile, -1, NULL))
        ret = SET_CONFIG_UPDATED;
    g_free(keyfile);

    return (ret);
459
}
460

461
set_config_result_t config_set_mode_setting(const char *mode)
462
{
463
    if (strcmp(mode, MODE_ASK) && common_valid_mode(mode))
464 465
        return SET_CONFIG_ERROR;
    return (config_set_config_setting(MODE_SETTING_ENTRY, MODE_SETTING_KEY, mode));
466 467
}

468
/* Builds the string used for hidden modes, when hide set to one builds the
469
 * new string of hidden modes when adding one, otherwise it will remove one */
470 471 472 473 474 475 476 477 478 479 480 481 482 483
static char * config_make_modes_string(const char *key, const char *mode_name, int include)
{
    char     *modes_new = 0;
    char     *modes_old = 0;
    gchar   **modes_arr = 0;
    GString  *modes_tmp = 0;
    int i;

    /* Get current comma separated list of hidden modes */
    modes_old = config_get_conf_string(MODE_SETTING_ENTRY, key);
    if(!modes_old)
    {
        modes_old = g_strdup("");
    }
484

485
    modes_arr = g_strsplit(modes_old, ",", 0);
486

487
    modes_tmp = g_string_new(NULL);
488

489
    for(i = 0; modes_arr[i] != NULL; i++)
490
    {
491 492 493 494 495
        if(strlen(modes_arr[i]) == 0)
        {
            /* Skip any empty strings */
            continue;
        }
496

497 498 499 500 501
        if(!strcmp(modes_arr[i], mode_name))
        {
            /* When unhiding, just skip all matching entries */
            if(!include)
                continue;
502

503 504 505
            /* When hiding, keep the 1st match and ignore the rest */
            include = 0;
        }
506

507 508 509 510
        if(modes_tmp->len > 0)
            modes_tmp = g_string_append(modes_tmp, ",");
        modes_tmp = g_string_append(modes_tmp, modes_arr[i]);
    }
511

512 513 514 515 516 517 518
    if(include)
    {
        /* Adding a hidden mode and no matching entry was found */
        if(modes_tmp->len > 0)
            modes_tmp = g_string_append(modes_tmp, ",");
        modes_tmp = g_string_append(modes_tmp, mode_name);
    }
519

520
    modes_new = g_string_free(modes_tmp, FALSE), modes_tmp = 0;
521

522
    g_strfreev(modes_arr), modes_arr = 0;
523

524
    g_free(modes_old), modes_old = 0;
525

526
    return modes_new;
527 528
}

529
set_config_result_t config_set_hide_mode_setting(const char *mode)
phdeswer's avatar
phdeswer committed
530
{
531
    set_config_result_t ret = SET_CONFIG_UNCHANGED;
532

533
    char *hidden_modes = config_make_modes_string(MODE_HIDE_KEY, mode, 1);
534

535 536 537
    if( hidden_modes ) {
        ret = config_set_config_setting(MODE_SETTING_ENTRY, MODE_HIDE_KEY, hidden_modes);
    }
538

539
    if(ret == SET_CONFIG_UPDATED) {
540 541 542
        common_send_hidden_modes_signal();
        common_send_supported_modes_signal();
        common_send_available_modes_signal();
543
    }
544

545
    g_free(hidden_modes);
546

547
    return(ret);
phdeswer's avatar
phdeswer committed
548 549
}

550
set_config_result_t config_set_unhide_mode_setting(const char *mode)
phdeswer's avatar
phdeswer committed
551
{
552
    set_config_result_t ret = SET_CONFIG_UNCHANGED;
553

554
    char *hidden_modes = config_make_modes_string(MODE_HIDE_KEY, mode, 0);
555

556 557 558
    if( hidden_modes ) {
        ret = config_set_config_setting(MODE_SETTING_ENTRY, MODE_HIDE_KEY, hidden_modes);
    }
559

560
    if(ret == SET_CONFIG_UPDATED) {
561 562 563
        common_send_hidden_modes_signal();
        common_send_supported_modes_signal();
        common_send_available_modes_signal();
564
    }
565

566
    g_free(hidden_modes);
567

568
    return(ret);
phdeswer's avatar
phdeswer committed
569 570
}

571
set_config_result_t config_set_mode_whitelist(const char *whitelist)
572
{
573
    set_config_result_t ret = config_set_config_setting(MODE_SETTING_ENTRY, MODE_WHITELIST_KEY, whitelist);
574

575 576 577
    if(ret == SET_CONFIG_UPDATED) {
        char *mode_setting;
        const char *current_mode;
578

579
        mode_setting = config_get_mode_setting();
580
        if (strcmp(mode_setting, MODE_ASK) && common_valid_mode(mode_setting))
581 582
            config_set_mode_setting(MODE_ASK);
        g_free(mode_setting);
583

584
        current_mode = control_get_usb_mode();
585 586 587
        if (!strcmp(current_mode, MODE_UNDEFINED)) {
            /* Disconnected -> do nothing */
        }
588
        else if (strcmp(current_mode, MODE_CHARGING_FALLBACK) && strcmp(current_mode, MODE_ASK) && common_valid_mode(current_mode)) {
589 590
            /* Invalid mode that is not MODE_ASK or MODE_CHARGING_FALLBACK
             * -> switch to MODE_CHARGING_FALLBACK */
591
            control_set_usb_mode(MODE_CHARGING_FALLBACK);
592
        }
593

594
        umdbus_send_whitelisted_modes_signal(whitelist);
595
        common_send_available_modes_signal();
596
    }
597

598
    return ret;
599 600
}

601
set_config_result_t config_set_mode_in_whitelist(const char *mode, int allowed)
602
{
603
    set_config_result_t ret = SET_CONFIG_UNCHANGED;
604

605
    char *whitelist = config_make_modes_string(MODE_WHITELIST_KEY, mode, allowed);
606

607 608 609
    if (whitelist) {
        ret = config_set_mode_whitelist(whitelist);
    }
610

611
    g_free(whitelist);
612

613
    return(ret);
614 615
}

616 617 618 619
/*
 * @param config : the key to be set
 * @param setting : The value to be set
 */
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
set_config_result_t config_set_network_setting(const char *config, const char *setting)
{
    GKeyFile *settingsfile;
    gboolean test = FALSE;
    gchar *keyfile;

    if(!strcmp(config, NETWORK_IP_KEY) || !strcmp(config, NETWORK_GATEWAY_KEY))
        if(config_validate_ip(setting) != 0)
            return SET_CONFIG_ERROR;

    settingsfile = g_key_file_new();
    test = g_key_file_load_from_file(settingsfile, FS_MOUNT_CONFIG_FILE, G_KEY_FILE_NONE, NULL);

    if(!strcmp(config, NETWORK_IP_KEY) || !strcmp(config, NETWORK_INTERFACE_KEY) || !strcmp(config, NETWORK_GATEWAY_KEY))
    {
        set_config_result_t ret = SET_CONFIG_ERROR;
        if (test)
        {
            if(!config_value_changed(settingsfile, NETWORK_ENTRY, config, setting))
            {
                g_key_file_free(settingsfile);
                return SET_CONFIG_UNCHANGED;
            }
        }
        else
        {
            log_debug("No conffile. Creating.\n");
            config_create_conf_file();
        }

        g_key_file_set_string(settingsfile, NETWORK_ENTRY, config, setting);
        keyfile = g_key_file_to_data (settingsfile, NULL, NULL);
        /* free the settingsfile before writing things out to be sure
653 654
         * the contents will be correctly written to file afterwards.
         * Just a precaution. */
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
        g_key_file_free(settingsfile);
        if (g_file_set_contents(FS_MOUNT_CONFIG_FILE, keyfile, -1, NULL))
            ret = SET_CONFIG_UPDATED;
        free(keyfile);
        return ret;
    }
    else
    {
        g_key_file_free(settingsfile);
        return SET_CONFIG_ERROR;
    }
}

char * config_get_network_setting(const char *config)
{
    char * ret = 0;
    struct mode_list_elem *data;

    if(!strcmp(config, NETWORK_IP_KEY))
    {
        ret = config_get_network_ip();
        if(!ret)
            ret = strdup("192.168.2.15");
    }
    else if(!strcmp(config, NETWORK_INTERFACE_KEY))
    {

        /* check main configuration before using
683
         * the information from the specific mode */
684 685 686 687 688
        ret = config_get_network_interface();

        if(ret)
            goto end;
        /* no interface override specified, let's use the one
689
         * from the mode config */
690
        data = worker_get_usb_mode_data();
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
        if(data)
        {
            if(data->network_interface)
            {
                ret = strdup(data->network_interface);
                goto end;
            }
        }
        ret = strdup("usb0");
    }
    else if(!strcmp(config, NETWORK_GATEWAY_KEY))
        return(config_get_network_gateway());
    else if(!strcmp(config, NETWORK_NETMASK_KEY))
    {
        ret = config_get_network_netmask();
        if(!ret)
            ret = strdup("255.255.255.0");
    }
    else if(!strcmp(config, NETWORK_NAT_INTERFACE_KEY))
        return(config_get_network_nat_interface());
    else
        /* no matching keys, return error */
        return(NULL);
714
end:
715
    return(ret);
716 717
}

718 719 720 721 722 723 724 725 726 727
/**
 * 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
 */
728 729 730 731 732 733 734 735 736
static void config_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);
    }
737
}
738

739 740 741 742 743 744 745
/**
 * 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
 */
746 747 748 749 750 751 752 753 754
static void config_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 )
            config_merge_key(dest, srce, grp, key[i]);
        g_strfreev(key);
    }
755
}
756

757 758 759 760 761 762
/**
 * Merge all groups and values from one keyfile to another
 *
 * @param dest keyfile to modify
 * @param srce keyfile to merge from
 */
763
static void config_merge_file(GKeyFile *dest, GKeyFile *srce)
764
{
765
    gchar **grp = g_key_file_get_groups(srce, 0);
766

767 768 769 770 771
    if( grp ) {
        for( size_t i = 0; grp[i]; ++i )
            config_merge_group(dest, srce, grp[i]);
        g_strfreev(grp);
    }
772 773 774 775 776 777 778 779 780 781
}

/**
 * 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)
 */
782
static int config_glob_error_cb(const char *path, int err)
783
{
784 785
    log_debug("%s: glob: %s", path, g_strerror(err));
    return 0;
786 787 788 789 790 791 792
}

/**
 * Read *.ini files on CONFIG_FILE_DIR in the order of [0-9][A-Z][a-z]
 *
 * @return the in memory value-pair file.
 */
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
static GKeyFile *config_read_ini_files(void)
{
    static const char pattern[] = CONFIG_FILE_DIR"/*.ini";

    GKeyFile *ini = g_key_file_new();
    glob_t gb;

    memset(&gb, 0, sizeof gb);

    if( glob(pattern, 0, config_glob_error_cb, &gb) != 0 ) {
        log_debug("no configuration ini-files found");
        g_key_file_free(ini);
        ini = NULL;
        goto exit;
    }

    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);
            config_merge_file(ini, tmp);
        }
        g_clear_error(&err);
        g_key_file_free(tmp);
    }
823
exit:
824 825
    globfree(&gb);
    return ini;
826
}
Philippe De Swert's avatar
Philippe De Swert committed
827

828 829 830 831 832 833
/**
 * Read the *.ini files and create/overwrite FS_MOUNT_CONFIG_FILE with
 * the merged data.
 *
 * @return 0 on failure
 */
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
int config_merge_conf_file(void)
{
    GString *keyfile_string = NULL;
    GKeyFile *settingsfile,*tempfile;
    int ret = 0;

    settingsfile = config_read_ini_files();
    if (!settingsfile)
    {
        log_debug("No configuration. Creating defaults.");
        config_create_conf_file();
        /* There was no configuration so no info to be merged */
        return ret;
    }

    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;
    }

    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);
    }
867
out:
868 869 870
    g_key_file_free(tempfile);
    g_key_file_free(settingsfile);
    return ret;
871
}
872

873
char * config_get_android_manufacturer(void)
874
{
875
#ifdef USE_MER_SSU
876 877 878 879 880 881 882
    /* If SSU can provide manufacturer name, use it. Otherwise fall
     * back to using the name specified in configuration files. */
    char *ssu_name = ssu_get_manufacturer_name();
    if( ssu_name )
    {
        return ssu_name;
    }
883 884
#endif

885
    return config_get_conf_string(ANDROID_ENTRY, ANDROID_MANUFACTURER_KEY);
886
}
887

888
char * config_get_android_vendor_id(void)
889
{
890
    return(config_get_conf_string(ANDROID_ENTRY, ANDROID_VENDOR_ID_KEY));
891 892
}

893
char * config_get_android_product(void)
894
{
895
#ifdef USE_MER_SSU
896 897 898 899 900 901 902
    /* If SSU can provide device model name, use it. Otherwise fall
     * back to using the name specified in configuration files. */
    char *ssu_name = ssu_get_product_name();
    if( ssu_name )
    {
        return ssu_name;
    }
903 904
#endif

905
    return config_get_conf_string(ANDROID_ENTRY, ANDROID_PRODUCT_KEY);
906 907
}

908
char * config_get_android_product_id(void)
909
{
910
    return(config_get_conf_string(ANDROID_ENTRY, ANDROID_PRODUCT_ID_KEY));
911 912
}

913
char * config_get_hidden_modes(void)
phdeswer's avatar
phdeswer committed
914
{
915
    return(config_get_conf_string(MODE_SETTING_ENTRY, MODE_HIDE_KEY));
phdeswer's avatar
phdeswer committed
916
}
917
char * config_get_mode_whitelist(void)
918
{
919
    return(config_get_conf_string(MODE_SETTING_ENTRY, MODE_WHITELIST_KEY));
920
}
phdeswer's avatar
phdeswer committed
921

922
int config_is_roaming_not_allowed(void)
923
{
924
    return(config_get_conf_int(NETWORK_ENTRY, NO_ROAMING_KEY));
925
}