- fd = open(tmpfile, O_CREAT | O_WRONLY | O_TRUNC, 0666);
- if (fd >= 0) {
- struct flock lck;
- lck.l_type = F_WRLCK;
- lck.l_whence = SEEK_SET;
- lck.l_start = 0;
- lck.l_len = 0;
- if (fcntl(fd, F_SETLK, &lck) != -1) {
- char *text = xasprintf("%ld\n", pid);
- if (write(fd, text, strlen(text)) == strlen(text)) {
- fatal_signal_add_file_to_unlink(pidfile);
- if (rename(tmpfile, pidfile) < 0) {
- VLOG_ERR("failed to rename \"%s\" to \"%s\": %s",
- tmpfile, pidfile, strerror(errno));
- fatal_signal_remove_file_to_unlink(pidfile);
- close(fd);
- } else {
- /* Keep 'fd' open to retain the lock. */
- struct stat s;
-
- if (!fstat(fd, &s)) {
- pidfile_dev = s.st_dev;
- pidfile_ino = s.st_ino;
- } else {
- VLOG_ERR("%s: fstat failed: %s",
- pidfile, strerror(errno));
- }
- }
- } else {
- VLOG_ERR("%s: write failed: %s", tmpfile, strerror(errno));
- close(fd);
- }
- free(text);
- } else {
- VLOG_ERR("%s: fcntl failed: %s", tmpfile, strerror(errno));
- close(fd);
- }
- } else {
- VLOG_ERR("%s: create failed: %s", tmpfile, strerror(errno));
- }
- fatal_signal_remove_file_to_unlink(tmpfile);
- free(tmpfile);
+ } else {
+ /* Everyone shares the same file which will be treated as a lock. To
+ * avoid some uncomfortable race conditions, we can't set up the fatal
+ * signal unlink until we've acquired it. */
+ tmpfile = xasprintf("%s.tmp", pidfile);
+ }
+
+ file = fopen(tmpfile, "a+");
+ if (!file) {
+ VLOG_FATAL("%s: create failed (%s)", tmpfile, strerror(errno));
+ }
+
+ error = lock_pidfile(file, F_SETLK);
+ if (error) {
+ /* Looks like we failed to acquire the lock. Note that, if we failed
+ * for some other reason (and '!overwrite_pidfile'), we will have
+ * left 'tmpfile' as garbage in the file system. */
+ VLOG_FATAL("%s: fcntl(F_SETLK) failed (%s)", tmpfile, strerror(error));
+ }
+
+ if (!overwrite_pidfile) {
+ /* We acquired the lock. Make sure to clean up on exit, and verify
+ * that we're allowed to create the actual pidfile. */
+ fatal_signal_add_file_to_unlink(tmpfile);
+ check_already_running();
+ }
+
+ if (fstat(fileno(file), &s) == -1) {
+ VLOG_FATAL("%s: fstat failed (%s)", tmpfile, strerror(errno));
+ }
+
+ if (ftruncate(fileno(file), 0) == -1) {
+ VLOG_FATAL("%s: truncate failed (%s)", tmpfile, strerror(errno));
+ }
+
+ fprintf(file, "%ld\n", pid);
+ if (fflush(file) == EOF) {
+ VLOG_FATAL("%s: write failed (%s)", tmpfile, strerror(errno));
+ }
+
+ error = rename(tmpfile, pidfile);
+
+ /* Due to a race, 'tmpfile' may be owned by a different process, so we
+ * shouldn't delete it on exit. */
+ fatal_signal_remove_file_to_unlink(tmpfile);
+
+ if (error < 0) {
+ VLOG_FATAL("failed to rename \"%s\" to \"%s\" (%s)",
+ tmpfile, pidfile, strerror(errno));