Как описано на странице man 2 fcntl
, вы можете использовать F_GETLK
для получить идентификатор процесса с конфликтующей блокировкой (если конфликтующая блокировка связана с процессом). Так, например,
/* Return 0 if descriptor locked exclusively, positive PID if
a known process holds a conflicting lock, or -1 if the
descriptor cannot be locked (and errno has the reason).
*/
static pid_t lock_exclusively(const int fd)
{
struct flock lock;
int err = 0;
if (fd == -1) {
errno = EINVAL;
return -1;
}
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if (!fcntl(fd, F_SETLK, &lock))
return 0;
/* Remember the cause of the failure */
err = errno;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
lock.l_pid = 0;
if (fcntl(fd, F_GETLK, &lock) == 0 && lock.l_pid > 0)
return lock.l_pid;
errno = err;
return -1;
}
Обратите внимание, что fd
должен быть открыт для чтения и записи. Я рекомендую использовать open(path, O_RDWR | O_NOCTTY)
или open(path, O_WRONLY | O_NOCTTY)
. Закрытие любого файлового дескриптора для того же файла снимет блокировку.
Кто-то может сказать, что переустановка lock
участников перед вторым fcntl()
вызовом не нужна, но я бы предпочел проявить осторожность.
Что касается того, как сообщить об этом, я бы просто использовал
int fd;
pid_t p;
fd = open(path, O_RDWR | O_NOCTTY);
if (fd == -1) {
fprintf(stderr, "%s: Cannot open file: %s.\n",
path, strerror(errno));
exit(EXIT_FAILURE);
}
p = lock_exclusively(fd);
if (p < 0) {
fprintf(stderr, "%s: Cannot lock file: %s.\n",
path, strerror(errno));
exit(EXIT_FAILURE);
} else
if (p > 0) {
fprintf(stderr, "%s: File is already locked by process %ld.\n",
path, (long)p);
exit(EXIT_FAILURE);
}
/* fd is now open and exclusive-locked. */
Пользователь всегда может запустить, например. ps -o cmd= -p PID
, чтобы узнать, что это за команда (или вы можете попробовать прочитать /proc/PID/cmdline
в Linux).
person
Nominal Animal
schedule
17.07.2018