18772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati/******************************************************************************
28772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati *
38772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati *  Copyright (C) 2014 Google, Inc.
48772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati *
58772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati *  Licensed under the Apache License, Version 2.0 (the "License");
68772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati *  you may not use this file except in compliance with the License.
78772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati *  You may obtain a copy of the License at:
88772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati *
98772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati *  http://www.apache.org/licenses/LICENSE-2.0
108772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati *
118772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati *  Unless required by applicable law or agreed to in writing, software
128772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati *  distributed under the License is distributed on an "AS IS" BASIS,
138772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
148772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati *  See the License for the specific language governing permissions and
158772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati *  limitations under the License.
168772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati *
178772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati ******************************************************************************/
188772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati
19d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati#define LOG_TAG "bt_osi_config"
20d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
2149a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include "osi/include/config.h"
2249a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen
23d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati#include <assert.h>
24d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati#include <ctype.h>
253fd6713276c37ffcec4e51afc21fa1514a10e0e7Elliott Hughes#include <errno.h>
263114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung#include <fcntl.h>
273114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung#include <libgen.h>
28d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati#include <stdio.h>
29d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati#include <stdlib.h>
30d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati#include <string.h>
31bb6836b8e3145522c119e9478d5c7e7df75c3890Arman Uguray#include <unistd.h>
324197cfdbd36d9f7f213df11b6fee795f22c867fdPavlin Radoslavov#include <sys/stat.h>
33d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
340f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/allocator.h"
350f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/list.h"
3644802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati#include "osi/include/log.h"
37d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
38d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatitypedef struct {
39d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  char *key;
40d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  char *value;
41d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati} entry_t;
42d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
43d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatitypedef struct {
44d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  char *name;
45d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  list_t *entries;
46d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati} section_t;
47d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
48d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatistruct config_t {
49d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  list_t *sections;
50d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati};
51d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
5236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// Empty definition; this type is aliased to list_node_t.
5336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavatistruct config_section_iter_t {};
5436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
559eb556804ae753b6fabc66329952dae596f378b7Ajay Panickerstatic bool config_parse(FILE *fp, config_t *config);
56d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
57d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatistatic section_t *section_new(const char *name);
58d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatistatic void section_free(void *ptr);
59d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatistatic section_t *section_find(const config_t *config, const char *section);
60d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
61d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatistatic entry_t *entry_new(const char *key, const char *value);
62d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatistatic void entry_free(void *ptr);
63d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatistatic entry_t *entry_find(const config_t *config, const char *section, const char *key);
64d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
657f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavaticonfig_t *config_new_empty(void) {
66ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  config_t *config = osi_calloc(sizeof(config_t));
67d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
68d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  config->sections = list_new(section_free);
6936c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  if (!config->sections) {
70db554581079863974af8e1289646f5deea6fc044Marie Janssen    LOG_ERROR(LOG_TAG, "%s unable to allocate list for sections.", __func__);
7136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati    goto error;
7236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  }
73d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
74d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return config;
7536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
7636c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavatierror:;
77ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  config_free(config);
787f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavati  return NULL;
797f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavati}
8036c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
81d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavaticonfig_t *config_new(const char *filename) {
82d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(filename != NULL);
83d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
847f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavati  config_t *config = config_new_empty();
857f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavati  if (!config)
86d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    return NULL;
87d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
887f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavati  FILE *fp = fopen(filename, "rt");
897f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavati  if (!fp) {
90db554581079863974af8e1289646f5deea6fc044Marie Janssen    LOG_ERROR(LOG_TAG, "%s unable to open file '%s': %s", __func__, filename, strerror(errno));
917f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavati    config_free(config);
92d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    return NULL;
93d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  }
949eb556804ae753b6fabc66329952dae596f378b7Ajay Panicker
959eb556804ae753b6fabc66329952dae596f378b7Ajay Panicker  if (!config_parse(fp, config)) {
969eb556804ae753b6fabc66329952dae596f378b7Ajay Panicker    config_free(config);
979eb556804ae753b6fabc66329952dae596f378b7Ajay Panicker    config = NULL;
989eb556804ae753b6fabc66329952dae596f378b7Ajay Panicker  }
999eb556804ae753b6fabc66329952dae596f378b7Ajay Panicker
100d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  fclose(fp);
101d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return config;
102d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
103d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
104da576af1312568c4892e6b217d89a82897d60d91Marie Janssenconfig_t *config_new_clone(const config_t *src) {
105b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen  assert(src != NULL);
106b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen
107b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen  config_t *ret = config_new_empty();
108b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen
109b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen  assert(ret != NULL);
110b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen
111b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen  for (const list_node_t *node = list_begin(src->sections);
112b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen       node != list_end(src->sections);
113b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen       node = list_next(node)) {
114b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen    section_t *sec = list_node(node);
115b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen
116b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen    for (const list_node_t *node_entry = list_begin(sec->entries);
117b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen         node_entry != list_end(sec->entries);
118b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen         node_entry = list_next(node_entry)) {
119b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen      entry_t *entry = list_node(node_entry);
120b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen
121b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen      config_set_string(ret, sec->name, entry->key, entry->value);
122b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen    }
123b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen  }
124b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen
125b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen  return ret;
126b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen}
127b9d28c30f9ef9f8f046bb08238abef9cba445be6Marie Janssen
128d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavativoid config_free(config_t *config) {
129d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  if (!config)
130d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    return;
131d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
132d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  list_free(config->sections);
133ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  osi_free(config);
134d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
135d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
136d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatibool config_has_section(const config_t *config, const char *section) {
137d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(config != NULL);
138d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(section != NULL);
139d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
140d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return (section_find(config, section) != NULL);
141d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
142d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
143d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatibool config_has_key(const config_t *config, const char *section, const char *key) {
144d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(config != NULL);
145d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(section != NULL);
146d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(key != NULL);
147d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
148d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return (entry_find(config, section, key) != NULL);
149d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
150d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
151d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatiint config_get_int(const config_t *config, const char *section, const char *key, int def_value) {
152d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(config != NULL);
153d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(section != NULL);
154d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(key != NULL);
155d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
156d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  entry_t *entry = entry_find(config, section, key);
157d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  if (!entry)
158d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    return def_value;
159d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
160d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  char *endptr;
161d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  int ret = strtol(entry->value, &endptr, 0);
162d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return (*endptr == '\0') ? ret : def_value;
163d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
164d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
165d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatibool config_get_bool(const config_t *config, const char *section, const char *key, bool def_value) {
166d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(config != NULL);
167d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(section != NULL);
168d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(key != NULL);
169d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
170d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  entry_t *entry = entry_find(config, section, key);
171d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  if (!entry)
172d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    return def_value;
173d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
174d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  if (!strcmp(entry->value, "true"))
175d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    return true;
176d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  if (!strcmp(entry->value, "false"))
177d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    return false;
178d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
179d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return def_value;
180d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
181d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
182d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavaticonst char *config_get_string(const config_t *config, const char *section, const char *key, const char *def_value) {
183d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(config != NULL);
184d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(section != NULL);
185d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(key != NULL);
186d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
187d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  entry_t *entry = entry_find(config, section, key);
188d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  if (!entry)
189d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    return def_value;
190d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
191d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return entry->value;
192d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
193d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
194d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavativoid config_set_int(config_t *config, const char *section, const char *key, int value) {
195d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(config != NULL);
196d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(section != NULL);
197d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(key != NULL);
198d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
199d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  char value_str[32] = { 0 };
200d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  sprintf(value_str, "%d", value);
201d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  config_set_string(config, section, key, value_str);
202d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
203d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
204d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavativoid config_set_bool(config_t *config, const char *section, const char *key, bool value) {
205d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(config != NULL);
206d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(section != NULL);
207d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(key != NULL);
208d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
209d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  config_set_string(config, section, key, value ? "true" : "false");
210d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
211d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
212d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavativoid config_set_string(config_t *config, const char *section, const char *key, const char *value) {
213d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  section_t *sec = section_find(config, section);
214d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  if (!sec) {
215d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    sec = section_new(section);
216d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    list_append(config->sections, sec);
217d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  }
218d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
219d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  for (const list_node_t *node = list_begin(sec->entries); node != list_end(sec->entries); node = list_next(node)) {
220d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    entry_t *entry = list_node(node);
221d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    if (!strcmp(entry->key, key)) {
222ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson      osi_free(entry->value);
223ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson      entry->value = osi_strdup(value);
224d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      return;
225d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    }
226d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  }
227d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
228d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  entry_t *entry = entry_new(key, value);
229d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  list_append(sec->entries, entry);
230d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
231d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
23236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavatibool config_remove_section(config_t *config, const char *section) {
23336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  assert(config != NULL);
23436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  assert(section != NULL);
23536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
23636c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  section_t *sec = section_find(config, section);
23736c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  if (!sec)
23836c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati    return false;
23936c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
24036c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  return list_remove(config->sections, sec);
24136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati}
24236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
24336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavatibool config_remove_key(config_t *config, const char *section, const char *key) {
24436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  assert(config != NULL);
24536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  assert(section != NULL);
24636c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  assert(key != NULL);
24736c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
24836c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  section_t *sec = section_find(config, section);
24936c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  entry_t *entry = entry_find(config, section, key);
25036c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  if (!sec || !entry)
25136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati    return false;
25236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
25336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  return list_remove(sec->entries, entry);
25436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati}
25536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
25636c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavaticonst config_section_node_t *config_section_begin(const config_t *config) {
25736c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  assert(config != NULL);
25836c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  return (const config_section_node_t *)list_begin(config->sections);
25936c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati}
26036c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
26136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavaticonst config_section_node_t *config_section_end(const config_t *config) {
26236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  assert(config != NULL);
26336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  return (const config_section_node_t *)list_end(config->sections);
26436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati}
26536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
26636c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavaticonst config_section_node_t *config_section_next(const config_section_node_t *node) {
26736c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  assert(node != NULL);
26836c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  return (const config_section_node_t *)list_next((const list_node_t *)node);
26936c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati}
27036c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
27136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavaticonst char *config_section_name(const config_section_node_t *node) {
27236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  assert(node != NULL);
27336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  const list_node_t *lnode = (const list_node_t *)node;
27436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  const section_t *section = (const section_t *)list_node(lnode);
27536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  return section->name;
27636c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati}
27736c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
27836c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavatibool config_save(const config_t *config, const char *filename) {
27936c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  assert(config != NULL);
28036c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  assert(filename != NULL);
28136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  assert(*filename != '\0');
28236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
2833114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  // Steps to ensure content of config file gets to disk:
2843114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  //
2853114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  // 1) Open and write to temp file (e.g. bt_config.conf.new).
2863114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  // 2) Sync the temp file to disk with fsync().
2873114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  // 3) Rename temp file to actual config file (e.g. bt_config.conf).
2883114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  //    This ensures atomic update.
2893114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  // 4) Sync directory that has the conf file with fsync().
2903114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  //    This ensures directory entries are up-to-date.
2913114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  int dir_fd = -1;
2923114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  FILE *fp = NULL;
2933114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung
2943114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  // Build temp config file based on config file (e.g. bt_config.conf.new).
2953114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  static const char *temp_file_ext = ".new";
2963114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  const int filename_len = strlen(filename);
2973114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  const int temp_filename_len = filename_len + strlen(temp_file_ext) + 1;
2983114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  char *temp_filename = osi_calloc(temp_filename_len);
2993114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  snprintf(temp_filename, temp_filename_len, "%s%s", filename, temp_file_ext);
3003114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung
3013114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  // Extract directory from file path (e.g. /data/misc/bluedroid).
3023114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  char *temp_dirname = osi_strdup(filename);
3033114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  const char *directoryname = dirname(temp_dirname);
3043114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  if (!directoryname) {
3053114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung    LOG_ERROR(LOG_TAG, "%s error extracting directory from '%s': %s", __func__, filename, strerror(errno));
3063114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung    goto error;
3073114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  }
30836c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
3093114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  dir_fd = open(directoryname, O_RDONLY);
3103114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  if (dir_fd < 0) {
3113114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung    LOG_ERROR(LOG_TAG, "%s unable to open dir '%s': %s", __func__, directoryname, strerror(errno));
3123114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung    goto error;
3133114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  }
3148772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati
3153114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  fp = fopen(temp_filename, "wt");
3168772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  if (!fp) {
317db554581079863974af8e1289646f5deea6fc044Marie Janssen    LOG_ERROR(LOG_TAG, "%s unable to write file '%s': %s", __func__, temp_filename, strerror(errno));
3188772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati    goto error;
3198772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  }
3208772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati
32136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) {
32236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati    const section_t *section = (const section_t *)list_node(node);
323fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski    if (fprintf(fp, "[%s]\n", section->name) < 0) {
324fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski      LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__, temp_filename, strerror(errno));
325ed2267a0a66b1aec52d9039bc20a6c5099dbdae7Alain Vongsouvanh      goto error;
326fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski    }
32736c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
32836c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati    for (const list_node_t *enode = list_begin(section->entries); enode != list_end(section->entries); enode = list_next(enode)) {
32936c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati      const entry_t *entry = (const entry_t *)list_node(enode);
330fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski      if (fprintf(fp, "%s = %s\n", entry->key, entry->value) < 0) {
331fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski        LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__, temp_filename, strerror(errno));
332ed2267a0a66b1aec52d9039bc20a6c5099dbdae7Alain Vongsouvanh        goto error;
333fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski      }
33436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati    }
33536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
33636c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati    // Only add a separating newline if there are more sections.
337fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski    if (list_next(node) != list_end(config->sections)) {
338fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski      if (fputc('\n', fp) == EOF) {
339fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski        LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__, temp_filename, strerror(errno));
340ed2267a0a66b1aec52d9039bc20a6c5099dbdae7Alain Vongsouvanh        goto error;
341fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski      }
342fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski    }
34336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  }
34436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
3453114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  // Sync written temp file out to disk. fsync() is blocking until data makes it to disk.
3463114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  if (fsync(fileno(fp)) < 0) {
3473114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung    LOG_WARN(LOG_TAG, "%s unable to fsync file '%s': %s", __func__, temp_filename, strerror(errno));
3483114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  }
3493114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung
350fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski  if (fclose(fp) == EOF) {
351fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski    LOG_ERROR(LOG_TAG, "%s unable to close file '%s': %s", __func__, temp_filename, strerror(errno));
352fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski    goto error;
353fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski  }
354ed2267a0a66b1aec52d9039bc20a6c5099dbdae7Alain Vongsouvanh  fp = NULL;
3558772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati
3564197cfdbd36d9f7f213df11b6fee795f22c867fdPavlin Radoslavov  // Change the file's permissions to Read/Write by User and Group
3574197cfdbd36d9f7f213df11b6fee795f22c867fdPavlin Radoslavov  if (chmod(temp_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) == -1) {
3581dffda3bb0c946be415fb3ceabb337694abdf488Marie Janssen    LOG_ERROR(LOG_TAG, "%s unable to change file permissions '%s': %s", __func__, filename, strerror(errno));
3594197cfdbd36d9f7f213df11b6fee795f22c867fdPavlin Radoslavov    goto error;
3604197cfdbd36d9f7f213df11b6fee795f22c867fdPavlin Radoslavov  }
3614197cfdbd36d9f7f213df11b6fee795f22c867fdPavlin Radoslavov
3623114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  // Rename written temp file to the actual config file.
3638772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  if (rename(temp_filename, filename) == -1) {
364db554581079863974af8e1289646f5deea6fc044Marie Janssen    LOG_ERROR(LOG_TAG, "%s unable to commit file '%s': %s", __func__, filename, strerror(errno));
3658772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati    goto error;
3668772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  }
3678772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati
3683114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  // This should ensure the directory is updated as well.
3693114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  if (fsync(dir_fd) < 0) {
3703114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung    LOG_WARN(LOG_TAG, "%s unable to fsync dir '%s': %s", __func__, directoryname, strerror(errno));
3713114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  }
3723114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung
3733114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  if (close(dir_fd) < 0) {
3743114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung    LOG_ERROR(LOG_TAG, "%s unable to close dir '%s': %s", __func__, directoryname, strerror(errno));
3753114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung    goto error;
3763114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  }
3773114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung
3788772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  osi_free(temp_filename);
3793114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  osi_free(temp_dirname);
38036c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  return true;
3818772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati
3823114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheungerror:
3833114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  // This indicates there is a write issue.  Unlink as partial data is not acceptable.
3848772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  unlink(temp_filename);
3853114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  if (fp)
3863114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung    fclose(fp);
3873114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  if (dir_fd != -1)
3883114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung    close(dir_fd);
3898772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  osi_free(temp_filename);
3903114ad623ca39bf6cbcee7f4841c00077faafcbaJacky Cheung  osi_free(temp_dirname);
3918772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  return false;
39236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati}
39336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
394d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatistatic char *trim(char *str) {
395d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  while (isspace(*str))
396d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    ++str;
397d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
398d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  if (!*str)
399d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    return str;
400d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
401d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  char *end_str = str + strlen(str) - 1;
402d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  while (end_str > str && isspace(*end_str))
403d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    --end_str;
404d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
405d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  end_str[1] = '\0';
406d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return str;
407d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
408d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
4099eb556804ae753b6fabc66329952dae596f378b7Ajay Panickerstatic bool config_parse(FILE *fp, config_t *config) {
410d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(fp != NULL);
411d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  assert(config != NULL);
412d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
413d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  int line_num = 0;
414d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  char line[1024];
415d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  char section[1024];
416d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  strcpy(section, CONFIG_DEFAULT_SECTION);
417d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
418d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  while (fgets(line, sizeof(line), fp)) {
419d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    char *line_ptr = trim(line);
420d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    ++line_num;
421d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
422d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    // Skip blank and comment lines.
423d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    if (*line_ptr == '\0' || *line_ptr == '#')
424d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      continue;
425d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
426d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    if (*line_ptr == '[') {
427d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      size_t len = strlen(line_ptr);
428d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      if (line_ptr[len - 1] != ']') {
429db554581079863974af8e1289646f5deea6fc044Marie Janssen        LOG_DEBUG(LOG_TAG, "%s unterminated section name on line %d.", __func__, line_num);
4309eb556804ae753b6fabc66329952dae596f378b7Ajay Panicker        return false;
431d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      }
432d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      strncpy(section, line_ptr + 1, len - 2);
433d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      section[len - 2] = '\0';
434d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    } else {
435d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      char *split = strchr(line_ptr, '=');
436d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      if (!split) {
437db554581079863974af8e1289646f5deea6fc044Marie Janssen        LOG_DEBUG(LOG_TAG, "%s no key/value separator found on line %d.", __func__, line_num);
4389eb556804ae753b6fabc66329952dae596f378b7Ajay Panicker        return false;
439d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      }
440d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
441d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      *split = '\0';
442d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      config_set_string(config, section, trim(line_ptr), trim(split + 1));
443d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    }
444d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  }
4459eb556804ae753b6fabc66329952dae596f378b7Ajay Panicker  return true;
446d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
447d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
448d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatistatic section_t *section_new(const char *name) {
449ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  section_t *section = osi_calloc(sizeof(section_t));
450d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
451ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  section->name = osi_strdup(name);
452d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  section->entries = list_new(entry_free);
453d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return section;
454d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
455d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
456d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatistatic void section_free(void *ptr) {
457d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  if (!ptr)
458d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    return;
459d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
460d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  section_t *section = ptr;
461ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  osi_free(section->name);
462d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  list_free(section->entries);
463ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  osi_free(section);
464d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
465d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
466d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatistatic section_t *section_find(const config_t *config, const char *section) {
467d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) {
468d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    section_t *sec = list_node(node);
469d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    if (!strcmp(sec->name, section))
470d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      return sec;
471d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  }
472d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
473d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return NULL;
474d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
475d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
476d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatistatic entry_t *entry_new(const char *key, const char *value) {
477ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  entry_t *entry = osi_calloc(sizeof(entry_t));
478d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
479ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  entry->key = osi_strdup(key);
480ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  entry->value = osi_strdup(value);
481d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return entry;
482d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
483d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
484d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatistatic void entry_free(void *ptr) {
485d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  if (!ptr)
486d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    return;
487d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
488d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  entry_t *entry = ptr;
489ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  osi_free(entry->key);
490ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  osi_free(entry->value);
491ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  osi_free(entry);
492d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
493d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
494d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatistatic entry_t *entry_find(const config_t *config, const char *section, const char *key) {
495d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  section_t *sec = section_find(config, section);
496d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  if (!sec)
497d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    return NULL;
498d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
499d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  for (const list_node_t *node = list_begin(sec->entries); node != list_end(sec->entries); node = list_next(node)) {
500d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    entry_t *entry = list_node(node);
501d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    if (!strcmp(entry->key, key))
502d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      return entry;
503d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  }
504d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
505d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return NULL;
506d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
507