Beispiel #1
0
int main(void)
{
	char cmd[80];

	snprintf(PIDFILE, sizeof(PIDFILE), "%s%s.pid", _PATH_VARRUN, __progname);

	signal(SIGTERM, sigterm_handler);
	signal(SIGALRM, sigalrm_handler);
	alarm(1);

	printf("Testing pidfile_poll() ...\n");
	if (!pidfile_poll(PIDFILE))
		printf("Timed out!\n");
	else
		printf("We got signal!\n");

	printf("Reading pid file, should be %d ...\n", getpid());
        printf("=> %d\n", pidfile_read(PIDFILE));

	printf("\nComparing __pidfile_name with our guessed PID filename ...\n");
	printf("strcmp(\"%s\",\n       \"%s\") => %s\n\n", __pidfile_name, PIDFILE,
	       !strcmp(__pidfile_name, PIDFILE) ? "OK" : "FAIL");

	/* Occular verification that calling pidfile() again updates mtime */
	snprintf(cmd, sizeof(cmd), "ls -l --full-time %s", PIDFILE);
	system(cmd);
	printf("Before ^^ pidfile() vv after ...\n");
	pidfile(NULL);
	system(cmd);
	
        printf("Signalling ourselves ...\n");

	return pidfile_signal(PIDFILE, SIGTERM);
}
Beispiel #2
0
struct pidfh *
pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
{
	struct pidfh *pfh;
	struct stat sb;
	int error, fd, len;

	pfh = malloc(sizeof(*pfh));
	if (pfh == NULL)
		return (NULL);

	if (path == NULL) {
        free(pfh);
        errno = EINVAL;
        return (NULL);
    }
	else
		len = snprintf(pfh->pf_path, sizeof(pfh->pf_path),
		    "%s", path);
	if (len >= (int)sizeof(pfh->pf_path)) {
		free(pfh);
		errno = ENAMETOOLONG;
		return (NULL);
	}

	/*
	 * Open the PID file and obtain exclusive lock.
	 */
	fd = open(pfh->pf_path, O_WRONLY | O_CREAT, mode);
	if (fd == -1) {
		free(pfh);
		return (NULL);
	}
    if (lock_file(fd) < 0) {
        if (errno == 0 || errno == EAGAIN) {
            pidfile_read(pfh->pf_path, pidptr);
            errno = EEXIST;
        }
		free(pfh);
		return (NULL);
    }
	/*
	 * Remember file information, so in pidfile_write() we are sure we write
	 * to the proper descriptor.
	 */
	if (fstat(fd, &sb) == -1) {
		error = errno;
		unlink(pfh->pf_path);
		close(fd);
		free(pfh);
		errno = error;
		return (NULL);
	}

	pfh->pf_fd = fd;
	pfh->pf_dev = sb.st_dev;
	pfh->pf_ino = sb.st_ino;

	return (pfh);
}
Beispiel #3
0
struct pidfh *
pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
{
	struct pidfh *pfh;
	struct stat sb;
	int error, fd;

	pfh = malloc(sizeof(*pfh));
	if (pfh == NULL)
		return (NULL);

	if (path == NULL) {
		snprintf(pfh->pf_path, sizeof(pfh->pf_path), "/var/run/%s.pid",
		    getprogname());
	} else {
		strlcpy(pfh->pf_path, path, sizeof(pfh->pf_path));
	}
	if (strlen(pfh->pf_path) == sizeof(pfh->pf_path) - 1) {
		free(pfh);
		errno = ENAMETOOLONG;
		return (NULL);
	}

	/*
	 * Open the PID file and obtain exclusive lock.
	 * We truncate PID file here only to remove old PID immediatelly,
	 * PID file will be truncated again in pidfile_write(), so
	 * pidfile_write() can be called multiple times.
	 */
	fd = open(pfh->pf_path,
	    O_WRONLY | O_CREAT | O_EXLOCK | O_TRUNC | O_NONBLOCK, mode);
	if (fd == -1) {
		if (errno == EWOULDBLOCK && pidptr != NULL) {
			errno = pidfile_read(pfh->pf_path, pidptr);
			if (errno == 0)
				errno = EEXIST;
		}
		free(pfh);
		return (NULL);
	}
	/*
	 * Remember file information, so in pidfile_write() we are sure we write
	 * to the proper descriptor.
	 */
	if (fstat(fd, &sb) == -1) {
		error = errno;
		unlink(pfh->pf_path);
		close(fd);
		free(pfh);
		errno = error;
		return (NULL);
	}

	pfh->pf_fd = fd;
	pfh->pf_dev = sb.st_dev;
	pfh->pf_ino = sb.st_ino;

	return (pfh);
}
Beispiel #4
0
int pidfile_open(char *path, pid_t *old_pid)
{       
	//nfs version > 3
	int fd = open(path, O_CREAT|O_EXCL|O_WRONLY, S_IWUSR);
	if (fd < 0){
		if (errno == -EEXIST)
			pidfile_read(path, old_pid);
	}
	return fd;
}                
Beispiel #5
0
/**
 * pidfile_poll - Poll for the existence of a pidfile and return PID
 * @pidfile: Path to pidfile to poll for
 *
 * This function polls for the pidfile at @pidfile for at most 5 seconds
 * before timing out. If the file is created within that time span the
 * file is read and its PID contents returned.
 *
 * Returns:
 * The PID read from @pidfile, or zero on timeout.
 */
