#include #include #include #include #include #include #include extern int errno; #include #include /* 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