Lseek SEEK_END не работает?

Я работаю над программой C с джойстиками, и я хотел бы получить последнее событие, которое является последней строкой файла js0. Я пытаюсь переместить курсор перед последним элементом, но это не работает. Есть идеи, почему?

int fd = open ("/dev/input/js0", O_RDONLY);
struct js_event e;
lseek(fd, -(sizeof(e)), SEEK_END);    
read (fd, &e, sizeof(e));
switch(e.type){
    case JS_EVENT_BUTTON: printf("btn\n");
    break;
    case JS_EVENT_AXIS: printf("axes\n");
    break;
    default: printf("smth else\n");
}

Я уверен, что файл, который я читаю, имеет длину не менее (sizeof(e)). Lseek возвращает мне -1, поэтому я получил errno, и это было 29 - Недопустимый поиск: почему это должен быть незаконный поиск? Я получаю те же результаты, даже если использую 0 в качестве смещения

  lseek(fd, 0, SEEK_END)

Я использую последнюю версию Ubuntu, спасибо за вашу помощь


person Dariooo    schedule 13.06.2017    source источник
comment
Вы проверили fd возврат из open, чтобы узнать, не возникла ли ошибка при открытии файла? Вы всегда должны проверять наличие ошибок в своем системном вызове... на всякий случай.   -  person lurker    schedule 13.06.2017
comment
Что показывает ls -l /dev/input/js0? Вы уверены, что /dev/input/js0 является поисковым устройством?   -  person Andrew Henle    schedule 13.06.2017
comment
@andrew Я получил это crw-rw-r--+ 1 root input 13, 0 giu 13 21:10 /dev/input/js0, и я думаю, что giu означает июнь (я итальянец). Что означает поисковое устройство? Я работаю над файлом, поэтому, по моему мнению, я должен иметь возможность перемещаться по нему. Извините, но я не очень хорошо разбираюсь в C, однако, спасибо, ребята!   -  person Dariooo    schedule 13.06.2017
comment
Как подразумевал @AndrewHenle, не все файлы доступны для поиска. Некоторые из них могут быть прочитаны только последовательно, и файл устройства, содержащий события джойстика, скорее всего, относится к категории недоступных для поиска.   -  person John Bollinger    schedule 13.06.2017
comment
@luker вы правы, спасибо, однако открытие не было проблемой, потому что я могу прочитать файл. Моя проблема в том, что lseek делает не то, что я думал   -  person Dariooo    schedule 13.06.2017
comment
Спасибо @john! Любое предложение о том, как я могу получить последнюю строку? У меня нет никакой другой идеи, кроме чтения построчно, пока я не найду какой-то EOF (есть ли какой-либо EOF для файлов, недоступных для поиска?)   -  person Dariooo    schedule 14.06.2017


Ответы (1)


почему это должно быть незаконным поиском?

Файл, который вы пытаетесь прочитать, является специальным символьным файлом (на что указывает 'c' в первой позиции его строки режима), с помощью которого драйвер джойстика ядра может взаимодействовать с программами пользовательского пространства, такими как ваша. Такие файлы подобны каналам — поиск по ним невозможен. Любая попытка найти другую позицию в таком файле потерпит неудачу, и некоторые реализации lseek() могут потерпеть неудачу, даже если аргументы соответствуют нулевому изменению чистой позиции. Дополнительную информацию о файлах устройств можно найти здесь: Что такое специальные символы и специальные файлы блоков в системе unix?

В комментариях вы спросите

Любое предложение о том, как я могу получить последнюю строку?

, но вряд ли это то, что вы на самом деле хотите. В таком файле, который представляет канал связи, достижение конца файла (чтобы можно было распознать последнюю строку) означает, что канал закрыт и все данные из него считаны. Через этот файловый дескриптор никакие данные больше никогда не будут доступны. В вашем случае при обычных обстоятельствах этого не произойдет. И я сомневаюсь, что это то, что вы надеетесь увидеть.

Я думаю, что вы хотите обнаружить самое последнее событие, доступное с устройства-джойстика, и это концептуально просто: вы читаете события с устройства до тех пор, пока чтение не заблокируется или не подойдет. Документация ядра Linux для используемого вами устройства содержит несколько советов, как избежать блокировки на неопределенный срок:

  • Используйте select(), чтобы определить, доступны ли данные с устройства, прежде чем пытаться их прочитать.

  • Откройте устройство в неблокирующем режиме (т. е. с параметром O_NONBLOCK) и будьте готовы к тому, что ваши read() сломаются (возвратится -1) с errno, установленным на EAGAIN.

Обратите внимание, что вам в любом случае следует проверять возвращаемое значение из read(), и что существует по крайней мере еще один режим сбоя, который не обязательно является подлинной ошибкой (EINTR). Прочтите эту справочную страницу, а также другие функции, которые вы используете, для получения подробной информации, подобной этой.

person John Bollinger    schedule 13.06.2017
comment
Большое спасибо @John, я действительно понятия не имел, что происходит, но теперь у меня есть полная карта того, что делать! постараюсь как можно скорее - person Dariooo; 14.06.2017
comment
Оно работает!! Большое спасибо @john! Могу я задать вам еще один вопрос? Должен ли я закрывать js0 в конце программы или нет? Я нигде не читал, но обычно закрываю каждый прочитанный файл - person Dariooo; 14.06.2017
comment
@ Dariooo, это хорошая привычка закрывать каждый файл, как только он вам больше не нужен, и я благодарю вас за это. Однако на самом деле всякий раз, когда процесс завершается, все его оставшиеся открытые файловые дескрипторы автоматически закрываются системой. Таким образом, вам не нужно беспокоиться о последствиях, если ваша программа выйдет из строя или будет принудительно завершена. - person John Bollinger; 14.06.2017