+ unsigned char saltbuf[SALT_SIZE];
+ char *saltname;
+ int saltfd, i, ret;
+
+ saltname = dupprintf("%s/%s", parentdirname, SALT_FILENAME);
+ saltfd = open(saltname, O_RDONLY);
+ if (saltfd < 0) {
+ char *tmpname;
+ int pid;
+
+ if (errno != ENOENT) {
+ *logtext = dupprintf("%s: open: %s", saltname,
+ strerror(errno));
+ sfree(saltname);
+ sfree(parentdirname);
+ return NULL;
+ }
+
+ /*
+ * The salt file doesn't already exist, so try to create
+ * it. Another process may be attempting the same thing
+ * simultaneously, so we must do this carefully: we write
+ * a salt file under a different name, then hard-link it
+ * into place, which guarantees that we won't change the
+ * contents of an existing salt file.
+ */
+ pid = getpid();
+ for (i = 0;; i++) {
+ tmpname = dupprintf("%s/%s.tmp.%d.%d",
+ parentdirname, SALT_FILENAME, pid, i);
+ saltfd = open(tmpname, O_WRONLY | O_EXCL | O_CREAT, 0400);
+ if (saltfd >= 0)
+ break;
+ if (errno != EEXIST) {
+ *logtext = dupprintf("%s: open: %s", tmpname,
+ strerror(errno));
+ sfree(tmpname);
+ sfree(saltname);
+ sfree(parentdirname);
+ return NULL;
+ }
+ sfree(tmpname); /* go round and try again with i+1 */
+ }
+ /*
+ * Invent some random data.
+ */
+ for (i = 0; i < SALT_SIZE; i++) {
+ saltbuf[i] = random_byte();
+ }
+ ret = write(saltfd, saltbuf, SALT_SIZE);
+ /* POSIX atomicity guarantee: because we wrote less than
+ * PIPE_BUF bytes, the write either completed in full or
+ * failed. */
+ assert(SALT_SIZE < PIPE_BUF);
+ assert(ret < 0 || ret == SALT_SIZE);
+ if (ret < 0) {
+ close(saltfd);
+ *logtext = dupprintf("%s: write: %s", tmpname,
+ strerror(errno));
+ sfree(tmpname);
+ sfree(saltname);
+ sfree(parentdirname);
+ return NULL;
+ }
+ if (close(saltfd) < 0) {
+ *logtext = dupprintf("%s: close: %s", tmpname,
+ strerror(errno));
+ sfree(tmpname);
+ sfree(saltname);
+ sfree(parentdirname);
+ return NULL;
+ }