+\f
+/* Truncates and replaces the contents of 'config_file' by a representation
+ * of 'remotes'. */
+static void
+save_config(FILE *config_file, const struct sset *remotes)
+{
+ const char *remote;
+ struct json *json;
+ char *s;
+
+ if (ftruncate(fileno(config_file), 0) == -1) {
+ VLOG_FATAL("failed to truncate temporary file (%s)", strerror(errno));
+ }
+
+ json = json_array_create_empty();
+ SSET_FOR_EACH (remote, remotes) {
+ json_array_add(json, json_string_create(remote));
+ }
+ s = json_to_string(json, 0);
+ json_destroy(json);
+
+ if (fseek(config_file, 0, SEEK_SET) != 0
+ || fputs(s, config_file) == EOF
+ || fflush(config_file) == EOF) {
+ VLOG_FATAL("failed to write temporary file (%s)", strerror(errno));
+ }
+ free(s);
+}
+
+/* Clears and replaces 'remotes' by a configuration read from 'config_file',
+ * which must have been previously written by save_config(). */
+static void
+load_config(FILE *config_file, struct sset *remotes)
+{
+ struct json *json;
+ size_t i;
+
+ sset_clear(remotes);
+
+ if (fseek(config_file, 0, SEEK_SET) != 0) {
+ VLOG_FATAL("seek failed in temporary file (%s)", strerror(errno));
+ }
+ json = json_from_stream(config_file);
+ if (json->type == JSON_STRING) {
+ VLOG_FATAL("reading json failed (%s)", json_string(json));
+ }
+ ovs_assert(json->type == JSON_ARRAY);
+ for (i = 0; i < json->u.array.n; i++) {
+ const struct json *remote = json->u.array.elems[i];
+ sset_add(remotes, json_string(remote));
+ }
+ json_destroy(json);
+}