/* Given a new pidfile name in 'path', deletes any previously-created pidfile
 * if the previous file differs to the new one.
 *
 * If a previous file is deleted, returns 1, which means that a new pidfile
 * must be created.  Otherwise, this returns 0, which means that the existing
 * file does not need to be touched. */
static int
cleanup_old_pidfile(const char* path)
{
	if (pidfile_path != NULL) {
		if (strcmp(pidfile_path, path) != 0) {
			pidfile_cleanup();

			free(pidfile_path);
			pidfile_path = NULL;

			return 1;
		} else
			return 0;
	} else
		return 1;
}
Beispiel #2
0
/* Locks the pidfile specified by path and writes the process pid to it.
 * The new pidfile is "registered" in the global variables pidfile_fd,
 * pidfile_path and pidfile_pid so that any further call to pidfile_lock(3)
 * can check if we are recreating the same file or a new one.
 *
 * Returns 0 on success, otherwise the pid of the process who owns the
 * lock if it can be read, otherwise -1. */
pid_t
pidfile_lock(const char *path)
{
	char dpath[PATH_MAX];
	static bool registered_atexit = false;

	/* Register for cleanup with atexit. */
	if (!registered_atexit) {
		if (atexit(pidfile_cleanup) == -1)
			return -1;
		registered_atexit = true;
	}

	if (path == NULL || strchr(path, '/') == NULL) {
		if (pidfile_varrun_path(dpath, sizeof(dpath), path) == -1)
			return -1;
		path = dpath;
	}

	/* If path has changed (no good reason), clean up the old pidfile. */
	if (pidfile_fd != -1 && strcmp(pidfile_path, path) != 0)
		pidfile_clean();

	if (pidfile_fd == -1) {
		int fd, opts;

		opts = O_WRONLY | O_CREAT | O_NONBLOCK;
#ifdef O_CLOEXEC
		opts |= O_CLOEXEC;
#endif
#ifdef O_EXLOCK
		opts |=	O_EXLOCK;
#endif
		if ((fd = open(path, opts, 0644)) == -1)
			goto return_pid;
#ifndef O_CLOEXEC
		if ((opts = fcntl(fd, F_GETFD)) == -1 ||
		    fctnl(fd, F_SETFL, opts | FD_CLOEXEC) == -1)
		{
			int error = errno;

			(void) close(fd);
			errno = error;
			return -1;
		}
#endif
#ifndef O_EXLOCK
		if (flock(fd, LOCK_EX | LOCK_NB) == -1) {
			int error = errno;

			(void) close(fd);
			if (error != EAGAIN) {
				errno = error;
				return -1;
			}
			fd = -1;
		}
#endif

return_pid:
		if (fd == -1) {
			pid_t pid;

			if (errno == EAGAIN) {
				/* The pidfile is locked, return the process ID
				 * it contains.
				 * If sucessful, set errno to EEXIST. */
				if ((pid = pidfile_read(path)) != -1)
					errno = EEXIST;
			} else
				pid = -1;

			return pid;
		}
		pidfile_fd = fd;
		strlcpy(pidfile_path, path, sizeof(pidfile_path));
	}

	pidfile_pid = getpid();

	/* Truncate the file, as we could be re-writing it.
	 * Then write the process ID. */
	if (ftruncate(pidfile_fd, 0) == -1 ||
	    lseek(pidfile_fd, 0, SEEK_SET) == -1 ||
	    dprintf(pidfile_fd, "%d\n", pidfile_pid) == -1)
	{
		int error = errno;

		pidfile_cleanup();
		errno = error;
		return -1;
	}

	/* Hold the fd open to persist the lock. */
	return 0;
}
Beispiel #3
0
int
pidfile(const char *basename)
{
	FILE *f;

	/*
	 * Register handler which will remove the pidfile later.
	 */
	if (!pidfile_atexit_done) {
		if (atexit(pidfile_cleanup) < 0)
			return -1;
		pidfile_atexit_done = 1;
	}

	if (basename == NULL)
		basename = getprogname();

	/*
	 * If pidfile has already been created for the supplied basename
	 * we don't need to create a pidfile again.
	 */
	if (pidfile_path != NULL) {
		if (strcmp(pidfile_basename, basename) == 0)
			return 0;
		/*
		 * Remove existing pidfile if it was created by this process.
		 */
		pidfile_cleanup();

		free(pidfile_path);
		pidfile_path = NULL;
		free(pidfile_basename);
		pidfile_basename = NULL;
	}

	pidfile_pid = getpid();

	pidfile_basename = strdup(basename);
	if (pidfile_basename == NULL)
		return -1;

	/* _PATH_VARRUN includes trailing / */
	(void) asprintf(&pidfile_path, "%s%s.pid", _PATH_VARRUN, basename);
	if (pidfile_path == NULL) {
		free(pidfile_basename);
		pidfile_basename = NULL;
		return -1;
	}

	if ((f = fopen(pidfile_path, "w")) == NULL) {
		free(pidfile_path);
		pidfile_path = NULL;
		free(pidfile_basename);
		pidfile_basename = NULL;
		return -1;
	}

	(void) fprintf(f, "%d\n", pidfile_pid);
	(void) fclose(f);
	return 0;
}