- Работа с файлами устройств (запись и IOCTL)
- How to write to a character special device?
- 1 Answer 1
- How to write the output into the file in Linux
- How do I save terminal output to a file?
- Writing the output into the file
- Appending the output or data to the file
- How to save the output of a command to a file in bash using tee command
- Examples
- I/O redirection summary for bash and POSIX shell
- Conclusion
- How to read/write to tty* device?
- 1 Answer 1
- Как написать свой первый Linux device driver. Часть 2
- Функция scull_open
- Функция scull_read
- Функция scull_write
- Опрос
Работа с файлами устройств (запись и IOCTL)
Файлы устройства представляют физические устройства. Многие физические устройства используются для вывода и для ввода, так должен иметься некоторый механизм для драйверов устройства в ядре, чтобы послать вывод устройству из процесса. Это выполняется, открывая файл устройства для вывода и записывая в него точно так же, как в обычный файл. В следующем примере, это выполнено функцией device_write .
Этого не всегда достаточно. Вообразите, что Вы имеете последовательный порт, связанный с модемом (даже если Вы имеете внутренний модем, он выглядит с точки зрения CPU как последовательный порт, связанный с модемом, так что Вы не должны слишком сдерживать Ваше воображение). Естественное решение использовать файл устройства, чтобы передавать модему команды модема или данные, которые будут посланы через телефонную линию и читать из модема ответы для команд или данные, полученные через телефонную линию. Однако, это оставляет открытым вопрос о том что делать, когда Вы должны работать с последовательным портом непосредственно, например настроить скорость обмена данными с портом.
Ответ в Unix должен использовать специальную функцию, названную ioctl (сокращение от i nput o utput c on t ro l ). Каждое устройство может иметь собственные команды ioctl , которые могут читать ioctl (для передачи данных от процесса ядру), записывать ioctl (чтобы возвратить информацию процессу), 5.1 , выполнять оба действия или ни одно из них. Функция ioctl вызывается с тремя параметрами: описатель файла соответствующий файлу устройства, ioctl номер, и параметра, который имеет тип long, так что Вы можете использовать приведение, чтобы передать что-нибудь. 5.2
Ioctl номер кодирует главный номер устройства, тип ioctl команды и тип параметра. Этот ioctl номер обычно создается макрообращением ( _IO , _IOR , _IOW или _IOWR : в зависимости от типа) в файле заголовка. Этот файл заголовка должен быть присоединен командой #include программой, которая использует ioctl и модулем (так что они могут генерировать соответствующие ioctl ). В примере ниже, файл заголовка chardev.h и программа, которая использует это ioctl.c .
Источник
How to write to a character special device?
Due to a broken udev setup on a machine from which I’m trying to rescue data (see this post of mine) I’m trying to write to a «character special» device corresponding to a USB flash drive, but am encountering difficulty.
What I would expect is that (with root permissions) I could do this:
What’s going on? How can I write to a character device?
P.S.: this is of interest specifically because the block devices I would normally expect ( /dev/sdb , stuff in /dev/block ) aren’t being created for some reason. Yet I noticed that a character device does get created when I insert a USB drive (and removed when I remove it). If I could find some way to write to that device I could save myself a lot of trouble transferring data slowly over audio cables (which is my current best approach).
1 Answer 1
Those are «raw USB» devices. Using them requires several USB-specific ioctl() functions: just writing raw data into them from the shell is unlikely to accomplish much at all. The data would have to be formatted into valid USB packets first, and the ioctl() functions used to establish connection to the right USB endpoint within that device.
And since we’re talking about a USB storage device, the procedure would be even more complicated: withing those USB packets, there should be one of six possible storage command sets. In practice, the overwhelmingly most common command set is the «SCSI transparent» command set — a SCSI protocol wrapped into USB.
As a result, you would first have to learn how to write onto a disk device using /dev/sg* devices, by crafting your own SCSI command packets. Once you achieved that, you could add USB-specific wrappers onto that procedure, and only then you might be able to write raw blocks onto a USB storage device using those /dev/bus/usb/ / devices.
In most cases, using raw USB ioctl() s is extremely tedious unless you need something very specific: most programmers needing raw USB access will use libusb or some other library (like libftdi for hardware-developer-level access to FTDI USB-to-serial converter chips) to handle the base mechanics of USB for them. In short, you would have to already be a pretty well established USB I/O programmer to successfully use raw USB storage device in a rescue situation such as yours.
Having said that, your other post looks like you’ve had to pull off a truly epic data rescue operation. For that, I respect your achievement. but I also hope you’ve learned something about the importance of backups.
Источник
How to write the output into the file in Linux
How do I save terminal output to a file?
A command can receive input from a file and send output to a file.
Writing the output into the file
The syntax is
command > filename
For example, send output of the ls command to file named foo.txt
$ ls > foo.txt
View foo.txt using the cat command:
$ cat foo.txt
Please note that when you type ‘ls > foo.txt’, shell redirects the output of the ls command to a file named foo.txt, replacing the existing contents of the file. In other words, the contents of the file will be overwritten.
Appending the output or data to the file
The syntax is
command >> filename
For example the following will append data:
- No ads and tracking
- In-depth guides for developers and sysadmins at Opensourceflare✨
- Join my Patreon to support independent content creators and start reading latest guides:
- How to set up Redis sentinel cluster on Ubuntu or Debian Linux
- How To Set Up SSH Keys With YubiKey as two-factor authentication (U2F/FIDO2)
- How to set up Mariadb Galera cluster on Ubuntu or Debian Linux
- A podman tutorial for beginners – part I (run Linux containers without Docker and in daemonless mode)
- How to protect Linux against rogue USB devices using USBGuard
Join Patreon ➔
Verify it:
cat /tmp/data.txt
How to save the output of a command to a file in bash using tee command
The tee command read from standard input and write to standard output and files. The syntax is as follows for writing data into the file:
command | tee file.txt
Want to append data? Try
command | tee -a output.txt
Examples
Display output of the date command on screen and save to the file named /tmp/output.txt. If the output.txt already exists, it gets overwritten:
$ date | tee /tmp/output.txt
$ cat /tmp/output.txt
Same as above but append to the given files, do not overwrite file:
$ pwd | tee -a /tmp/test.txt
$ echo «Today is $(date)» | tee -a /tmp/test.txt
$ hostnamectl | tee -a /tmp/test.txt
$ cat /tmp/test.txt
The above commands will append the output to the end of the file, just like the shell >> operator as explained earlier.
I/O redirection summary for bash and POSIX shell
Shell operator | Description | Overwrite existing file? |
---|---|---|
command > output.txt | Save terminal output (standard output) to a file named output.txt | Yes |
command >> output.txt | Append terminal output (standard output) to a file named output.txt | No |
command | Takes standard input from output.txt file | N/A |
command 0 | Takes standard input from output.txt file | N/A |
command 1> output.txt | Puts standard output to output.txt file | Yes |
command 1>> output.txt | Appends standard output to output.txt | No |
command 2> output.txt | Puts standard error to output.txt | Yes |
command 2>> output.txt | Appends standard error to output.txt file | No |
command &> output.txt | Puts both standard error and output to output.txt | Yes |
command > output.txt 2>&1 | <POSIX> Puts both standard error and output to file named output.txt | Yes |
command &>> output.txt | Appends both standard error and output to file named output.txt | No |
command >> output.txt 2>&1 | <POSIX> Appends both standard error and output to file called output.txt | No |
command | tee output.txt | Puts standard output to output.txt while displaying output on screen | Yes |
command | tee -a output.txt | Appends standard output to output.txt while displaying output on screen | No |
command |& tee output.txt | Puts both standard output and error to output.txt while displaying output on terminal | Yes |
command 2>&1 | tee output.txt | <POSIX> Puts both standard output and error to file named output.txt while displaying output on terminal | Yes |
command |& tee -a output.txt | Append both standard output and error to file called output.txt while displaying output on terminal | No |
command 2>&1 | tee -a output.txt | <POSIX> Append both standard output and error to file named output.txt while displaying output on terminal | No |
Conclusion
You learned how to write the output to the file in Linux or Unix-like system when using bash or POSIX shell. We have:
- /dev/stdin (standard input) — File descriptor 0 is duplicated.
- /dev/stdout (standard output) — File descriptor 1 is duplicated.
- /dev/stderr (standard error) — File descriptor 2 is duplicated.
See I/O redirection documentation for more information. We can read bash man page as follows using the man command:
man bash
🐧 Get the latest tutorials on Linux, Open Source & DevOps via
Источник
How to read/write to tty* device?
I have a device that sends information over USB to my computer. Arch Linux sets up this device by creating a file named ttyUSB0 in /dev/ . I have been using GTKterm to receive this incoming information and display it in an emulated terminal window.
My question is, how exactly does GTKterm read/write to this ttyUSB0 file, and where might I start learning how to implement similar functionality? That is, in the most basic form, how might I write a character to ttyUSB0 , or, in contrast, receive a byte and write it to a file?
strupp/serial.html : open(), read(), write() and select(). Nothing special, it seems.
1 Answer 1
TTYs are files that you can use just like any other. You can open them with the standard file-opening tools of your language and read or write from them. They have some special behaviour that’s different to «ordinary» files, but the basics are the same. I’ll cover some of the special cases at the end, but first, an experiment.
One interesting thing you can do straight from a regular terminal. Run tty and it will print a line like:
That’s the TTY device your terminal is running in. You can write something to that terminal:
You can even read from it:
( read X is sh’s «read a line from standard input into variable X» command; the screen or xterm , you can run run echo spooky > /dev/pts/2 in that shell to make the text appear on your original terminal, and the same for the other commands. All of this is just your shell opening a file without knowing it’s a TTY.
Here is a very simple C program that does just what you asked, and writes a single character to /dev/pts/3, then reads a single byte back from it:
A real TTY device that’s attached to a shell or terminal emulator will have interesting behaviour there, but you should get something back.
To access a terminal you need to have permission to use it. Those are just the standard file permissions you see with ls -l and set with chmod : you need read permission to open the file and read it, and write permission to write into it. The TTYs that back your terminal will be owned by you, but another user’s TTY won’t, and TTYs for USB devices may or may not be, depending on your configuration. You can change the permissions in the same way as always.
As far as writing a program to work with it goes, you don’t need to do much special. You can see in the example that one thing you don’t need to do is close the file every time to have your data read by the other end: the TTY files act like pipelines, just pushing data in both directions as it comes in. When I wrote text to the TTY it appeared immediately, and when I read from it afterwards there wasn’t anything waiting for me already. It’s not like writing to a regular file where the data gets saved on disk — it gets passed on immediately to the other side, or stored in memory until someone reads it.
You may want to use the select function so that you can do other things while you wait for the device to say something, but if you’re happy to just wait for data to come through you can just use blocking reads and let the OS do the lifting.
One thing to keep in mind is that there is can be limited buffer size in the kernel, and if you write a lot of data at once you may end up blocking without meaning to. If that’s likely to be a problem, use non-blocking IO with open(«/dev/. «, O_RDWR | O_NONBLOCK) . The principle will be the same either way.
Источник
Как написать свой первый Linux device driver. Часть 2
В предыдущей части мы рассмотрели базовые структуры, а также написали инициализацию и удаление устройства.
В данной статье мы добавим в наш драйвер функции открытия scull_open, чтения/записи scull_read/scull_write и получим первый рабочий драйвер устройства.
Хочу выразить благодарность всем пользователям, которые прочитали, лайкнули и прокомментировали мою предыдущую статью. Отдельное спасибо за уточнения Kolyuchkin и dlinyj.
В прошлый раз поступило предложение не рассматривать подробно внутренности каждой функции, поэтому в данной статье я попытаюсь представить их в более широком смысле.
Сразу к делу!
В предыдущей статье мы не рассмотрели одну функцию, которая является частью scull_cleanup_module, а именно scull_trim. Как вы можете наблюдать в функции присутствует цикл, который просто проходится по связному списку и возвращает память ядру. Мы не будем заострять тут наше внимание. Главное впереди!
Перед рассмотрением функции sull_open, я хотел бы сделать маленькое отступление.
Многое в системе Linux может быть представлено в виде файла. Какие операции чаще совершаются с файлами — открытие, чтение, запись и закрытие. Также и с драйверами устройств, мы можем открыть, закрыть, прочитать и записать в устройство.
Поэтому в структуре file_operations, мы видим такие поля как: .read, .write, .open и .release — это базовые операции, которые может выполнять драйвер.
Функция scull_open
Функция принимает два аргумента:
- Указатель на структуру inode. Структура inode — это индексный дескриптор, который хранит информацию о файлах, каталогах и объектах файловой системы.
- Указатель на структуру file. Структура, которая создается ядром при каждом открытии файла, содержит информацию, необходимую верхним уровням ядра.
Главной функцией scull_open является инициализация устройства (если устройство открыто первый раз) и заполнение необходимых полей структур для его корректной работы.
Так как наше устройство ничего не делает, то нам и нечего инициализировать:)
Но чтобы создать видимость работы, мы выполним несколько действий:
В выше приведенном коде с помощью container_of мы получаем указатель на cdev типа struct scull_dev, используя inode->i_cdev. Полученный указатель записываем в поле private_data.
Далее, все еще проще, если файл открыт для записи — очистим его перед использованием и выведем сообщение о том, что устройство открыто.
Функция scull_read
Сейчас я постараюсь описать смысл использования функции read.
Так как наше устройство является символьным, то мы можем работать с ним как с потоком байтов. А что можно делать с потоком байтов? Правильно — читать. Значит, как понятно из названия функции, она будет читать из устройства байтики.
Когда вызывается функция чтения, ей передаются несколько аргументов, первый из них мы уже рассмотрели, теперь посмотрим на остальные.
buf — это указатель на строку, а __user говорит нам о том, что этот указатель находится в пространстве пользователя. Аргумент передает пользователь.
count — количество байтов, которые нужно прочитать. Аргумент передает пользователь.
f_pos — смещение. Аргумент передает ядро.
Т.е., когда пользователь хочет прочитать из устройства, он вызывает функцию read (не scull_read) при этом указывает буфер куда будет записана информация и количество читаемых байт.
Теперь немного подробнее рассмотрим код:
Первым делом идут проверки:
- Если смещение больше, чем размер файла, то, по понятным причинам, читать мы больше не можем. Выведем ошибку и выйдем из функции.
- Если сумма текущего смещения и размера данных для считывания больше размера кванта, то мы корректируем размер данных, подлежащих считыванию, и рапортуем сообщение наверх.
А вот и предмет разговора:
copy_to_user — копирует данные в buf (который находится в пространстве пользователя) из памяти, которую выделило ядро dptr->data[s_pos] размером count.
Если вам сейчас не понятны все эти переменные : s_pos, q_pos, item, rest — не беда, тут главное понять смысл функции read, а уже в 3 части статьи мы протестируем наш драйвер, и там уже будет понятно за что отвечает каждая из них. Но если вы хотите узнать об этом сейчас, вы всегда можете использовать printk (если вы понимаете, о чем я:)).
Функция scull_write
В виду того, что функция scull_write очень похожа на scull_read, и ее отличие от вышерассмотренной понятен из названия, я не буду расписывать эту функцию, а предлагаю вам осмыслить ее самостоятельно.
Все, мы написали полноценный бесполезный драйвер, внизу будет приведен полный код, а в следующей статье мы его протестируем.
После того как я прочитал статью, то понял, что получилось слишком много кода и лишних функций, поэтому ниже приведен максимально простой вариант реализации данного драйвера.
Опрос
Так сложились обстоятельства, что в данный момент у меня есть задачи по портированию драйверов устройств с одной версии ядра на другую. Интересно ли вам было бы прочитать как происходит этот процесс на конкретных примерах?
Если у вас уже есть такой опыт, вы можете поделиться им и написать мне, с какими вы столкнулись проблемами/ошибками при переносе драйверов устройств. А я в свою очередь постараюсь добавить ваш опыт в статью (обязательно укажу вас в ней).
Спасибо! 🙂
Источник