/* This file is part of Bolixo. Bolixo is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Bolixo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Bolixo. If not, see . */ /* This is a small utility to control exclusive access to a resource. It does that with a symbolic link. Symbolic links are atomics. You can use them to create-and-set a value. In this program, the value is a process id (PID). The logic goes like this if symlink-lock path_of_the symlink out_PID then we are good to proceed else can't process, exit fi The sequence to establish the lock goes like this Test if the link exist by performing a readlink(). If it exists, check if the PID exists. If it exists, but the PID does not, unlink it If it exists, we exit (and fail). If it does not exist, we create the symlink with the PID. If it fail, we fail. ..... The flock utility does a better job. So this is not worth it. There are races with the symlinks. */ #include #include #include #include #include #include #include #include #include #include #include "../helper.h" using namespace std; static int make_link (const char *path, unsigned pid) { int ret = -1; string pid_str = string_f("%u",pid); if (symlink(pid_str.c_str(),path)==0){ ret = 0; }else if (is_any_of(errno,EPERM,EINVAL)){ // We fail, but for bad reason tlmp_error ("Can't set the symlink %s (%s)\n",path,strerror(errno)); }else{ // Fail. The link was not there but we can't set ours // so someone else did it in the meantime. } return ret; } int main (int argc, char *argv[]) { glocal int ret = -1; glocal unsigned pid = 0; glocal.ret = (argc,argv); setproginfo ("symlink-lock",VERSION,"Utility to establish exclusive access to a resource"); setarg ('p',"pid","Process ID of the caller",glocal.pid,true); int ret = -1; if (argc != 1){ usage(); }else{ const char *path = argv[0]; char buf[PATH_MAX]; auto size = readlink (path,buf,sizeof(buf)-1); if (size == -1){ // No link, we set ours debug_printf ("No lock, we place our own\n"); ret = make_link (path,glocal.pid); }else{ buf[size] = '\0'; debug_printf ("lock owned by pid %s\n",buf); if (size > 5){ // Odd, this symlink is not a PID. tlmp_error ("Symlink %s already exist with an odd value: %s\n",path,buf); }else{ unsigned pid = atoi(buf); if (kill(pid,0)==-1){ // PID does not exist debug_printf ("Old lock, process gone, we put our own\n"); unlink(path); ret = make_link (path,glocal.pid); }else{ debug_printf ("Process owning lock is still active, can't set lock\n"); } } } } return ret; return glocal.ret; }