blob: 16c2d59a5815beaa1c69f959dad454f2b2270927 [file] [log] [blame]
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
extern int errno;
#include <errno.h>
#include <stdlib.h>
/* Check the file and return:
* - 1 in case it exists
* - 0 if not exists
* - (-1) in case of unexpected error, like EPERM)
* if file exists is_symlink variable is set if the file
* is a symlink
*/
static int
_file_exists(char *path)
{
struct stat buf;
if (stat(path, &buf)) {
if (errno == ENOENT) {
/* OK. this symlink was removed by somebody else */
return 0;
}else{
fprintf(stderr,"Error while stat'ing symlink %s: %s (%d)\n",
path, strerror(errno), errno);
return -1;
}
}
return 1;
}
static int
_symlink_exists(char *path)
{
struct stat buf;
if (lstat(path, &buf)) {
return 0;
}
if (!S_ISLNK(buf.st_mode)) {
return -1;
}
return 1;
}
static int
_create_locked_cmd(char *path, int cmd)
{
int ret = 0, fd;
struct flock flk;
fd = open(path, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (0 > fd) {
fprintf(stderr,"Error opening file %s: %s (%d)\n",
path, strerror(errno), errno);
return -1;
}
flk.l_whence = SEEK_SET;
flk.l_start = 0;
flk.l_len = 0;
flk.l_type = F_WRLCK;
do{
if (0 == (ret = fcntl(fd, cmd, &flk))) {
break;
} else if (EINTR != errno) {
fprintf(stderr,"Error locking file %s: %s (%d)\n",
path, strerror(errno), errno);
close(fd);
return -errno;
}
} while(EINTR == errno);
if (0 == ret)
return fd;
close(fd);
return ret;
}
static int
_is_locked(char *path)
{
int ret, fd;
struct flock flk;
memset(&flk, 0, sizeof(flk));
fd = open(path, O_RDONLY);
if (0 > fd) {
if (EEXIST == errno) {
return 0;
} else {
fprintf(stderr,"Error opening file %s: %s (%d)\n",
path, strerror(errno), errno);
return -1;
}
}
do{
if (0 == (ret = fcntl(fd, F_GETLK, &flk))) {
break;
}
} while(EINTR == errno);
if (ret) {
fprintf(stderr,"Error getting file lock information for %s: %s (%d)\n",
path, strerror(errno), errno);
return -1;
}
if (F_WRLCK == flk.l_type && SEEK_SET == flk.l_whence) {
return 1;
}
return 0;
}
int pmix_leader_is_alive(char *lname)
{
int ret, error;
char fname[FILENAME_MAX] = { 0 };
char lock_name[FILENAME_MAX] = { 0 };
ret = _symlink_exists(lname);
if (0 > ret) {
fprintf(stderr,"Error accessing symlink %s: %d:%s\n",
lname, error, strerror(error));
return -1;
}
if (0 > readlink(lname, fname, FILENAME_MAX - 1)) {
if (ENOENT == errno) {
/* Symlink was removed between _symlink_exists & readlink */
return 0;
} else {
fprintf(stderr,"Error reading symlink %s: %d:%s\n",
lname, error, strerror(error));
return -1;
}
}
snprintf(lock_name, FILENAME_MAX - 1, "%s.lock",fname);
ret = _file_exists(lock_name);
/* In case of fatal error (ret < 0) or file abscense */
if (0 >= ret)
return ret;
return _is_locked(lock_name);
}
void pmix_remove_leader_symlink(char *path)
{
int ret, is_symlink;
/* Check prior to go further */
ret = _symlink_exists(path);
if (0 > ret) {
fprintf(stderr,"FATAL error\n");
exit(1);
}
if (0 == ret) {
/* File was already deleted. Nothing to do */
return;
}
char lockname[FILENAME_MAX];
snprintf(lockname, FILENAME_MAX, "%s.lock", path);
int fd = pmix_create_locked_wait(lockname);
/* Check prior to go further */
ret = _symlink_exists(path);
if (0 > ret) {
fprintf(stderr,"FATAL error\n");
exit(1);
}
if (0 == ret) {
/* File was already deleted. Nothing to do */
goto exit;
}
if (pmix_leader_is_alive(path)) {
/* Somebody already took care about this */
goto exit;
}
if (unlink(path)) {
if (ENOENT != errno) {
fprintf(stderr, "unlink(%s): %s", path, strerror(errno));
exit(1);
}
}
exit:
close(fd);
}
int pmix_create_locked(char *path)
{
return _create_locked_cmd(path, F_SETLK);
}
int pmix_create_locked_wait(char *path)
{
return _create_locked_cmd(path, F_SETLKW);
}
#if 0
#define FPREFIX "test"
int main(int argc, char **argv)
{
char lockfile[FILENAME_MAX], basefile[FILENAME_MAX];
if (2 > argc) {
fprintf(stderr, "Not enough parameters\n");
exit(0);
}
snprintf(basefile, FILENAME_MAX, FPREFIX ".%s", argv[1]);
snprintf(lockfile, FILENAME_MAX, "%s.lock", basefile);
if (0 > _create_locked(lockfile)) {
fprintf(stderr, "Cannot create personal lock file %s\n", basefile);
exit(0);
}
int fd = open(basefile,O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd < 0) {
fprintf(stderr,"Cannot create basefile\n");
exit(0);
}
while(1) {
if (!pmix_leader_is_alive(FPREFIX)) {
pmix_remove_leader_symlink(FPREFIX);
if (!symlink(basefile, FPREFIX)) {
while(1) {
sleep(1);
}
}
}
sleep(1);
}
}
#endif