pid_t pidfile_poll(const char *pidfile)
{
	pid_t pid = 0;
	int tries = 0;

	/* Timeout = 100 * 50ms = 5s */
	while ((pid = pidfile_read(pidfile)) <= 0 && tries++ < 100)
		usleep(50000);	/* Wait 50ms between retries */

	if (pid < 0)
		pid = 0;

	return pid;
}
Beispiel #6
0
/**
 * pidfile_signal - Send signal to a PID and cleanup pidfile afterwards
 * @pidfile: File containing PID, usually in /var/run/<PROC>.pid
 * @signal: Signal to send to PID found in @pidfile.
 *
 * If @signal is any of %SIGTERM, %SIGKILL, or if kill() returns -1 the
 * @pidfile is removed.
 *
 * Returns:
 * POSIX OK(0) on success, non-zero otherwise.
 */
int pidfile_signal(const char *pidfile, int signal)
{
	int pid = -1, ret = -1;

	pid = pidfile_read(pidfile);
	if (pid <= 0)
		return 1;

	ret = kill(pid, signal);
	if ((ret == -1) || (signal == SIGTERM) || (signal == SIGKILL))
		(void)remove(pidfile);

	return 0;
}
Beispiel #7
0
struct pidfh * pidfile_open(const char *path, mode_t mode, pid_t *pidptr, char **argv)
{
    struct pidfh *pfh;
    struct stat sb;
    int error, fd, len, count;
    struct timespec rqtp;

    pfh = malloc(sizeof(*pfh));
    if (pfh == NULL)
        return (NULL);
    if (path == NULL)
        len = snprintf(pfh->pf_path, sizeof(pfh->pf_path), "/var/run/%s.pid", getprogname());
    else
        len = snprintf(pfh->pf_path, sizeof(pfh->pf_path), "%s", path);

    if (len >= (int)sizeof(pfh->pf_path)) {
        free(pfh);
        errno = ENAMETOOLONG;
        return (NULL);
    }

    fd = flopen(pfh->pf_path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NONBLOCK, mode);

    if (fd == -1) {
        if (errno == EWOULDBLOCK) {
            if (pidptr == NULL) {
                errno = EEXIST;
            } else {
                count = 20;
                rqtp.tv_sec = 0;
                rqtp.tv_nsec = 5000000;
                for(;;) {
                    errno = pidfile_read(pfh->pf_path, pidptr);
                    if (errno != EAGAIN || --count == 0)
                        break;
                    nanosleep(&rqtp, 0);
                }
                if (errno == EAGAIN)
                        *pidptr = -1;
                if (errno == 0 || errno == EAGAIN)
                        errno = EEXIST;
            }
        }
            free(pfh);
            return(NULL);
    }
        
    if (fstat(fd, &sb) == -1) {
        error = errno;
        unlink(pfh->pf_path);
        close(fd);
        free(pfh);
        errno = error;
        return (NULL);
    }

        pfh->pf_fd  = fd;
        pfh->pf_dev = sb.st_dev;
        pfh->pf_ino = sb.st_ino;
        
