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
23f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He#include <base/logging.h>
24d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati#include <ctype.h>
253fd6713276c37ffcec4e51afc21fa1514a10e0e7Elliott Hughes#include <errno.h>
2695dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung#include <fcntl.h>
2795dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung#include <libgen.h>
28d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati#include <stdio.h>
29d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati#include <stdlib.h>
30d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati#include <string.h>
314197cfdbd36d9f7f213df11b6fee795f22c867fdPavlin Radoslavov#include <sys/stat.h>
32b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson#include <unistd.h>
33d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
340f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/allocator.h"
350f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/list.h"
3644802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati#include "osi/include/log.h"
377f8bfcc35285ca6e93a4436699bc95c13b920cafHansong Zhang#include "log/log.h"
38d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
39d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatitypedef struct {
40b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  char* key;
41b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  char* value;
42d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati} entry_t;
43d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
44d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatitypedef struct {
45b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  char* name;
46b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  list_t* entries;
47d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati} section_t;
48d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
49d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatistruct config_t {
50b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  list_t* sections;
51d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati};
52d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
5336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// Empty definition; this type is aliased to list_node_t.
5436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavatistruct config_section_iter_t {};
5536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
56b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic bool config_parse(FILE* fp, config_t* config);
57d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
58b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic section_t* section_new(const char* name);
59b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void section_free(void* ptr);
60b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic section_t* section_find(const config_t* config, const char* section);
61d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
62b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic entry_t* entry_new(const char* key, const char* value);
63b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void entry_free(void* ptr);
64b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic entry_t* entry_find(const config_t* config, const char* section,
65b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                           const char* key);
66d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
67b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonconfig_t* config_new_empty(void) {
68b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  config_t* config = static_cast<config_t*>(osi_calloc(sizeof(config_t)));
69d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
70d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  config->sections = list_new(section_free);
7136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  if (!config->sections) {
72db554581079863974af8e1289646f5deea6fc044Marie Janssen    LOG_ERROR(LOG_TAG, "%s unable to allocate list for sections.", __func__);
7336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati    goto error;
7436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  }
75d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
76d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return config;
7736c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
7836c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavatierror:;
79ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  config_free(config);
807f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavati  return NULL;
817f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavati}
8236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
83b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonconfig_t* config_new(const char* filename) {
84f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(filename != NULL);
85d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
86b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  config_t* config = config_new_empty();
87b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (!config) return NULL;
88d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
89b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  FILE* fp = fopen(filename, "rt");
907f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavati  if (!fp) {
91b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    LOG_ERROR(LOG_TAG, "%s unable to open file '%s': %s", __func__, filename,
92b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson              strerror(errno));
937f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavati    config_free(config);
94d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    return NULL;
95d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  }
9672a183d00c7534c80a4deb9fb41d38fd9e9455f6Ajay Panicker
9772a183d00c7534c80a4deb9fb41d38fd9e9455f6Ajay Panicker  if (!config_parse(fp, config)) {
9872a183d00c7534c80a4deb9fb41d38fd9e9455f6Ajay Panicker    config_free(config);
9972a183d00c7534c80a4deb9fb41d38fd9e9455f6Ajay Panicker    config = NULL;
10072a183d00c7534c80a4deb9fb41d38fd9e9455f6Ajay Panicker  }
10172a183d00c7534c80a4deb9fb41d38fd9e9455f6Ajay Panicker
102d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  fclose(fp);
103d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return config;
104d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
105d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
106b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonconfig_t* config_new_clone(const config_t* src) {
107f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(src != NULL);
108d9ebc239abf77a1133c3456db84444ccbc8d0fddMarie Janssen
109b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  config_t* ret = config_new_empty();
110d9ebc239abf77a1133c3456db84444ccbc8d0fddMarie Janssen
111f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(ret != NULL);
112d9ebc239abf77a1133c3456db84444ccbc8d0fddMarie Janssen
113b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  for (const list_node_t* node = list_begin(src->sections);
114b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson       node != list_end(src->sections); node = list_next(node)) {
115b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    section_t* sec = static_cast<section_t*>(list_node(node));
116d9ebc239abf77a1133c3456db84444ccbc8d0fddMarie Janssen
117b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    for (const list_node_t* node_entry = list_begin(sec->entries);
118d9ebc239abf77a1133c3456db84444ccbc8d0fddMarie Janssen         node_entry != list_end(sec->entries);
119d9ebc239abf77a1133c3456db84444ccbc8d0fddMarie Janssen         node_entry = list_next(node_entry)) {
120b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson      entry_t* entry = static_cast<entry_t*>(list_node(node_entry));
121d9ebc239abf77a1133c3456db84444ccbc8d0fddMarie Janssen
122d9ebc239abf77a1133c3456db84444ccbc8d0fddMarie Janssen      config_set_string(ret, sec->name, entry->key, entry->value);
123d9ebc239abf77a1133c3456db84444ccbc8d0fddMarie Janssen    }
124d9ebc239abf77a1133c3456db84444ccbc8d0fddMarie Janssen  }
125d9ebc239abf77a1133c3456db84444ccbc8d0fddMarie Janssen
126d9ebc239abf77a1133c3456db84444ccbc8d0fddMarie Janssen  return ret;
127d9ebc239abf77a1133c3456db84444ccbc8d0fddMarie Janssen}
128d9ebc239abf77a1133c3456db84444ccbc8d0fddMarie Janssen
129b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid config_free(config_t* config) {
130b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (!config) return;
131d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
132d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  list_free(config->sections);
133ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  osi_free(config);
134d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
135d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
136b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonbool config_has_section(const config_t* config, const char* section) {
137f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(config != NULL);
138f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(section != NULL);
139d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
140d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return (section_find(config, section) != NULL);
141d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
142d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
143b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonbool config_has_key(const config_t* config, const char* section,
144b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                    const char* key) {
145f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(config != NULL);
146f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(section != NULL);
147f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(key != NULL);
148d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
149d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return (entry_find(config, section, key) != NULL);
150d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
151d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
152b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonint config_get_int(const config_t* config, const char* section, const char* key,
153b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                   int def_value) {
154f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(config != NULL);
155f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(section != NULL);
156f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(key != NULL);
157d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
158b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  entry_t* entry = entry_find(config, section, key);
159b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (!entry) return def_value;
160d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
161b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  char* endptr;
162d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  int ret = strtol(entry->value, &endptr, 0);
163d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return (*endptr == '\0') ? ret : def_value;
164d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
165d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
166b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonbool config_get_bool(const config_t* config, const char* section,
167b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                     const char* key, bool def_value) {
168f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(config != NULL);
169f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(section != NULL);
170f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(key != NULL);
171d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
172b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  entry_t* entry = entry_find(config, section, key);
173b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (!entry) return def_value;
174d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
175b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (!strcmp(entry->value, "true")) return true;
176b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (!strcmp(entry->value, "false")) return false;
177d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
178d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return def_value;
179d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
180d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
181b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonconst char* config_get_string(const config_t* config, const char* section,
182b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                              const char* key, const char* def_value) {
183f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(config != NULL);
184f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(section != NULL);
185f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(key != NULL);
186d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
187b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  entry_t* entry = entry_find(config, section, key);
188b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (!entry) return def_value;
189d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
190d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return entry->value;
191d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
192d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
193b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid config_set_int(config_t* config, const char* section, const char* key,
194b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                    int value) {
195f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(config != NULL);
196f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(section != NULL);
197f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(key != NULL);
198d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
199b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  char value_str[32] = {0};
20080d7f60680f483a71e413f2453ab20013aff5c5cGeorge Burgess IV  snprintf(value_str, sizeof(value_str), "%d", value);
201d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  config_set_string(config, section, key, value_str);
202d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
203d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
204b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid config_set_bool(config_t* config, const char* section, const char* key,
205b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                     bool value) {
206f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(config != NULL);
207f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(section != NULL);
208f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(key != NULL);
209d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
210d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  config_set_string(config, section, key, value ? "true" : "false");
211d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
212d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
213b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid config_set_string(config_t* config, const char* section, const char* key,
214b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                       const char* value) {
215b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  section_t* sec = section_find(config, section);
216d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  if (!sec) {
217d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    sec = section_new(section);
218d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    list_append(config->sections, sec);
219d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  }
220d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
2217f8bfcc35285ca6e93a4436699bc95c13b920cafHansong Zhang  std::string value_string = value;
2227f8bfcc35285ca6e93a4436699bc95c13b920cafHansong Zhang  std::string value_no_newline;
2237f8bfcc35285ca6e93a4436699bc95c13b920cafHansong Zhang  size_t newline_position = value_string.find("\n");
2247f8bfcc35285ca6e93a4436699bc95c13b920cafHansong Zhang  if (newline_position != std::string::npos) {
2257f8bfcc35285ca6e93a4436699bc95c13b920cafHansong Zhang    android_errorWriteLog(0x534e4554, "70808273");
2267f8bfcc35285ca6e93a4436699bc95c13b920cafHansong Zhang    value_no_newline = value_string.substr(0, newline_position);
2277f8bfcc35285ca6e93a4436699bc95c13b920cafHansong Zhang  } else {
2287f8bfcc35285ca6e93a4436699bc95c13b920cafHansong Zhang    value_no_newline = value_string;
2297f8bfcc35285ca6e93a4436699bc95c13b920cafHansong Zhang  }
2307f8bfcc35285ca6e93a4436699bc95c13b920cafHansong Zhang
231b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  for (const list_node_t* node = list_begin(sec->entries);
232b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson       node != list_end(sec->entries); node = list_next(node)) {
233b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    entry_t* entry = static_cast<entry_t*>(list_node(node));
234d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    if (!strcmp(entry->key, key)) {
235ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson      osi_free(entry->value);
2367f8bfcc35285ca6e93a4436699bc95c13b920cafHansong Zhang      entry->value = osi_strdup(value_no_newline.c_str());
237d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      return;
238d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    }
239d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  }
240d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
2417f8bfcc35285ca6e93a4436699bc95c13b920cafHansong Zhang  entry_t* entry = entry_new(key, value_no_newline.c_str());
242d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  list_append(sec->entries, entry);
243d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
244d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
245b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonbool config_remove_section(config_t* config, const char* section) {
246f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(config != NULL);
247f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(section != NULL);
24836c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
249b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  section_t* sec = section_find(config, section);
250b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (!sec) return false;
25136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
25236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  return list_remove(config->sections, sec);
25336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati}
25436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
255b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonbool config_remove_key(config_t* config, const char* section, const char* key) {
256f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(config != NULL);
257f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(section != NULL);
258f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(key != NULL);
25936c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
260b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  section_t* sec = section_find(config, section);
261b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  entry_t* entry = entry_find(config, section, key);
262b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (!sec || !entry) return false;
26336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
26436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  return list_remove(sec->entries, entry);
26536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati}
26636c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
267b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonconst config_section_node_t* config_section_begin(const config_t* config) {
268f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(config != NULL);
269b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  return (const config_section_node_t*)list_begin(config->sections);
27036c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati}
27136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
272b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonconst config_section_node_t* config_section_end(const config_t* config) {
273f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(config != NULL);
274b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  return (const config_section_node_t*)list_end(config->sections);
27536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati}
27636c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
277b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonconst config_section_node_t* config_section_next(
278b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    const config_section_node_t* node) {
279f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(node != NULL);
280b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  return (const config_section_node_t*)list_next((const list_node_t*)node);
28136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati}
28236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
283b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonconst char* config_section_name(const config_section_node_t* node) {
284f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(node != NULL);
285b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  const list_node_t* lnode = (const list_node_t*)node;
286b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  const section_t* section = (const section_t*)list_node(lnode);
28736c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  return section->name;
28836c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati}
28936c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
290b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonbool config_save(const config_t* config, const char* filename) {
291f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(config != NULL);
292f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(filename != NULL);
293f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(*filename != '\0');
29436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
29595dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  // Steps to ensure content of config file gets to disk:
29695dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  //
29795dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  // 1) Open and write to temp file (e.g. bt_config.conf.new).
29895dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  // 2) Sync the temp file to disk with fsync().
29995dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  // 3) Rename temp file to actual config file (e.g. bt_config.conf).
30095dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  //    This ensures atomic update.
30195dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  // 4) Sync directory that has the conf file with fsync().
30295dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  //    This ensures directory entries are up-to-date.
30395dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  int dir_fd = -1;
304b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  FILE* fp = NULL;
30595dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung
30695dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  // Build temp config file based on config file (e.g. bt_config.conf.new).
307b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  static const char* temp_file_ext = ".new";
30895dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  const int filename_len = strlen(filename);
30995dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  const int temp_filename_len = filename_len + strlen(temp_file_ext) + 1;
310b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  char* temp_filename = static_cast<char*>(osi_calloc(temp_filename_len));
31195dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  snprintf(temp_filename, temp_filename_len, "%s%s", filename, temp_file_ext);
31295dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung
31395dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  // Extract directory from file path (e.g. /data/misc/bluedroid).
314b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  char* temp_dirname = osi_strdup(filename);
315b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  const char* directoryname = dirname(temp_dirname);
31695dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  if (!directoryname) {
317b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    LOG_ERROR(LOG_TAG, "%s error extracting directory from '%s': %s", __func__,
318b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson              filename, strerror(errno));
31995dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung    goto error;
32095dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  }
32136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
32295dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  dir_fd = open(directoryname, O_RDONLY);
32395dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  if (dir_fd < 0) {
324b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    LOG_ERROR(LOG_TAG, "%s unable to open dir '%s': %s", __func__,
325b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson              directoryname, strerror(errno));
32695dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung    goto error;
32795dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  }
3288772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati
32995dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  fp = fopen(temp_filename, "wt");
3308772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  if (!fp) {
331b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    LOG_ERROR(LOG_TAG, "%s unable to write file '%s': %s", __func__,
332b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson              temp_filename, strerror(errno));
3338772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati    goto error;
3348772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  }
3358772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati
336b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  for (const list_node_t* node = list_begin(config->sections);
337b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson       node != list_end(config->sections); node = list_next(node)) {
338b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    const section_t* section = (const section_t*)list_node(node);
339fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski    if (fprintf(fp, "[%s]\n", section->name) < 0) {
340b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson      LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__,
341b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                temp_filename, strerror(errno));
342ed2267a0a66b1aec52d9039bc20a6c5099dbdae7Alain Vongsouvanh      goto error;
343fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski    }
34436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
345b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    for (const list_node_t* enode = list_begin(section->entries);
346b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson         enode != list_end(section->entries); enode = list_next(enode)) {
347b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson      const entry_t* entry = (const entry_t*)list_node(enode);
348fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski      if (fprintf(fp, "%s = %s\n", entry->key, entry->value) < 0) {
349b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson        LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__,
350b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                  temp_filename, strerror(errno));
351ed2267a0a66b1aec52d9039bc20a6c5099dbdae7Alain Vongsouvanh        goto error;
352fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski      }
35336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati    }
35436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
35536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati    // Only add a separating newline if there are more sections.
356fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski    if (list_next(node) != list_end(config->sections)) {
357fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski      if (fputc('\n', fp) == EOF) {
358b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson        LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__,
359b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                  temp_filename, strerror(errno));
360ed2267a0a66b1aec52d9039bc20a6c5099dbdae7Alain Vongsouvanh        goto error;
361fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski      }
362fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski    }
36336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  }
36436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
365b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  // Sync written temp file out to disk. fsync() is blocking until data makes it
366b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  // to disk.
36795dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  if (fsync(fileno(fp)) < 0) {
368b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    LOG_WARN(LOG_TAG, "%s unable to fsync file '%s': %s", __func__,
369b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson             temp_filename, strerror(errno));
37095dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  }
37195dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung
372fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski  if (fclose(fp) == EOF) {
373b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    LOG_ERROR(LOG_TAG, "%s unable to close file '%s': %s", __func__,
374b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson              temp_filename, strerror(errno));
375fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski    goto error;
376fd2f03a2e0ab304a2b67a5a3ecf2e4e73d58e6d9Amadeusz Slawinski  }
377ed2267a0a66b1aec52d9039bc20a6c5099dbdae7Alain Vongsouvanh  fp = NULL;
3788772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati
3794197cfdbd36d9f7f213df11b6fee795f22c867fdPavlin Radoslavov  // Change the file's permissions to Read/Write by User and Group
3804197cfdbd36d9f7f213df11b6fee795f22c867fdPavlin Radoslavov  if (chmod(temp_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) == -1) {
381b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    LOG_ERROR(LOG_TAG, "%s unable to change file permissions '%s': %s",
382b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson              __func__, filename, strerror(errno));
3834197cfdbd36d9f7f213df11b6fee795f22c867fdPavlin Radoslavov    goto error;
3844197cfdbd36d9f7f213df11b6fee795f22c867fdPavlin Radoslavov  }
3854197cfdbd36d9f7f213df11b6fee795f22c867fdPavlin Radoslavov
38695dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  // Rename written temp file to the actual config file.
3878772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  if (rename(temp_filename, filename) == -1) {
388b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    LOG_ERROR(LOG_TAG, "%s unable to commit file '%s': %s", __func__, filename,
389b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson              strerror(errno));
3908772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati    goto error;
3918772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  }
3928772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati
39395dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  // This should ensure the directory is updated as well.
39495dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  if (fsync(dir_fd) < 0) {
395b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    LOG_WARN(LOG_TAG, "%s unable to fsync dir '%s': %s", __func__,
396b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson             directoryname, strerror(errno));
39795dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  }
39895dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung
39995dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  if (close(dir_fd) < 0) {
400b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    LOG_ERROR(LOG_TAG, "%s unable to close dir '%s': %s", __func__,
401b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson              directoryname, strerror(errno));
40295dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung    goto error;
40395dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  }
40495dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung
4058772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  osi_free(temp_filename);
40695dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  osi_free(temp_dirname);
40736c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati  return true;
4088772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati
40995dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheungerror:
410b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  // This indicates there is a write issue.  Unlink as partial data is not
411b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  // acceptable.
4128772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  unlink(temp_filename);
413b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (fp) fclose(fp);
414b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (dir_fd != -1) close(dir_fd);
4158772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  osi_free(temp_filename);
41695dbe03a693f4a920204b8c6acbba5269915a59fJacky Cheung  osi_free(temp_dirname);
4178772a37805c112ecda63997f2221fe97944c5ecfSharvil Nanavati  return false;
41836c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati}
41936c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
420b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic char* trim(char* str) {
421b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  while (isspace(*str)) ++str;
422d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
423b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (!*str) return str;
424d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
425b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  char* end_str = str + strlen(str) - 1;
426b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  while (end_str > str && isspace(*end_str)) --end_str;
427d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
428d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  end_str[1] = '\0';
429d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return str;
430d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
431d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
432b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic bool config_parse(FILE* fp, config_t* config) {
433f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(fp != NULL);
434f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(config != NULL);
435d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
436d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  int line_num = 0;
437d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  char line[1024];
438d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  char section[1024];
439d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  strcpy(section, CONFIG_DEFAULT_SECTION);
440d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
441d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  while (fgets(line, sizeof(line), fp)) {
442b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    char* line_ptr = trim(line);
443d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    ++line_num;
444d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
445d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    // Skip blank and comment lines.
446b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    if (*line_ptr == '\0' || *line_ptr == '#') continue;
447d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
448d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    if (*line_ptr == '[') {
449d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      size_t len = strlen(line_ptr);
450d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      if (line_ptr[len - 1] != ']') {
451b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson        LOG_DEBUG(LOG_TAG, "%s unterminated section name on line %d.", __func__,
452b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                  line_num);
45372a183d00c7534c80a4deb9fb41d38fd9e9455f6Ajay Panicker        return false;
454d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      }
455d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      strncpy(section, line_ptr + 1, len - 2);
456d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      section[len - 2] = '\0';
457d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    } else {
458b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson      char* split = strchr(line_ptr, '=');
459d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      if (!split) {
460b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson        LOG_DEBUG(LOG_TAG, "%s no key/value separator found on line %d.",
461b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                  __func__, line_num);
46272a183d00c7534c80a4deb9fb41d38fd9e9455f6Ajay Panicker        return false;
463d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      }
464d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
465d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      *split = '\0';
466d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati      config_set_string(config, section, trim(line_ptr), trim(split + 1));
467d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati    }
468d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  }
46972a183d00c7534c80a4deb9fb41d38fd9e9455f6Ajay Panicker  return true;
470d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
471d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
472b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic section_t* section_new(const char* name) {
473b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  section_t* section = static_cast<section_t*>(osi_calloc(sizeof(section_t)));
474d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
475ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  section->name = osi_strdup(name);
476d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  section->entries = list_new(entry_free);
477d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return section;
478d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
479d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
480b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void section_free(void* ptr) {
481b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (!ptr) return;
482d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
483b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  section_t* section = static_cast<section_t*>(ptr);
484ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  osi_free(section->name);
485d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  list_free(section->entries);
486ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  osi_free(section);
487d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
488d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
489b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic section_t* section_find(const config_t* config, const char* section) {
490b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  for (const list_node_t* node = list_begin(config->sections);
491b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov       node != list_end(config->sections); node = list_next(node)) {
492b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    section_t* sec = static_cast<section_t*>(list_node(node));
493b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    if (!strcmp(sec->name, section)) return sec;
494d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  }
495d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
496d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return NULL;
497d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
498d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
499b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic entry_t* entry_new(const char* key, const char* value) {
500b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  entry_t* entry = static_cast<entry_t*>(osi_calloc(sizeof(entry_t)));
501d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
502ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  entry->key = osi_strdup(key);
503ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  entry->value = osi_strdup(value);
504d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return entry;
505d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
506d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
507b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void entry_free(void* ptr) {
508b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (!ptr) return;
509d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
510b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  entry_t* entry = static_cast<entry_t*>(ptr);
511ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  osi_free(entry->key);
512ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  osi_free(entry->value);
513ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  osi_free(entry);
514d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
515d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
516b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic entry_t* entry_find(const config_t* config, const char* section,
517b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                           const char* key) {
518b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  section_t* sec = section_find(config, section);
519b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (!sec) return NULL;
520d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
521b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  for (const list_node_t* node = list_begin(sec->entries);
522b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov       node != list_end(sec->entries); node = list_next(node)) {
523b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    entry_t* entry = static_cast<entry_t*>(list_node(node));
524b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    if (!strcmp(entry->key, key)) return entry;
525d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  }
526d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
527d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati  return NULL;
528d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati}
529