-FILE *ask_and_open(const char *filename, const char *what, const char *mode)
-{
- FILE *r;
- char *directory;
- char *fn;
-
- /* Check stdin and stdout */
- if(!isatty(0) || !isatty(1)) {
- /* Argh, they are running us from a script or something. Write
- the files to the current directory and let them burn in hell
- for ever. */
- fn = xstrdup(filename);
- } else {
- /* Ask for a file and/or directory name. */
- fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
- what, filename);
- fflush(stdout);
-
- fn = readline(stdin, NULL, NULL);
-
- if(!fn) {
- fprintf(stderr, _("Error while reading stdin: %s\n"),
- strerror(errno));
- return NULL;
+/// Write the main configuration file.
+bool main_config_write(meshlink_handle_t *mesh, const char *conf_subdir, const config_t *config, void *key) {
+ if(!mesh->confbase && !conf_subdir) {
+ return true;
+ }
+
+ char path[PATH_MAX];
+ char tmp_path[PATH_MAX + 4];
+ make_main_path(mesh, conf_subdir, path, sizeof(path));
+ snprintf(tmp_path, sizeof(tmp_path), "%s.tmp", path);
+
+ FILE *f = fopen(tmp_path, "w");
+
+ if(!f) {
+ logger(mesh, MESHLINK_ERROR, "Failed to open `%s': %s", tmp_path, strerror(errno));
+ return false;
+ }
+
+ if(!config_write_file(mesh, f, config, key)) {
+ logger(mesh, MESHLINK_ERROR, "Failed to write `%s': %s", tmp_path, strerror(errno));
+ fclose(f);
+ return false;
+ }
+
+ if(fsync(fileno(f))) {
+ logger(mesh, MESHLINK_ERROR, "Failed to sync `%s': %s", tmp_path, strerror(errno));
+ fclose(f);
+ return false;
+ }
+
+ if(rename(tmp_path, path)) {
+ logger(mesh, MESHLINK_ERROR, "Failed to rename `%s' to `%s': %s", tmp_path, path, strerror(errno));
+ fclose(f);
+ return false;
+ }
+
+ if(fclose(f)) {
+ logger(mesh, MESHLINK_ERROR, "Failed to close `%s': %s", tmp_path, strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+/// Read an invitation file from the confbase sub-directory, and immediately delete it.
+bool invitation_read(meshlink_handle_t *mesh, const char *conf_subdir, const char *name, config_t *config, void *key) {
+ if(!mesh->confbase && !conf_subdir) {
+ return false;
+ }
+
+ char path[PATH_MAX];
+ char used_path[PATH_MAX];
+ make_invitation_path(mesh, conf_subdir, name, path, sizeof(path));
+ make_used_invitation_path(mesh, conf_subdir, name, used_path, sizeof(used_path));
+
+ // Atomically rename the invitation file
+ if(rename(path, used_path)) {
+ if(errno == ENOENT) {
+ logger(mesh, MESHLINK_ERROR, "Peer tried to use non-existing invitation %s\n", name);
+ } else {
+ logger(mesh, MESHLINK_ERROR, "Error trying to rename invitation %s\n", name);