+static int service_load(struct connman_service *service)
+{
+ GKeyFile *keyfile;
+ gchar *pathname, *data = NULL;
+ gsize length;
+ gchar *str;
+ unsigned int ssid_len;
+ int err = 0;
+
+ DBG("service %p", service);
+
+ if (service->profile == NULL)
+ return -EINVAL;
+
+ pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, service->profile);
+ if (pathname == NULL)
+ return -ENOMEM;
+
+ keyfile = g_key_file_new();
+
+ if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
+ g_free(pathname);
+ return -ENOENT;
+ }
+
+ g_free(pathname);
+
+ if (g_key_file_load_from_data(keyfile, data, length,
+ 0, NULL) == FALSE) {
+ g_free(data);
+ return -EILSEQ;
+ }
+
+ g_free(data);
+
+ switch (service->type) {
+ case CONNMAN_SERVICE_TYPE_UNKNOWN:
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ break;
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ if (service->name == NULL) {
+ gchar *name;
+
+ name = g_key_file_get_string(keyfile,
+ service->identifier, "Name", NULL);
+ if (name != NULL) {
+ g_free(service->name);
+ service->name = name;
+ }
+
+ if (service->network != NULL)
+ connman_network_set_name(service->network,
+ name);
+ }
+
+ if (service->network &&
+ connman_network_get_blob(service->network,
+ "WiFi.SSID", &ssid_len) == NULL) {
+ gchar *hex_ssid;
+
+ hex_ssid = g_key_file_get_string(keyfile,
+ service->identifier,
+ "SSID", NULL);
+
+ if (hex_ssid != NULL) {
+ gchar *ssid;
+ unsigned int i, j = 0, hex;
+ size_t hex_ssid_len = strlen(hex_ssid);
+
+ ssid = g_try_malloc0(hex_ssid_len / 2);
+ if (ssid == NULL) {
+ g_free(hex_ssid);
+ err = -ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < hex_ssid_len; i += 2) {
+ sscanf(hex_ssid + i, "%02x", &hex);
+ ssid[j++] = hex;
+ }
+
+ connman_network_set_blob(service->network,
+ "WiFi.SSID", ssid, hex_ssid_len / 2);
+ }
+
+ g_free(hex_ssid);
+ }
+ /* fall through */
+
+ case CONNMAN_SERVICE_TYPE_WIMAX:
+ case CONNMAN_SERVICE_TYPE_BLUETOOTH:
+ case CONNMAN_SERVICE_TYPE_CELLULAR:
+ service->favorite = g_key_file_get_boolean(keyfile,
+ service->identifier, "Favorite", NULL);
+
+ str = g_key_file_get_string(keyfile,
+ service->identifier, "Failure", NULL);
+ if (str != NULL) {
+ service->state = CONNMAN_SERVICE_STATE_FAILURE;
+ service->error = string2error(str);
+ }
+ break;
+ }
+
+ str = g_key_file_get_string(keyfile,
+ service->identifier, "Modified", NULL);
+ if (str != NULL) {
+ g_time_val_from_iso8601(str, &service->modified);
+ g_free(str);
+ }
+
+ str = g_key_file_get_string(keyfile,
+ service->identifier, "Passphrase", NULL);
+ if (str != NULL) {
+ g_free(service->passphrase);
+ service->passphrase = str;
+ }
+
+ __connman_ipconfig_load(service->ipconfig, keyfile,
+ service->identifier, "IPv4.");
+
+done:
+ g_key_file_free(keyfile);
+
+ return err;
+}
+
+static int service_save(struct connman_service *service)
+{
+ GKeyFile *keyfile;
+ gchar *pathname, *data = NULL;
+ gsize length;
+ gchar *str;
+ int err = 0;
+
+ DBG("service %p", service);
+
+ if (service->profile == NULL)
+ return -EINVAL;
+
+ pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, service->profile);
+ if (pathname == NULL)
+ return -ENOMEM;
+
+ keyfile = g_key_file_new();
+
+ if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
+ goto update;
+
+ if (length > 0) {
+ if (g_key_file_load_from_data(keyfile, data, length,
+ 0, NULL) == FALSE)
+ goto done;
+ }
+
+ g_free(data);
+
+update:
+ if (service->name != NULL)
+ g_key_file_set_string(keyfile, service->identifier,
+ "Name", service->name);
+
+ switch (service->type) {
+ case CONNMAN_SERVICE_TYPE_UNKNOWN:
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ break;
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ if (service->network) {
+ const unsigned char *ssid;
+ unsigned int ssid_len = 0;
+
+ ssid = connman_network_get_blob(service->network,
+ "WiFi.SSID", &ssid_len);
+
+ if (ssid != NULL && ssid_len > 0 && ssid[0] != '\0') {
+ char *identifier = service->identifier;
+ GString *str;
+ unsigned int i;
+
+ str = g_string_sized_new(ssid_len * 2);
+ if (str == NULL) {
+ err = -ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < ssid_len; i++)
+ g_string_append_printf(str,
+ "%02x", ssid[i]);
+
+ g_key_file_set_string(keyfile, identifier,
+ "SSID", str->str);
+
+ g_string_free(str, TRUE);
+ }
+ }
+ /* fall through */
+
+ case CONNMAN_SERVICE_TYPE_WIMAX:
+ case CONNMAN_SERVICE_TYPE_BLUETOOTH:
+ case CONNMAN_SERVICE_TYPE_CELLULAR:
+ g_key_file_set_boolean(keyfile, service->identifier,
+ "Favorite", service->favorite);
+
+ if (service->state == CONNMAN_SERVICE_STATE_FAILURE) {
+ const char *failure = error2string(service->error);
+ if (failure != NULL)
+ g_key_file_set_string(keyfile,
+ service->identifier,
+ "Failure", failure);
+ } else {
+ g_key_file_remove_key(keyfile, service->identifier,
+ "Failure", NULL);
+ }
+ break;
+ }
+
+ str = g_time_val_to_iso8601(&service->modified);
+ if (str != NULL) {
+ g_key_file_set_string(keyfile, service->identifier,
+ "Modified", str);
+ g_free(str);
+ }
+
+ if (service->passphrase != NULL)
+ g_key_file_set_string(keyfile, service->identifier,
+ "Passphrase", service->passphrase);
+ else
+ g_key_file_remove_key(keyfile, service->identifier,
+ "Passphrase", NULL);
+
+ __connman_ipconfig_save(service->ipconfig, keyfile,
+ service->identifier, "IPv4.");
+
+ data = g_key_file_to_data(keyfile, &length, NULL);
+
+ if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
+ connman_error("Failed to store service information");
+
+done:
+ g_free(data);
+
+ g_key_file_free(keyfile);
+
+ g_free(pathname);
+
+ return err;
+}
+
+static struct connman_storage service_storage = {
+ .name = "service",
+ .priority = CONNMAN_STORAGE_PRIORITY_LOW,
+ .service_load = service_load,
+ .service_save = service_save,
+};
+