/* If a pidfile has been configured, creates it and stores the running * process's pid in it. Ensures that the pidfile will be deleted when the * process exits. */ static void make_pidfile(void) { if (pidfile) { /* Create pidfile via temporary file, so that observers never see an * empty pidfile or an unlocked pidfile. */ long int pid = getpid(); char *tmpfile; int fd; tmpfile = xasprintf("%s.tmp%ld", pidfile, pid); fatal_signal_add_file_to_unlink(tmpfile); 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. */ } free(text); } else { VLOG_ERR("%s: write failed: %s", tmpfile, strerror(errno)); close(fd); } } 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); } free(pidfile); pidfile = NULL; }
/* Unregisters pidfile from being unlinked when the program terminates via * exit() or a fatal signal. */ void remove_pidfile_from_unlink(void) { if (pidfile) { fatal_signal_remove_file_to_unlink(pidfile); } }
/* Like fatal_signal_remove_file_to_unlink(), but also unlinks 'file'. * Returns 0 if successful, otherwise a positive errno value. */ int fatal_signal_unlink_file_now(const char *file) { int error = unlink(file) ? errno : 0; if (error) { VLOG_WARN("could not unlink \"%s\" (%s)", file, strerror(error)); } fatal_signal_remove_file_to_unlink(file); return error; }
/* Destroys 'client'. */ void vlog_client_close(struct vlog_client *client) { if (client) { unlink(client->bind_path); fatal_signal_remove_file_to_unlink(client->bind_path); free(client->bind_path); free(client->connect_path); close(client->fd); free(client); } }
/* Destroys 'server' and stops listening for connections. */ void vlog_server_close(struct vlog_server *server) { if (server) { poll_cancel(server->waiter); close(server->fd); unlink(server->path); fatal_signal_remove_file_to_unlink(server->path); free(server->path); free(server); } }
/* Like fatal_signal_remove_file_to_unlink(), but also unlinks 'file'. * Returns 0 if successful, otherwise a positive errno value. */ int fatal_signal_unlink_file_now(const char *file) { int error; fatal_signal_init(); ovs_mutex_lock(&mutex); error = unlink(file) ? errno : 0; if (error) { VLOG_WARN("could not unlink \"%s\" (%s)", file, ovs_strerror(error)); } fatal_signal_remove_file_to_unlink(file); ovs_mutex_unlock(&mutex); return error; }
/* If a pidfile has been configured, creates it and stores the running * process's pid in it. Ensures that the pidfile will be deleted when the * process exits. */ static void make_pidfile(void) { long int pid = getpid(); struct stat s; char *tmpfile; FILE *file; int error; /* Create a temporary pidfile. */ if (overwrite_pidfile) { tmpfile = xasprintf("%s.tmp%ld", pidfile, pid); fatal_signal_add_file_to_unlink(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, ovs_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, ovs_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, ovs_strerror(errno)); } if (ftruncate(fileno(file), 0) == -1) { VLOG_FATAL("%s: truncate failed (%s)", tmpfile, ovs_strerror(errno)); } fprintf(file, "%ld\n", pid); if (fflush(file) == EOF) { VLOG_FATAL("%s: write failed (%s)", tmpfile, ovs_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, ovs_strerror(errno)); } /* Ensure that the pidfile will get deleted on exit. */ fatal_signal_add_file_to_unlink(pidfile); /* Clean up. * * We don't close 'file' because its file descriptor must remain open to * hold the lock. */ pidfile_dev = s.st_dev; pidfile_ino = s.st_ino; free(tmpfile); }