Commit Diff


commit - 44f8036e904cc038f2370d7f1736e16683f7d128
commit + 0583c4cc97a2206fc4cb5a33bc46d12b934a1c30
blob - 6b02de2bf2ad5e613b4eb9949ed3ef62ef6377b2
blob + e1d4d63874e32cdd55d0cd9b33e4d80650fab772
--- commands.c
+++ commands.c
@@ -2434,10 +2434,10 @@ savevar(void *keyptr, size_t keysize, void *value, siz
 static int
 saveenvcmd(int argc, char **argv)
 {
-	char path[PATH_MAX];
+	char tmppath[PATH_MAX], path[PATH_MAX];
 	FILE *f;
 	char *home;
-	int ret;
+	int ret, fd;
 
 	if (argc != 1) {
 		printf("%% usage: saveenv\n");
@@ -2459,16 +2459,38 @@ saveenvcmd(int argc, char **argv)
 		return 0;
 	}
 
-	f = fopen(path, "w");
+	ret = snprintf(tmppath, sizeof(tmppath), "%s/.nshenv-XXXXXXXXXX", home);
+	if (ret < 0 || (size_t)ret >= sizeof(tmppath)) {
+		printf("%% path to ~/.nshenv is too long\n");
+		return 0;
+	}
+
+	fd = mkstemp(tmppath);
+	if (fd == -1) {
+		printf("%s: mkstemp %s: %s", __func__, tmppath,
+		    strerror(errno));
+		return 0;
+	}
+
+
+	f = fdopen(fd, "w");
 	if (f == NULL) {
-		printf("%% fopen %s: %s\n", path, strerror(errno));
+		printf("%% fopen %s: %s\n", tmppath, strerror(errno));
+		close(fd);
 		return 0;
 	}
 
 	if (fchmod(fileno(f), S_IRUSR | S_IWUSR) == -1)
-		printf("%% chmod 600 %s: %s\n", path, strerror(errno));
+		printf("%% chmod 600 %s: %s\n", tmppath, strerror(errno));
 
 	hashtable_foreach(nsh_env, savevar, f);
+
+	if (rename(tmppath, path) == -1) {
+		printf("%% rename %s %s: %s\n", tmppath, path, strerror(errno));
+		if (unlink(tmppath) == -1)
+			printf("%% unlink %s: %s\n", tmppath, strerror(errno));
+	}
+
 	fclose(f);
 
 	return 0;