LinuxForum.Fans
Тема

Может ли модуль читать обычный файл?

Автор: nihao 33 сообщений 16390 просмотров
#212873
drBatty написал:
[quote=Olej]
[quote=drBatty]
Можно ли в модуле выполнить те же функции, что и в пользовательской программе? А именно: открыть файл

Вопрос хороший и ответ на него не очевидный...[/quote]
[/quote]

Здесь я ошибся!
Действительно, единственный умный пост в теме написал nihao, а не drBatty.

drBatty написал:

раз уж вы меня обвиняете в неграмотности.)

А неграмотность? при чём тут обвинения? - неграмотность она либо есть, либо её нет :lol: - это как с сусликом :lol:

drBatty написал:

Вы в игноре.

Наконец то!
Теперь хоть предмет темы пообсуждать можно - никто под ногами не путается.
... а для вас, drBatty, есть там рядом немало более доступных тем: игры там ... мультимедии разные, опять же wink

#212875
Olej написал:
Здесь я ошибся!
Действительно, единственный умный пост в теме написал nihao, а не drBatty

мда... Единственный умный пост... И тот - вопрос топикстартера. Самокритично, чтож... А что вы ещё делаете на этом неумном форуме?

Olej написал:
А неграмотность? при чём тут обвинения? - неграмотность она либо есть, либо её нет laugh - это как с сусликом laugh

с сусликом? это про [:||||:] из ДМБ?
Понятно...
- видишь, какой drbatty неграмотный?
- не вижу.
- и я не вижу. Но он всё равно неграмотный!
:D

#212877
drBatty написал:

А что вы ещё делаете на этом неумном форуме?

1. Развлекаюсь :lol:

2. ... и потом, на всём форуме в целом - далеко не все до такой степени не умны :lol:

3. ... мне здесь подсказали ряд очень не слабых ссылок на публикации...

Т.е. я время на форуме провожу не без пользы :lol:

#212882

В тему:

nihao написал:
А именно: открыть файл (не файл устройства! не в /proc) и прочитать данные оттуда в свой собственный буфер

Для однозначности терминологии: при работе с именами из /proc и из /dev со стороны модуля - ничего подобного "открытию" и т.п. операциям не делается, там а). совсем другие механизмы б). и совсем специальный набор API для этого, в). причём, для /proc - один API, а для /dev - совершенно другой, ... а для /sys - ещё свой отдельный API.
Это всё совершенно отдельные темы, и с чтением файла они просто не имеют ничего минимально общего!

#212941
Fat-Zer написал:

[quote=Olej] а вот запустить в пользовательское пространство новое приложение как exec() модуль элементарно может

как exec модуль уж точно не может. man 3 exec для закрепления.[/quote]

Fat-Zer, вы сами себе противоречите:

- ... только для лучшего закрепления лучше всё-таки :D

text

$ man 2 execve

- потому как все библиотечные вызовы execl, execlp, execle, execv, execvp - тут же сразу транзитом преобразуются в системный вызов execve ...

- который тоже ничего сам не делает, а тут же превращается в int 80h (или sysenter, если вам так больше нравится wink - что в точности то же самое)... и мы уже в kernel

- ничего более (т.е. практически ничего вообще) в пользовательском процессе не делается, не происходит.

- если exec из пользовательского процесса создаст новый процесс только и полностью в вызове кода kernel - то почему же сам код kernel не может делать то же самое?

- а код модуля ничем(!) не отличается от кода самого ядра (в чём и есть самое слабое место всей этой модели).

Ну так почему бы коду модуля ядра не запускать ещё новый пользовательский процесс?
И кто тогда вообще запускает для вас всё множество пользовательских процессов, когда вы набираете команды в shell? :lol:

#212967
Olej написал:
Что находится из исходников? Если эти имена ядром не экспортируются? Как вы к ним будете связываться?

всё там экспортируется... даже в исходники лезть не обязательно... достаточно и include/linux/fs.h

Olej написал:
Вы покажите как читать - и всё станет, может, не так трудно?

да элементарно.... собрать самостоятельно сможете...

text

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/sched.h>

static const char inp_file[]= "/etc/rc.conf";

