|
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 |
00deb3 |
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 |
|