/* -------------------------------------------------------------------- */ /* SMS Client, send messages to mobile phones and pagers */ /* */ /* lock.c */ /* */ /* Copyright (C) 1997,1998,1999 Angelo Masci */ /* */ /* This library is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU Library General Public */ /* License as published by the Free Software Foundation; either */ /* version 2 of the License, or (at your option) any later version. */ /* */ /* This library 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 */ /* Library General Public License for more details. */ /* */ /* You should have received a copy of the GNU Library General Public */ /* License along with this library; if not, write to the Free */ /* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* */ /* You can contact the author at this e-mail address: */ /* */ /* angelo@styx.demon.co.uk */ /* */ /* -------------------------------------------------------------------- */ /* $Id$ -------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include "logfile/logfile.h" #include "lock.h" #include "common/common.h" /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static pid_t resource_lock_pid(char *resource_lockfile) { int lock_fd, i, eof; pid_t pid; char buf[512], c; lock_fd = open(resource_lockfile, O_RDONLY); if (lock_fd == -1) { return(-1); } eof = FALSE; i = 0; while((i < 11) && (eof == FALSE)) { switch (read(lock_fd, &c, 1)) { case 1: buf[i] = c; i++; break; case -1: if (errno != EINTR) { lprintf(LOG_ERROR, "Reading pid from lockfile '%s'\n", resource_lockfile); exit(-1); } break; case 0: eof = TRUE; } } buf[i] = '\0'; if (sscanf(buf, "%10d\n", &pid) != 1) { pid = -1; } close(lock_fd); return pid; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ int resource_unlock(char *resource_lockfile) { pid_t pid; pid = resource_lock_pid(resource_lockfile); if (pid == getpid()) { lprintf(LOG_VERBOSE, "Removing Lockfile '%s'\n", resource_lockfile); unlink(resource_lockfile); } return 0; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static int file_exists(char *filename) { struct stat stat_buf; if (stat(filename, &stat_buf) == -1) { return -1; } if (! S_ISREG(stat_buf.st_mode)) { return -1; } return 0; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static int directory_exists(char *filename) { struct stat stat_buf; if (stat(filename, &stat_buf) == -1) { return -1; } if (! S_ISDIR(stat_buf.st_mode)) { return -1; } return 0; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ int resource_locked(char *resource_lockfile) { pid_t pid; #if 0 if (access(resource_lockfile, F_OK) == 0) #else if (file_exists(resource_lockfile) == 0) #endif { /* lockfile exists */ pid = resource_lock_pid(resource_lockfile); if (pid != -1) { /* Is there a process with this pid? */ if (kill(pid, 0) == 0) { return -1; /* Process exists */ } else { if (errno == EPERM) { return -1; /* Process exists */ } } /* Process does not exist */ /* we can unlink this lockfile as */ /* it is stale. */ lprintf(LOG_VERBOSE, "Removing Stale Lockfile '%s'\n", resource_lockfile); unlink(resource_lockfile); return 0; } else { /* Could not determine PID of */ /* owner of this lockfile! */ return -1; } } /* No process holds the lock */ return 0; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ int resource_lock(char *resource_lockfile) { int lock_fd, i, len; char buf[64]; if (resource_locked(resource_lockfile) == 0) { lock_fd = open(resource_lockfile, O_CREAT|O_WRONLY|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if (lock_fd == -1) { if (errno == EEXIST) { /* Could not create lockfile */ /* A lockfile already exists */ /* The most likely reason for */ /* this is another process */ /* generating one after our */ /* call to resource_locked() */ return -1; } lprintf(LOG_ERROR, "Cannot create lockfile %s\n", resource_lockfile); exit(-1); } len = sms_snprintf(buf, 64, "%10d sms_client\n", (int)getpid()); i = 0; while(i < len) { switch (write(lock_fd, &buf[i], 1)) { case 1: i++; break; case -1: if (errno != EINTR) { lprintf(LOG_ERROR, "Reading pid from lockfile '%s'\n", resource_lockfile); exit(-1); } } } chmod(resource_lockfile, S_IRUSR|S_IRGRP|S_IROTH); close(lock_fd); /* Created lockfile with this pid */ lprintf(LOG_VERBOSE, "Created Lockfile '%s'\n", resource_lockfile); return 0; } /* Could not create lockfile */ return -1; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ int resource_wait(char *resource_lockfile, long delay) { libcommon_usleep(delay); /* Sleep between checks on the */ /* lockfile. */ /* What would be really nice would */ /* be a way to block and return if */ /* the attributes on the lockfile */ /* change. */ return 0; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ int resource_test_lockdir(char *resource_lockfile) { char *lock_dir, *ptr; lock_dir = strdup(resource_lockfile); if (lock_dir == NULL) { return -1; } ptr = strrchr(lock_dir, '/'); if (ptr != NULL) { *ptr = '\0'; } else { strcpy(lock_dir, "."); } if (directory_exists(lock_dir) == -1) { lprintf(LOG_ERROR, "Cannot access lock directory '%s'\n", lock_dir); free(lock_dir); return -1; } free(lock_dir); return 0; }