Add config logging, make parsing stricter, and move sync

The functions that parse the config file will report failure if
the config file is improperly formatted or is missing the necessary
Adapter section. Also moved sync to sync the filesystem after the
config file is saved.

Bug: 27354612
Change-Id: Ia75ff628d83bdc933c4bc16761d6c55eef19b757
diff --git a/btif/src/btif_config.cc b/btif/src/btif_config.cc
index 3018afd..2703372 100644
--- a/btif/src/btif_config.cc
+++ b/btif/src/btif_config.cc
@@ -24,6 +24,7 @@
 #include <ctype.h>
 #include <pthread.h>
 #include <stdio.h>
+#include <string>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
@@ -46,6 +47,7 @@
 
 #define INFO_SECTION "Info"
 #define FILE_TIMESTAMP "TimeCreated"
+#define FILE_SOURCE "FileSource"
 #define TIME_STRING_LENGTH sizeof("YYYY-MM-DD HH:MM:SS")
 static const char* TIME_STRING_FORMAT = "%Y-%m-%d %H:%M:%S";
 
@@ -67,6 +69,7 @@
 static void delete_config_files(void);
 static void btif_config_remove_unpaired(config_t *config);
 static void btif_config_remove_restricted(config_t *config);
+static config_t *btif_config_open(const char* filename);
 
 static enum ConfigSource {
   NOT_LOADED,
@@ -131,26 +134,32 @@
   if (is_factory_reset())
     delete_config_files();
 
-  config = config_new(CONFIG_FILE_PATH);
+  std::string file_source;
+
+  config = btif_config_open(CONFIG_FILE_PATH);
   btif_config_source = ORIGINAL;
   if (!config) {
     LOG_WARN(LOG_TAG, "%s unable to load config file: %s; using backup.",
               __func__, CONFIG_FILE_PATH);
-    config = config_new(CONFIG_BACKUP_PATH);
+    config = btif_config_open(CONFIG_BACKUP_PATH);
     btif_config_source = BACKUP;
+    file_source = "Backup";
   }
   if (!config) {
     LOG_WARN(LOG_TAG, "%s unable to load backup; attempting to transcode legacy file.", __func__);
     config = btif_config_transcode(CONFIG_LEGACY_FILE_PATH);
     btif_config_source = LEGACY;
+    file_source = "Legacy";
   }
   if (!config) {
     LOG_ERROR(LOG_TAG, "%s unable to transcode legacy file; creating empty config.", __func__);
     config = config_new_empty();
     btif_config_source = NEW_FILE;
+    file_source = "Empty";
   }
 
-  const char* time_str;
+  if (!file_source.empty())
+    config_set_string(config, INFO_SECTION, FILE_SOURCE, file_source.c_str());
 
   if (!config) {
     LOG_ERROR(LOG_TAG, "%s unable to allocate a config object.", __func__);
@@ -164,6 +173,7 @@
     btif_config_remove_restricted(config);
 
   // Read or set config file creation timestamp
+  const char* time_str;
   time_str = config_get_string(config, INFO_SECTION, FILE_TIMESTAMP, NULL);
   if (time_str != NULL) {
     strlcpy(btif_config_time_created, time_str, TIME_STRING_LENGTH);
@@ -197,6 +207,20 @@
   return future_new_immediate(FUTURE_FAIL);
 }
 
+static config_t *btif_config_open(const char *filename) {
+  config_t *config = config_new(filename);
+  if (!config)
+    return NULL;
+
+  if (!config_has_section(config, "Adapter")) {
+    LOG_ERROR(LOG_TAG, "Config is missing adapter section");
+    config_free(config);
+    return NULL;
+  }
+
+  return config;
+}
+
 static future_t *shut_down(void) {
   btif_config_flush();
   return future_new_immediate(FUTURE_SUCCESS);
@@ -456,11 +480,11 @@
 
   pthread_mutex_lock(&lock);
   rename(CONFIG_FILE_PATH, CONFIG_BACKUP_PATH);
-  sync();
   config_t *config_paired = config_new_clone(config);
   btif_config_remove_unpaired(config_paired);
   config_save(config_paired, CONFIG_FILE_PATH);
   config_free(config_paired);
+  sync();
   pthread_mutex_unlock(&lock);
 }
 
@@ -522,6 +546,8 @@
 
     dprintf(fd, "  Devices loaded: %d\n", btif_config_devices_loaded);
     dprintf(fd, "  File created/tagged: %s\n", btif_config_time_created);
+    dprintf(fd, "  File source: %s\n", config_get_string(config, INFO_SECTION,
+                                           FILE_SOURCE, "Original"));
 }
 
 static void btif_config_remove_restricted(config_t* config) {
diff --git a/osi/src/config.c b/osi/src/config.c
index 6c76ae1..9683de2 100644
--- a/osi/src/config.c
+++ b/osi/src/config.c
@@ -50,7 +50,7 @@
 // Empty definition; this type is aliased to list_node_t.
 struct config_section_iter_t {};
 
-static void config_parse(FILE *fp, config_t *config);
+static bool config_parse(FILE *fp, config_t *config);
 
 static section_t *section_new(const char *name);
 static void section_free(void *ptr);
@@ -89,7 +89,12 @@
     config_free(config);
     return NULL;
   }
-  config_parse(fp, config);
+
+  if (!config_parse(fp, config)) {
+    config_free(config);
+    config = NULL;
+  }
+
   fclose(fp);
   return config;
 }
@@ -352,7 +357,7 @@
   return str;
 }
 
-static void config_parse(FILE *fp, config_t *config) {
+static bool config_parse(FILE *fp, config_t *config) {
   assert(fp != NULL);
   assert(config != NULL);
 
@@ -373,7 +378,7 @@
       size_t len = strlen(line_ptr);
       if (line_ptr[len - 1] != ']') {
         LOG_DEBUG(LOG_TAG, "%s unterminated section name on line %d.", __func__, line_num);
-        continue;
+        return false;
       }
       strncpy(section, line_ptr + 1, len - 2);
       section[len - 2] = '\0';
@@ -381,13 +386,14 @@
       char *split = strchr(line_ptr, '=');
       if (!split) {
         LOG_DEBUG(LOG_TAG, "%s no key/value separator found on line %d.", __func__, line_num);
-        continue;
+        return false;
       }
 
       *split = '\0';
       config_set_string(config, section, trim(line_ptr), trim(split + 1));
     }
   }
+  return true;
 }
 
 static section_t *section_new(const char *name) {