static int __init kread_init(void) { struct file *f; static char buff[256]; size_t n;

printk(KERN_ALERT "openning file: %s\n",inp_file); f = filp_open(inp_file, O_RDONLY, 0);

if(!f) { printk(KERN_ALERT "file open failed: %s\n",inp_file); return 100500; }

n = kernel_read(f, 0, buff, 255);

if(n){ buff[n]=0; printk(KERN_ALERT "read first %d bytes: %s\n", 255, buff); } else { printk(KERN_ALERT "kernel_read failed\n"); }

filp_close(f, current->files); return 0; }

static void __exit kread_exit(void) { printk(KERN_ALERT "Goodbye, world\n"); }

module_init(kread_init); module_exit(kread_exit);

Olej написал:
Обычный файл из ядра читать может трудно, а может и невозможно

из ядра возможно !ВСЁ!, что не запрещено запрещено законами физики и математики.

про exec: был тонкий намёк на фундаментальное свойство:

The exec() family of functions replaces the current process image with a new process image.
что для работы в режиме ядра - бред. или вы предлогаете любой current заменять? это можно, но смысла в этом не больше, чем в чтение файла... всегда сделать /dev/leper_colony и всякого, кто будит читать или писать заменять на /bin/leper и через некоторое количество времени убивать его. wink
Olej написал:
Ну так почему бы коду модуля ядра не запускать ещё новый пользовательский процесс?

а это пожалуйста...
ещё раз: из ядра можно сделать \практически\ ВСЁ(!)

ЗЫ: Olej, drBatty, балаган без переписки по сабжу прекращаем...

#213014
Fat-Zer написал:

[quote=Olej]Вы покажите как читать - и всё станет, может, не так трудно?

да элементарно.... собрать самостоятельно сможете...
[/quote]

Пример хорош (мне было интересно).
Это и есть то, что я просил показать: простенько и со вкусом wink
По нему как раз можно кой-чего прокомментировать в пояснение первоначального вопроса ... но я это сделаю чуть позже.

#213091
Olej написал:
но я это сделаю чуть позже.

Так вот к чему это я?

nihao написал:
Можно ли в модуле выполнить те же функции, что и в пользовательской программе?

Конечно же нельзя!
Можно использовать некоторый только по смыслу похожий набор вызовов из kernel API (если такой набор существует для ваших целей!).

Вот Fat-Zer использовал набор функций filp_open() -> kernel_read() -> filp_close(), что по смыслу похоже на open() - read() - close(), но это совершенно другие API! (они даже расположены в совершенно разных местах-адресах open() - read() - close() в libc.so, а filp_open() - kernel_read() - filp_close() в kernel).

P.S. пример, конечно подкупающий своей простотой, ... я, конечно, собрал, поигрался wink ... респект...
единственно, вызывает сомнение место (т.е. я просто не согласен):

text

   filp_close( f, current->files );

- использование current внутри модуля, загружаемого insmod (в функции инициализации)??? - ну и на чью структуру task будет указывать такой curent?
вполне достаточно:

text

   filp_close( f, NULL );

Я когда-то решал подобную задачу по-другому, другой набор kernel API, он несколько более общий, но сложнее и более громоздкий. Для полноты картины я переписал "в том стиле" показанный пример (с теми же переменными), получилось вот что:

text

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/uaccess.h>

static const char inp_file[] = "/etc/yumex.profiles.conf"; #define BUF_LEN 255

