/* $Id$ * * This file is part of pgets. * * pgets 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 2 of the License, or (at your * option) any later version. * * pgets 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 pgets; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #define _GNU_SOURCE #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "lock.h" #include "util.h" #ifndef LOCKDIR #define LOCKDIR "/var/lock" #endif static const char *lockfile(const char *dev) { static char lockfile[PATH_MAX]; snprintf(lockfile, sizeof(lockfile), LOCKDIR"/LCK..%s", basename((char*) dev)); return lockfile; } static const char *tempfile(const char *path) { static char t[PATH_MAX]; snprintf(t, sizeof(t), "%s.tmp.%lu", path, (unsigned long) getpid()); return t; } int device_lock(const char *dev, const char *appname) { struct stat st; int fd; const char *path, *temp; char buf[100]; char uidbuf[32]; uid_t uid; if (stat(LOCKDIR, &st) != 0 || !S_ISDIR(st.st_mode)) { fprintf(stderr, "Failed to lock device, directory "LOCKDIR" not existent.\n"); return -1; } path = lockfile(dev); temp = tempfile(path); for (;;) { mode_t u; struct passwd* pw; char *username; if ((fd = open(path, O_RDONLY)) < 0) { if (errno != ENOENT) { fprintf(stderr, "Failed to open lock file: %s\n", strerror(errno)); return -1; } } if (fd >= 0) { ssize_t n; n = loop_read(fd, buf, sizeof(buf) - 1); close(fd); if (n < 0) { close(fd); fprintf(stderr, "Failed to read from lock file: %s\n", strerror(errno)); return -1; } if (n > 0) { pid_t pid; if (n == 4) pid = (pid_t) *((uint32_t*) buf); else { unsigned long v; buf[n] = 0; sscanf(buf, "%lu", &v); pid = (pid_t) v; } if (pid > 0) { if (kill(pid, 0) < 0 && errno == ESRCH) { fprintf(stderr, "Lockfile is stale. Overriding it.\n"); /* Yes, here is a race condition */ unlink(path); } else return 1; } } } u = umask(0033); fd = open(temp, O_WRONLY | O_CREAT | O_EXCL, 0666); umask(u); if (fd < 0) { fprintf(stderr, "Failed to create temporary lock file: %s\n", strerror(errno)); return -1; } uid = getuid(); if ((pw = getpwuid(uid))) username = pw->pw_name; else snprintf(username = uidbuf, sizeof(uidbuf), "%lu", (unsigned long) uid); snprintf(buf, sizeof(buf), "%10lu %s %.20s\n", (unsigned long) getpid(), appname, username); if (loop_write(fd, buf, strlen(buf)) < 0) { fprintf(stderr, "Failed to write to temporary lock file: %s\n", strerror(errno)); close(fd); return -1; } close(fd); if (link(temp, path) < 0) { if (errno == EEXIST) continue; fprintf(stderr, "Failed to link temporary lock file: %s\n", strerror(errno)); } unlink(temp); return 0; } } int device_unlock(const char *dev) { if (unlink(lockfile(dev)) < 0) { fprintf(stderr, "Failed to remove lock file: %s\n", strerror(errno)); return -1; } return 0; }