        return (pfh);
}
Beispiel #8
0
struct pidfh *
pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
{
	struct pidfh *pfh;
	struct stat sb;
	int error, fd, len, count;
	struct timespec rqtp;

	pfh = malloc(sizeof(*pfh));
	if (pfh == NULL)
		return (NULL);

	if (path == NULL)
		len = snprintf(pfh->pf_path, sizeof(pfh->pf_path),
		    "/var/run/%s.pid", getprogname());
	else
		len = snprintf(pfh->pf_path, sizeof(pfh->pf_path),
		    "%s", path);
	if (len >= (int)sizeof(pfh->pf_path)) {
		free(pfh);
		errno = ENAMETOOLONG;
		return (NULL);
	}

	/*
	 * Open the PID file and obtain exclusive lock.
	 * We truncate PID file here only to remove old PID immediatelly,
	 * PID file will be truncated again in pidfile_write(), so
	 * pidfile_write() can be called multiple times.
	 */
	fd = flopen(pfh->pf_path,
	    O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NONBLOCK, mode);
	if (fd == -1) {
		if (errno == EWOULDBLOCK) {
			if (pidptr == NULL) {
				errno = EEXIST;
			} else {
				count = 20;
				rqtp.tv_sec = 0;
				rqtp.tv_nsec = 5000000;
				for (;;) {
					errno = pidfile_read(pfh->pf_path,
					    pidptr);
					if (errno != EAGAIN || --count == 0)
						break;
					nanosleep(&rqtp, 0);
				}
				if (errno == EAGAIN)
					*pidptr = -1;
				if (errno == 0 || errno == EAGAIN)
					errno = EEXIST;
			}
		}
		free(pfh);
		return (NULL);
	}

	/*
	 * Remember file information, so in pidfile_write() we are sure we write
	 * to the proper descriptor.
	 */
	if (fstat(fd, &sb) == -1) {
		error = errno;
		unlink(pfh->pf_path);
		close(fd);
		free(pfh);
		errno = error;
		return (NULL);
	}

	pfh->pf_fd = fd;
	pfh->pf_dev = sb.st_dev;
	pfh->pf_ino = sb.st_ino;

	return (pfh);
}
Beispiel #9
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 #10
0
struct pidfh *
pidfile_open(const char *pathp, mode_t mode, pid_t *pidptr)
{
	char path[MAXPATHLEN];
	struct pidfh *pfh;
	struct stat sb;
	int error, fd, dirfd, dirlen, filenamelen, count;
	struct timespec rqtp;
	cap_rights_t caprights;

	pfh = malloc(sizeof(*pfh));
	if (pfh == NULL)
		return (NULL);

	if (pathp == NULL) {
		dirlen = snprintf(pfh->pf_dir, sizeof(pfh->pf_dir),
		    "/var/run/");
		filenamelen = snprintf(pfh->pf_filename,
		    sizeof(pfh->pf_filename), "%s.pid", getprogname());
	} else {
		if (strlcpy(path, pathp, sizeof(path)) >= sizeof(path)) {
			free(pfh);
			errno = ENAMETOOLONG;
			return (NULL);
		}
		dirlen = strlcpy(pfh->pf_dir, dirname(path),
		    sizeof(pfh->pf_dir));
		(void)strlcpy(path, pathp, sizeof(path));
		filenamelen = strlcpy(pfh->pf_filename, basename(path),
		    sizeof(pfh->pf_filename));
	}

	if (dirlen >= (int)sizeof(pfh->pf_dir) ||
	    filenamelen >= (int)sizeof(pfh->pf_filename)) {
		free(pfh);
		errno = ENAMETOOLONG;
		return (NULL);
	}

	dirfd = open(pfh->pf_dir, O_CLOEXEC | O_DIRECTORY | O_NONBLOCK);
	if (dirfd == -1) {
		error = errno;
		free(pfh);
		errno = error;
		return (NULL);
	}

	/*
	 * Open the PID file and obtain exclusive lock.
	 * We truncate PID file here only to remove old PID immediately,
	 * PID file will be truncated again in pidfile_write(), so
	 * pidfile_write() can be called multiple times.
	 */
	fd = flopenat(dirfd, pfh->pf_filename,
	    O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NONBLOCK, mode);
	if (fd == -1) {
		if (errno == EWOULDBLOCK) {
			if (pidptr == NULL) {
				errno = EEXIST;
			} else {
				count = 20;
				rqtp.tv_sec = 0;
				rqtp.tv_nsec = 5000000;
				for (;;) {
					errno = pidfile_read(dirfd,
					    pfh->pf_filename, pidptr);
					if (errno != EAGAIN || --count == 0)
						break;
					nanosleep(&rqtp, 0);
				}
				if (errno == EAGAIN)
					*pidptr = -1;
				if (errno == 0 || errno == EAGAIN)
					errno = EEXIST;
			}
		}
		error = errno;
		close(dirfd);
		free(pfh);
		errno = error;
		return (NULL);
	}

	/*
	 * Remember file information, so in pidfile_write() we are sure we write
	 * to the proper descriptor.
	 */
	if (fstat(fd, &sb) == -1) {
		goto failed;
	}

	if (cap_rights_limit(dirfd,
	    cap_rights_init(&caprights, CAP_UNLINKAT)) < 0 && errno != ENOSYS) {
		goto failed;
	}

	if (cap_rights_limit(fd, cap_rights_init(&caprights, CAP_PWRITE,
	    CAP_FSTAT, CAP_FTRUNCATE)) < 0 &&
	    errno != ENOSYS) {
		goto failed;
	}

	pfh->pf_dirfd = dirfd;
	pfh->pf_fd = fd;
	pfh->pf_dev = sb.st_dev;
	pfh->pf_ino = sb.st_ino;

	return (pfh);

failed:
	error = errno;
	unlinkat(dirfd, pfh->pf_filename, 0);
	close(dirfd);
	close(fd);
	free(pfh);
	errno = error;
	return (NULL);
}