static int __init kread_init( void ) { struct file *f; char buff[ BUF_LEN + 1 ] = ""; size_t n; long l; loff_t file_offset = 0;

mm_segment_t fs = get_fs(); set_fs( get_ds() );

printk( "**** openning file: %s\n", inp_file ); f = filp_open( inp_file, O_RDONLY, 0 );

if( IS_ERR( f ) ) { printk( KERN_ALERT "file open failed: %s\n", inp_file ); l = -ENOENT; goto fail_oupen; }

l = vfs_llseek( f, 0L, 2 ); // 2 means SEEK_END if( l <= 0 ) { printk( "failed to lseek %s\n", inp_file ); l = -EINVAL; goto failure; } printk( "**** file size = %d bytes\n", (int)l );

vfs_llseek( f, 0L, 0 ); // 0 means SEEK_SET if( ( n = vfs_read( f, buff, l, &file_offset ) ) != l ) { printk( "failed to read %s\n", inp_file ); l = -EIO; goto failure; } buff[ n ] = '\0'; printk( "%s\n", buff ); printk( KERN_ALERT "**** close file: %s\n", inp_file ); l = -EPERM; failure: filp_close( f, NULL ); fail_oupen: set_fs(fs); return (int)l; }

module_init( kread_init ); MODULE_LICENSE( "GPL" );

Столь же неплохо работает:

text

[olej@notebook file]$ sudo insmod mod_vfs.ko
insmod: error inserting 'mod_vfs.ko': -1 Operation not permitted
[olej@notebook file]$ dmesg | tail -n 25
...
**** openning file: /etc/yumex.profiles.conf
**** file size = 32 bytes
[main]
lastprofile = yum-enabled
**** close file: /etc/yumex.profiles.conf
...
[olej@notebook file]$ cat /etc/yumex.profiles.conf
[main]
lastprofile = yum-enabled[olej@notebook file]$

А привёл я другой вариант вот почему:
- здесь использован другой набор kernel API: filp_open() -> vfs_llseek() -> vfs_read() -> filp_close() ...
- который только похож на набор POSIX API userspace по своему смыслу...
- и использованы прямые вызовы экспортируемых имён модуля VFS ... и так во всём: в коде доступны только те имена kernel API, которые экспортируются либо самим ядром, либо подгруженными модулями...
- а сверх того (сверх возможностей предоставленных таким экспортом) ничего в коде модуля получить нельзя... (как например, ту же таблицу sys_call_table, которую уже не раз упоминали).

#213096
Fat-Zer написал:

про exec: был тонкий намёк на фундаментальное свойство:

The exec() family of functions replaces the current process image with a new process image.

что для работы в режиме ядра - бред. или вы предлогаете любой current заменять? это можно, но смысла в этом не больше, чем в чтение файла... всегда сделать /dev/leper_colony и всякого, кто будит читать или писать заменять на /bin/leper и через некоторое количество времени убивать его. wink

Olej написал:
Ну так почему бы коду модуля ядра не запускать ещё новый пользовательский процесс?

а это пожалуйста...
ещё раз: из ядра можно сделать \практически\ ВСЁ(!)

Я здесь не уловил смысла рассуждений, зачем это сказано? :
- exec() в POSIX, вообще то не создаёт нового адресного пространства, для него это делает всегда предшествующий fork() (в Win32 там, как помнится, картина другая ... с точностью до наоборот wink )
- так точно и kernel при использовании helper-API - создаёт ещё одно адресное пространство (юзеровское), и после создаёт в нём процесс.

#213102
Olej написал:
- использование current внутри модуля, загружаемого insmod (в функции инициализации)??? - ну и на чью структуру task будет указывать такой curent?
вполне достаточно:

копипастил из close() - не задумывался, что там во втором параметре. а вообще стоит посмотреть что это такое....

vfs_read напрямую лучше не использовать. он рассчитан на то, что буфер находится в юзерспейсе. ИРЛ разницы наверняка не будет, но правильнее использовать обёртку. (хотя там какая-то тёмная фигня происходит)

ЗЫ: прочитайте какой-нить большой файл wink

#213103
Fat-Zer написал:

vfs_read напрямую лучше не использовать. он рассчитан на то, что буфер находится в юзерспейсе. ИРЛ разницы наверняка не будет, но правильнее использовать обёртку. (хотя там какая-то тёмная фигня происходит)

это и решается обрамлением кода:

text

    mm_segment_t fs = get_fs();
    set_fs( get_ds() );
    ...
    set_fs(fs);    
#213175
Olej написал:
это и решается обрамлением кода:

спасибо кэп... вопрос в том, что этот код делает и почему оно работает...

#213204
Fat-Zer написал:
[quote=Olej]это и решается обрамлением кода:

спасибо кэп... вопрос в том, что этот код делает и почему оно работает...[/quote]

Он делает подмену сегментов данных.
В деталях разберуть (я как-то не задавался вопросом) - напишу wink

P.S. но без этого точно не работает ... с кодом ошибки: Bad address.

Войдите или зарегистрируйтесь, чтобы ответить.