Blame daemon/flag.c

Packit 8480eb
/* ----------------------------------------------------------------------- *
Packit 8480eb
 *
Packit 8480eb
 * flag.c - autofs flag file management
Packit 8480eb
 *
Packit 8480eb
 * Copyright 2008 Red Hat, Inc. All rights reserved.
Packit 8480eb
 * Copyright 2008 Ian Kent <raven@themaw.net>
Packit 8480eb
 *
Packit 8480eb
 * This program is free software; you can redistribute it and/or modify
Packit 8480eb
 * it under the terms of the GNU General Public License as published by
Packit 8480eb
 * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
Packit 8480eb
 * USA; either version 2 of the License, or (at your option) any later
Packit 8480eb
 * version.
Packit 8480eb
 *
Packit 8480eb
 * This program is distributed in the hope that it will be useful,
Packit 8480eb
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8480eb
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8480eb
 * GNU General Public License for more details.
Packit 8480eb
 *
Packit 8480eb
 * ----------------------------------------------------------------------- */
Packit 8480eb
Packit 8480eb
#include <sys/time.h>
Packit 8480eb
#include <sys/types.h>
Packit 8480eb
#include <sys/stat.h>
Packit 8480eb
#include <time.h>
Packit 8480eb
#include <string.h>
Packit 8480eb
#include <stdio.h>
Packit 8480eb
#include <signal.h>
Packit 8480eb
#include <errno.h>
Packit 8480eb
#include <limits.h>
Packit 8480eb
Packit 8480eb
#include "automount.h"
Packit 8480eb
Packit 8480eb
#define MAX_PIDSIZE	20
Packit 8480eb
#define FLAG_FILE	AUTOFS_FLAG_DIR "/autofs-running"
Packit 8480eb
Packit 8480eb
#define EXE_SELF	"/proc/self/exe"
Packit 8480eb
#define EXE_PID		"/proc/%u/exe"
Packit 8480eb
Packit 8480eb
/* Flag for already existing flag file. */
Packit 8480eb
static int we_created_flagfile = 0;
Packit 8480eb
Packit 8480eb
/* file descriptor of flag file */
Packit 8480eb
static int fd = -1;
Packit 8480eb
Packit 8480eb
static int check_pid_exe_name(pid_t pid)
Packit 8480eb
{
Packit 8480eb
	char self_name[PATH_MAX + 1];
Packit 8480eb
	char pid_name[PATH_MAX + 1];
Packit 8480eb
	char exe_pid[MAX_PIDSIZE + 1];
Packit 8480eb
	int len, ret = 0;
Packit 8480eb
Packit 8480eb
	len = readlink(EXE_SELF, self_name, PATH_MAX);
Packit 8480eb
	if (len == -1 || len == PATH_MAX)
Packit 8480eb
		goto out;
Packit 8480eb
	else
Packit 8480eb
		self_name[len] = 0;
Packit 8480eb
Packit 8480eb
	len = snprintf(exe_pid, MAX_PIDSIZE, EXE_PID, pid);
Packit 8480eb
	if (len >= MAX_PIDSIZE)
Packit 8480eb
		goto out;
Packit 8480eb
Packit 8480eb
	len = readlink(exe_pid, pid_name, PATH_MAX);
Packit 8480eb
	if (len == -1 || len == PATH_MAX)
Packit 8480eb
		goto out;
Packit 8480eb
	else
Packit 8480eb
		pid_name[len] = 0;
Packit 8480eb
Packit 8480eb
	ret = !strcmp(self_name, pid_name);
Packit 8480eb
out:
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int flag_is_owned(int fd)
Packit 8480eb
{
Packit 8480eb
	int pid = 0, tries = 3;
Packit 8480eb
Packit 8480eb
	while (tries--) {
Packit 8480eb
		char pidbuf[MAX_PIDSIZE + 1];
Packit 8480eb
		int got;
Packit 8480eb
Packit 8480eb
		lseek(fd, 0, SEEK_SET);
Packit 8480eb
		got = read(fd, pidbuf, MAX_PIDSIZE);
Packit 8480eb
		/*
Packit 8480eb
		 * We add a terminator to the pid to verify write complete.
Packit 8480eb
		 * If the write isn't finished in 300 milliseconds then it's
Packit 8480eb
		 * probably a stale lock file.
Packit 8480eb
		 */
Packit 8480eb
		if (got > 0 && pidbuf[got - 1] == '\n') {
Packit 8480eb
			sscanf(pidbuf, "%d", &pid;;
Packit 8480eb
			break;
Packit 8480eb
		} else {
Packit 8480eb
			struct timespec t = { 0, 100000000 };
Packit 8480eb
			struct timespec r;
Packit 8480eb
Packit 8480eb
			while (nanosleep(&t, &r) == -1 && errno == EINTR)
Packit 8480eb
				memcpy(&t, &r, sizeof(struct timespec));
Packit 8480eb
Packit 8480eb
			continue;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* Stale flagfile */
Packit 8480eb
	if (!tries)
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	if (pid) {
Packit 8480eb
		int ret;
Packit 8480eb
Packit 8480eb
		ret = kill(pid, 0);
Packit 8480eb
		/*
Packit 8480eb
		 * If lock file exists but is not owned by a process
Packit 8480eb
		 * we return unowned status so we can get rid of it
Packit 8480eb
		 * and continue.
Packit 8480eb
		 */
Packit 8480eb
		if (ret == -1 && errno == ESRCH)
Packit 8480eb
			return 0;
Packit 8480eb
Packit 8480eb
		/* If there is a process check if it is automount */
Packit 8480eb
		if (!check_pid_exe_name(pid))
Packit 8480eb
			return 0;
Packit 8480eb
	} else {
Packit 8480eb
		/*
Packit 8480eb
		 * Odd, no pid in file - so what should we do?
Packit 8480eb
		 * Assume something bad happened to owner and
Packit 8480eb
		 * return unowned status.
Packit 8480eb
		 */
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Remove flag file. */
Packit 8480eb
void release_flag_file(void)
Packit 8480eb
{
Packit 8480eb
	if (fd > 0) {
Packit 8480eb
		close(fd);
Packit 8480eb
		fd = -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (we_created_flagfile) {
Packit 8480eb
		unlink(FLAG_FILE);
Packit 8480eb
		we_created_flagfile = 0;
Packit 8480eb
	}
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* * Try to create flag file */
Packit 8480eb
int aquire_flag_file(void)
Packit 8480eb
{
Packit 8480eb
	char linkf[PATH_MAX];
Packit 8480eb
	size_t len;
Packit 8480eb
Packit 8480eb
	len = snprintf(linkf, sizeof(linkf), "%s.%d", FLAG_FILE, getpid());
Packit 8480eb
	if (len >= sizeof(linkf))
Packit 8480eb
		/* Didn't acquire it */
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * Repeat until it was us who made the link or we find the
Packit 8480eb
	 * flag file already exists. If an unexpected error occurs
Packit 8480eb
	 * we return 0 claiming the flag file exists which may not
Packit 8480eb
	 * really be the case.
Packit 8480eb
	 */
Packit 8480eb
	while (!we_created_flagfile) {
Packit 8480eb
		int errsv, i, j;
Packit 8480eb
Packit Service 04a986
		i = open_fd_mode(linkf, O_WRONLY|O_CREAT, 0644);
Packit 8480eb
		if (i < 0) {
Packit 8480eb
			release_flag_file();
Packit 8480eb
			return 0;
Packit 8480eb
		}
Packit 8480eb
		close(i);
Packit 8480eb
Packit 8480eb
		j = link(linkf, FLAG_FILE);
Packit 8480eb
		errsv = errno;
Packit 8480eb
Packit 8480eb
		(void) unlink(linkf);
Packit 8480eb
Packit 8480eb
		if (j < 0 && errsv != EEXIST) {
Packit 8480eb
			release_flag_file();
Packit 8480eb
			return 0;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		fd = open_fd(FLAG_FILE, O_RDWR);
Packit 8480eb
		if (fd < 0) {
Packit 8480eb
			/* Maybe the file was just deleted? */
Packit 8480eb
			if (errno == ENOENT)
Packit 8480eb
				continue;
Packit 8480eb
			release_flag_file();
Packit 8480eb
			return 0;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (j == 0) {
Packit 8480eb
			char pidbuf[MAX_PIDSIZE + 1];
Packit 8480eb
			int pidlen;
Packit 8480eb
Packit 8480eb
			pidlen = sprintf(pidbuf, "%d\n", getpid());
Packit 8480eb
			if (write(fd, pidbuf, pidlen) != pidlen) {
Packit 8480eb
				release_flag_file();
Packit 8480eb
				return 0;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			we_created_flagfile = 1;
Packit 8480eb
		} else {
Packit 8480eb
			/*
Packit 8480eb
			 * Someone else made the link.
Packit 8480eb
			 * If the flag file is not owned by anyone clean
Packit 8480eb
			 * it up and try again, otherwise return fail.
Packit 8480eb
			 */
Packit 8480eb
			if (!flag_is_owned(fd)) {
Packit 8480eb
				close(fd);
Packit 8480eb
				fd = -1;
Packit 8480eb
				unlink(FLAG_FILE);
Packit 8480eb
				continue;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			release_flag_file();
Packit 8480eb
			return 0;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		close(fd);
Packit 8480eb
		fd = -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb