Можно ли определить, открыт ли файл другой программой?

Для новичков как вообще в Linux, так и в конкретной теме, к которой относится вопрос.

Модератор: Bizdelnick

MiK13
Сообщения: 1263
ОС: Linux Debian

Можно ли определить, открыт ли файл другой программой?

Сообщение MiK13 »

Здравствуйте! Столкнулся с проблемой. Но сначала предыстория.
Поступило от заказчика задание: нужно доработать программу АРМа. Смысл доработки: по COM-порту поступает сообщение (4 байта, один из них -- код ошибки), получив которое нужно на экран вывести окно с информацией об ошибке.
Если бы АРМ был иксовый, я бы просто написал ещё одну программу, но во время разработки мы до иксов ещё не дошли, АРМ работает на Debian 4 и графика -- на svgalib. То есть пришлось дорабатывать и АРМ. Доработал. И написал довольно простую программу, которая принимает сообщение и записывает код в разделяемую память. А АРМ, обнаружив этот код, рисует дополнительное окно. Сброс -- по Escape.
Отправил им программы АРМа и proj_fka. Сказали, что fka не запускается -- нет библиотеки (собирал под Debian 7). Собрал с -static -- сказали всё работает. АРМ собрать с -static не удалось. Но он заработал (почти) без проблем.
Теперь об основной проблеме.
Сегодня позвонили: "Сообщения не показываются. Хотя раньше показывались". Приехал. Стал разбираться. Запускаю в режиме консоли -- не виду, чтобы по COM порту что-то приходило. Говорят, что ДОЛЖНО. Проверяю через dd if=/dev/tttyS0 bs=1 -- тоже ничего не вижу. Потом, вдруг, слышу: "У нас через этот порт подключены джойстик и клавиатура. Всё работает". И тут до меня доходит.
Выдаю pgrep -lf fk и вижу ещё два процесса rmo_fk. Говорят: "Это наша программа". Захожу в /proc/uid/fd и вижу
@3 -> /dev/ttyS0
То есть их программа открыла этот же COM порт и вся информация с него идёт ей.
Даю skill rmo_fk, запускаю свою программу -- всё "работает" (почти, в программе допустил одну маленькую ошибку, которую не мог найти, возясь по несколько часов в течение двух дней, сообразил, когда ждал троллейбус).
Но в моей программе

Код: Выделить всё

char *dev="/dev/ttyS0";
  if(!(f=fopen(dev,"r")))
    error(1,errno,"Error open file \"%s\"",dev);
не выдаёт никаких ошибок.

Поэтому и возник вопрос Если ли средства, позволяющие обнаружить, что файл уже открыт и сообщить об этом?
Этот вопрос на будущее. В данном случае сказал, что единственный вариант -- встраивать мой код в свою программу.
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение serzh-z »

MiK13 писал:
10.12.2018 23:56
Если ли средства, позволяющие обнаружить, что файл уже открыт и сообщить об этом?
См. flock и lockf.
Спасибо сказали:
Аватара пользователя
Vascom
Сообщения: 1699
ОС: Fedora 32

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение Vascom »

А как же lsof?
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21279
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение Bizdelnick »

Vascom писал:
11.12.2018 09:44
А как же lsof?
Он, как и fuser, не покажет информацию о процессах, к которым у пользователя нет права доступа.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
Vascom
Сообщения: 1699
ОС: Fedora 32

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение Vascom »

И правильно сделает.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21279
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение Bizdelnick »

Vascom писал:
11.12.2018 14:26
И правильно сделает.
С одной стороны — да, с другой стороны — это помешает решить данную задачу. Остаются блокировки, но с ними другая сложность: они должны использоваться обеими программами.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
MiK13
Сообщения: 1263
ОС: Linux Debian

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение MiK13 »

Vascom писал:
11.12.2018 09:44
А как же lsof?
Я попытался выдать lsof, но оказалось, что на том компьютере его нет.
serzh-z писал:
11.12.2018 01:29
См. flock и lockf.
Про flock я читал раньше, но, как я понял из man'а, он носит "рекомендательный характер", то есть он может только сказать, выдал ли его на этот же файл кто-то другой или нет.
И, похоже, единственным способом пока остаётся через popen выдать
"find /proc -type l -exec ls -l '{}' ';' | grep '/dev/ttyS0'" да и то, если там есть find.
Да и то в этом есть очень большие сомнения. По крайней мере я сейчас попробовал это сделать -- не получилось
И вообще, прежде, чем приступать к разработке программы, после получения задания от начальства надо пообщаться с программистами, которые также работают над данной системой, выяснить, с какими файлами и как они работают.
Спасибо сказали:
MiK13
Сообщения: 1263
ОС: Linux Debian

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение MiK13 »

Попробовал сейчас на своём компьютере find /proc -type l -exec ls -l '{}' ';' | grep '-> /dev/ttyS0' -- ничего не получилось.
Видимо, надо записывать lsof и проверять с помощью popen("lsof | grep /dev/ttyS0","r")
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21279
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение Bizdelnick »

MiK13, вы ж вроде сишник, чего Вы эти костыли из grep'ов городите?
Хотя в любом случае проблему Вы так не решите. Ну выполните Вы проверку перед открытием файла, а потом что? Где гарантия, что кто-нибудь не откроет его позднее, и не начнёт оттуда читать?
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
MiK13
Сообщения: 1263
ОС: Linux Debian

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение MiK13 »

Bizdelnick писал:
11.12.2018 16:37
MiK13, вы ж вроде сишник, чего Вы эти костыли из grep'ов городите?
Хотя в любом случае проблему Вы так не решите.
Конечно, полного решения этой задачи нет. Поэтому самый надёжный вариант -- перед сдачей в эксплуатацию обсудить совместно какая программа с чем работает.
А что касается "костылей из grep'ов"... я заметил, что довольно много функций из системных библиотек имеют аналоги из программ. И если есть возможность их использовать, что почему бы и нет? И предварительно с помощью bash'а проверить. А потом уже либо использовать system и popen, либо, если важна эффективность, уже на си самому реализовывать.
Bizdelnick писал:
11.12.2018 16:37
Ну выполните Вы проверку перед открытием файла, а потом что? Где гарантия, что кто-нибудь не откроет его позднее, и не начнёт оттуда читать?
Конечно гарантии никакой нет.То есть гарантия была бы, если бы Linux не позволял открывать уже открытые другими программами устройства-"каналы", то есть файлы, в которых данные не хранятся, а формируются, типа /dev/tty*. Потому, что получается, что сначала одна программа его открыла, потом другая, и кто должен получать данные?
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21279
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение Bizdelnick »

MiK13 писал:
11.12.2018 17:25
А что касается "костылей из grep'ов"... я заметил, что довольно много функций из системных библиотек имеют аналоги из программ. И если есть возможность их использовать, что почему бы и нет?
Потому что это уродливо и, в Ваших примерах, некорректно. За такое и в shell-скриптах руки отрывать надо, если уж откровенно. Что Вам выдаст lsof | grep /dev/ttyS0, Вы задумывались? Это вовсе не обязательно будет строка, в которой упоминается точно такой путь.
MiK13 писал:
11.12.2018 17:25
устройства-"каналы", то есть файлы, в которых данные не хранятся, а формируются, типа /dev/tty*.
Это не канал (FIFO), а символьное устройство. Суть, конечно, близка, но тип файла другой.
MiK13 писал:
11.12.2018 17:25
получается, что сначала одна программа его открыла, потом другая, и кто должен получать данные?
Кто первый попытается прочитать, тот и получит.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение serzh-z »

В рот мне ноги... Дайте мне развидеть решения из этой темы.

lockf поддерживает принудительные блокировки, при условии, что файловая система смонтирована с mand и на файл выставлен бит S_ISGID и снят S_IXGRP.

ioctl, в конце концов, умеет переводить терминал а эксклюзивный режим после открытия. См. TIOCEXCL.
Спасибо сказали:
MiK13
Сообщения: 1263
ОС: Linux Debian

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение MiK13 »

Bizdelnick писал:
11.12.2018 19:36
MiK13 писал:
11.12.2018 17:25
А что касается "костылей из grep'ов"... я заметил, что довольно много функций из системных библиотек имеют аналоги из программ. И если есть возможность их использовать, что почему бы и нет?
Потому что это уродливо и, в Ваших примерах, некорректно. За такое и в shell-скриптах руки отрывать надо, если уж откровенно. Что Вам выдаст lsof | grep /dev/ttyS0, Вы задумывались? Это вовсе не обязательно будет строка, в которой упоминается точно такой путь.
А что значит "уродливо"? Зачем писать десятки строк кода, если можно решить ту же задачу с помощью нескольких, используя системные программы?
Но в любом случае я все скрипты буду проверять руками. В максимально возможном числе (для конкретного случая) вариантов.
А lsof | grep /dev/ttyS0 я у себя проверял -- работает нормально.
Кстати, когда я вместо /dev/ttyS0 указал ссылку на него /dev/shm/aaa, данная команда выдала тот же результат.
Интересно, что когда я эту ссылку сделал не от рута, то программа fka, запущенная от рута, выдала ошибку доступа.
Bizdelnick писал:
11.12.2018 19:36
MiK13 писал:
11.12.2018 17:25
устройства-"каналы", то есть файлы, в которых данные не хранятся, а формируются, типа /dev/tty*.
Это не канал (FIFO), а символьное устройство. Суть, конечно, близка, но тип файла другой.
С точки зрения системы тип файла другой. Но суть, по-моему, такая же: байты данных не существуют постоянно в каком-то месте, а возникают и после их прочтения исчезают.
Bizdelnick писал:
11.12.2018 19:36
MiK13 писал:
11.12.2018 17:25
получается, что сначала одна программа его открыла, потом другая, и кто должен получать данные?
Кто первый попытается прочитать, тот и получит.
Как и случилось в данном случае. Когда стали говорить, что COM-порт работает, и они по нему получают данные от других устройств, я понял, что должна быть программа, которая до моей забирает данные. И когда я её увидел и снял, то моя программа заработала.

В общем я понял, что подобные проблемы надо решать только организационным путём,
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21279
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение Bizdelnick »

MiK13 писал:
11.12.2018 23:52
Зачем писать десятки строк кода, если можно решить ту же задачу с помощью нескольких, используя системные программы?
Ваше решение некорректно.
MiK13 писал:
11.12.2018 23:52
А lsof | grep /dev/ttyS0 я у себя проверял -- работает нормально.
Не надо его проверять, надо просто подумать. Как насчёт файла /home/user/dev/ttyS0? Или /dev/ttyS01?
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
MiK13
Сообщения: 1263
ОС: Linux Debian

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение MiK13 »

serzh-z писал:
11.12.2018 21:32
ioctl, в конце концов, умеет переводить терминал а эксклюзивный режим после открытия. См. TIOCEXCL.
Сделал:

Код: Выделить всё

  if(!(f=fopen(dev,"r")))
    error(1,errno,"Error open file \"%s\"",dev);
  fn=fileno(f);
  bg=ioctl(fn,TIOCEXCL);
  printf("ioctl(%d,0x%X)=%d\n",fn,TIOCEXCL,bg);
Запускаю программу -- печатает ioctl(3,0x540C)=0
Запускаю ещё раз (в другом окне -- печатает тоже самое.
lsof | grep /dev/ttyS0 выдаёт наличие двух процессов. Для обоих

Код: Выделить всё

root@MDD49:/proc/11713/fd# ls -l
итого 0
lrwx------ 1 root root 64 дек 12 01:06 0 -> /dev/pts/7
lrwx------ 1 root root 64 дек 12 01:06 1 -> /dev/pts/7
lrwx------ 1 root root 64 дек 12 01:06 2 -> /dev/pts/7
lr-x------ 1 root root 64 дек 12 01:06 3 -> /dev/ttyS0
l-wx------ 1 root root 64 дек 12 01:06 8 -> pipe:[1999342]
Различается только значение pid и число после pipe: (что это -- не знаю, но предполагаю, что очередь сообщений)
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение serzh-z »

MiK13
Эксклюзивный режим не распространяется на процессы рута.
Спасибо сказали:
MiK13
Сообщения: 1263
ОС: Linux Debian

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение MiK13 »

serzh-z писал:
12.12.2018 01:55
MiK13
Эксклюзивный режим не распространяется на процессы рута.
В этом и проблема.
Все вспомогательные программы запускаются до программы login. А программа АРМа, работающая через svgalib, также должна запускаться с привилегиями рута. Впрочем, программа, читающая из COM порта тоже.
Хотя... наверно, можно просто добавить пользователя в группу dialout. Проверю, сработает ли это.
Bizdelnick писал:
12.12.2018 00:22
Как насчёт файла /home/user/dev/ttyS0? Или /dev/ttyS01?
А что это за файлы?

P.S. Проверил.
Добавил себя в группу dialout. После этого программа стала запускаться не от рута.
Установил TIOCEXCL. От рута ещё одна копия запустилась. А вот от себя -- нет: Error open file "/dev/ttyS0": Device or resource busy
То есть проблема, в принципе, решаема, но только в принципе. Нужна договорённость между разными разработчиками. А её не было :(
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21279
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение Bizdelnick »

MiK13 писал:
12.12.2018 11:14
А что это за файлы?
mkdir ~/dev
cat > ~/dev/ttyS0

Кто мешает так сделать? Я нашёл DoS-уязвимость в Вашей программе, платите мне.
MiK13 писал:
12.12.2018 11:14
Нужна договорённость между разными разработчиками.
Договорённость ничем не поможет. С одним устройством должна работать одна программа, и всё тут. Если нужно несколько, они должны делать это через прослойку-драйвер.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
MiK13
Сообщения: 1263
ОС: Linux Debian

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение MiK13 »

Bizdelnick писал:
12.12.2018 11:26
MiK13 писал:
12.12.2018 11:14
А что это за файлы?
mkdir ~/dev
cat > ~/dev/ttyS0

Кто мешает так сделать?
При реальной эксплуатации пользователи не должны знать пароль рута. А пользователи не имеют доступа к командам.
Кроме того, программы работают с конкретным устройством -- /dev/ttyS0.
Bizdelnick писал:
12.12.2018 11:26
MiK13 писал:
12.12.2018 11:14
Нужна договорённость между разными разработчиками.
Договорённость ничем не поможет. С одним устройством должна работать одна программа, и всё тут. Если нужно несколько, они должны делать это через прослойку-драйвер.
Я имел ввиду договорённость кто с каким устройством и как будет работать.
Из исходного задания, "надо при получении информации через последовательный порт выдать на экран сообщение" не было ясно, что с этим портом уже работает другая программа.
Поэтому и надо договариваться, как это всё будет работать. И тут возможны варианты.
  1. Одна программа, которая принимает данные и в зависимости от их значений вызывает различные функции. которые могут писать разные люди.
  2. (Пока только мысль). Программа принимает данные и, в зависимости от их содержания, "раскидывает" их по разным "трубам". Из которых эти данные читают другие программы
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21279
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение Bizdelnick »

MiK13 писал:
12.12.2018 12:10
При реальной эксплуатации пользователи не должны знать пароль рута.
Так для этого не нужно быть рутом.
MiK13 писал:
12.12.2018 12:10
программы работают с конкретным устройством -- /dev/ttyS0
О чём я и говорю. Программа работает с конкретным устройством, а проверка может среагировать на другие файлы.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
MiK13
Сообщения: 1263
ОС: Linux Debian

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение MiK13 »

Bizdelnick писал:
12.12.2018 12:27
MiK13 писал:
12.12.2018 12:10
программы работают с конкретным устройством -- /dev/ttyS0
О чём я и говорю. Программа работает с конкретным устройством, а проверка может среагировать на другие файлы.
Понял. Но и от этого, в принципе, можно защититься, если грепать не по "/dev/ttyS0", а по " /dev/ttyS0"
Правда, и это можно обойти с помощью mkdir -p "/home/user/123 /dev"
Но
Bizdelnick писал:
12.12.2018 12:27
MiK13 писал:
12.12.2018 12:10
При реальной эксплуатации пользователи не должны знать пароль рута.
Так для этого не нужно быть рутом.
Там не должно быть пользователей, которые имеют прямой доступ к /bin/sh или чему-то подобному.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21279
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение Bizdelnick »

MiK13 писал:
12.12.2018 16:03
Там не должно быть пользователей, которые имеют прямой доступ к /bin/sh или чему-то подобному.
Чего точно не должно быть, так это допущений, что на пользовательской системе чего-то не будет.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
MiK13
Сообщения: 1263
ОС: Linux Debian

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение MiK13 »

Bizdelnick писал:
12.12.2018 16:55
Чего точно не должно быть, так это допущений, что на пользовательской системе чего-то не будет.
В принципе да. Если компьютер работает в сети и используется для решения разных задач, которые могут меняться. Причём, решаемые задачи определяет сам пользователь.
В данном же случае, это система, в которой решается ряд конкретных задач. Основная -- наблюдение за работой приборов. Вспомогательные -- копирование протоколов на флешку, а также добавление, удаление пользователей (операторов), задание им паролей, У всех пользователей uid=0, а shell -- конкретный скрипт.
И не исключаю, что пользователи, которые операторы -- те, что могут считать, что "линукс" -- неправильно, а правильно -- "линекс" :)
А задача, о которой я написал в начале -- это на этапе отладки.
И я не уверен, что не потерял бы больше времени, если бы, выдав pgrep -lf fk, не увидел, кроме своей, ещё и rmo_fk, которая также принимала данные по этому порту.
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение serzh-z »

MiK13 писал:
12.12.2018 11:14
От рута ещё одна копия запустилась.
В обычном случае, приложение запущенное от root должно понижать свои привилегии до обычного пользователя (с помощью setegid и seteuid).
Спасибо сказали:
MiK13
Сообщения: 1263
ОС: Linux Debian

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение MiK13 »

serzh-z писал:
13.12.2018 01:03
В обычном случае, приложение запущенное от root должно понижать свои привилегии до обычного пользователя (с помощью setegid и seteuid).
Спасибо, запомню.
Но всё, что я писал, годится только для случая, если и другие программы будут это использовать.
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu

Re: Можно ли определить, открыт ли файл другой программой?

Сообщение serzh-z »

MiK13 писал:
13.12.2018 01:16
только для случая, если и другие программы будут это использовать.
Если ещё не понятно - в POSIX и Linux нет другого более вменяемого и современного механизма блокировок. При использовании только лишь DAC, root - это бог всего и так просто защитить себя самого от себя же он не может.
Спасибо сказали: