Jdoc:include - метод отображения контента на странице. Пишем простой модуль ядра Linux

Как вы знаете из статьи что такое ядро Linux, ядро является монолитным. Это значит, что весь исполняемый код сосредоточен в одном файле. Такая архитектура имеет некоторые недостатки, например, невозможность установки новых драйверов без пересборки ядра. Но разработчики нашли решение и этой проблеме, добавив систему модулей.

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

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

Модули ядра Linux собираются только под определенную версию ядра, есть способ запуска модуля независимо от версии ядра, если они совместимы с помощью dkms, но об этом мы поговорим позже.

Находятся все модули в папке /lib/modules/. Учитывая, что модули рассчитаны только для определенной версии ядра, то в этой папке создается отдельная подпапка, для каждой установленной в системе версии ядра. В этой папке находятся сами модули и дополнительные конфигурационные файлы, модули отсортированы по категориям, в зависимости от назначения например:

ls /lib/modules/4.1.20-11-default/kernel/

arch Documentation fs lib net sound
crypto drivers kernel mm security

Перед тем как переходить к практике, давайте коротко рассмотрим основные команды для управления модулями.

  • lsmod - посмотреть загруженные модули
  • modinfo - информация о модуле
  • insmod - загрузить модуль
  • rmmod - удалить модуль

Работа с модулями ядра Linux выполняется, в основном, с помощью этих команд, но могут использовать и другие.

Все модули

Такая задача возникает нечасто, но если вы хотите посмотреть все установленные модули ядра Linux в системе, делается очень просто. Все модули расположены в папке /lib/modules, а поэтому очень просто вычислить их все одной командой, или даже просто зайти в папку файловым менеджером и посмотреть.

В Ubuntu команда будет выглядеть вот так:

dpkg -S *.ko | grep /lib/modules

Можно смастерить такую конструкцию с помощью find:

find /lib/modules -name *.ko

Можем искать только для текущего ядра:

find /lib/modules/$(uname -r) -name *.ko

Также, все модули записаны в конфигурационном файле /lib/modules/modules.aliases, поэтому мы можем просто посмотреть его содержимое:

Если хотим проверить установлен ли определенный модуль ядра Linux, отфильтруем вывод любой из команд с помощью grep:

find /lib/modules -name *.ko | grep vbox

/lib/modules/4.1.20-11-default/weak-updates/misc/vboxnetadp.ko
/lib/modules/4.1.20-11-default/weak-updates/misc/vboxvideo.ko

Что загружено?

Все информация о загруженных модулях хранится в файле /proc/modules, мы можем ее вывести командой:

cat /proc/modules

tun 32768 2 - Live 0xffffffffa07a9000
vboxpci 28672 0 - Live 0xffffffffa07a1000 (O)
vboxnetadp 28672 0 - Live 0xffffffffa0632000 (O)
vboxnetflt 32768 0 - Live 0xffffffffa06f3000 (O)
af_packet 40960 8 - Live 0xffffffffa065b000

Но для этого дела есть более цивилизованные методы. Это утилита lsmod и modinfo. Чтобы посмотреть загруженные модули ядра linux выполните:

Module Size Used by
ctr 16384 2
ccm 20480 2
fuse 106496 3
bnep 20480 2
bluetooth 532480 5 bnep

Удобно проверять загружен ли модуль с помощью grep:

sudo lsmod | grep vbox

А более подробную информацию о каждом модуле можно получить с помощью утилиты modinfo:

filename: /lib/modules/4.1.20-11-default/kernel/fs/fuse/fuse.ko
alias: devname:fuse
alias: char-major-10-229
alias: fs-fuseblk
alias: fs-fuse
license: GPL
description: Filesystem in Userspace
author: Miklos Szeredi
alias: fs-fusectl
srcversion: 739DE4A12CE441C9FBD74C7

Здесь вы можете увидеть файл модуля, его лицензию, автора и зависимости. Зависимости - это те модули, которые должны быть загружены для его нормальной работы. К сожалению, не для всех модулей доступно нормальное описание, но вы можете попробовать посмотреть описание зависимостей модуля.

Запуск модулей ядра

Загрузить модуль ядра Linux можно с помощью команд modprobe или insmod.

Например, загрузим модуль vboxdrv

sudo modprobe vboxdrv

Чтобы загрузить модуль ядра linux с помощью insmod необходимо передать адрес файла модуля:

sudo insmod /lib/modules/4.1.20-11-default/weak-updates/misc/vboxdrv.ko

Напоминаю, что его можно узнать с помощью команды modinfo. Запуск модуля ядра Linux предпочтительно выполнять с помощью modprobe, поскольку эта команда не только находит файл модуля в файловой системе, но и загружает все его зависимости.

Удаление модулей ядра

Здесь аналогично две команды - modprobe, позволяет удалить модуль если ей передать опцию -r, а также есть команда rmmod. Начнем с modprobe:

sudo modprobe -r vboxdrv

Другая команда в этом случае выглядит немного проще:

sudo rmmod vboxdrv

rmmod: ERROR: Module vboxdrv is in use by: vboxnetadp vboxnetflt vboxpci

Если вы получили ошибку во время выгрузки модуля, значит он еще используется другими модулями, и сначала нужно выгрузить их. Правильно отработавшая команда не должна ничего возвращать.

rmmod vboxnetadp vboxnetflt vboxpci

Блокирование загрузки модулей

Иногда, во время загрузки системы для используемых нами устройств, загружаются не те модули ядра Linux, они либо не поддерживают нужную функциональность либо конфликтуют с другими модулями. Ярким примером можно назвать загрузку драйвера b43 вместо brcmsmac для беспроводных адаптеров Broadcom. Чтобы решить эту проблему вы можете добавлять модули в черный список. Для этого достаточно добавить одну строчку в файл /etc/modprobe.d/blacklist.conf:

vi /etc/modprobe.d/blacklist.conf

Этот код добавит в черный список модуль b43.

Установка модулей ядра Linux

Собранные для этой версии ядра модули вы можете просто скопировать в нужную папку, собственно, мы так и поступаем, когда собираем ядро из исходников. Но с проприетарными драйверами и другими внешними драйверами, не поставляемыми в комплекте с ядром дело обстоит иначе. Эти модули поддерживают несколько версий ядра, но для их установки используется специальная технология - DKMS (Dynamic Kernel Module Support). Причем модуль, установленный таким образом один раз, будет пересобираться для каждой новой версии ядра автоматически.

wget http://tenet.dl.sourceforge.net/project/e1000/ixgbe%20stable/4.3.15/ixgbe-4.3.15.tar.gz
$ sudo tar -xf ixgbe-4.3.15.tar.gz -C /usr/local/src
$ sudo mv /usr/local/src/ixgbe-4.3.15/src /usr/src/ixgbe-4.3.15

Создадим конфигурационный файл:

sudo vi /usr/src/ixgbe-4.3.15/dkms.conf

PACKAGE_NAME="ixgbe"
PACKAGE_VERSION="4.3.15"
BUILT_MODULE_NAME="ixgbe"
DEST_MODULE_LOCATION="/kernel/drivers/net/ethernet/intel/ixgbe/"
AUTOINSTALL="yes"

Добавим модуль в дерево ядра:

sudo dkms add -m ixgbe -v 4.3.15

Запускаем сборку, для текущего ядра:

sudo dkms build -m ixgbe -v 4.3.15

И устанавливаем:

sudo dkms install -m ixgbe -v 4.3.15

Установка модулей ядра завершена. Теперь вы можете посмотреть информацию о драйвере или загрузить его:

dkms status | grep ixgbe

Выводы

Скорее всего, вам редко придется возиться с этими модулями. Но работа с модулями ядра будет необходима, если ваш дистрибутив не поддерживает аппаратное обеспечение вашего устройства из коробки, а также когда вы работаете со сторонним программным обеспечением, таким как VirtualBox, Vmware и т д. Но очень полезно знать как обращаться с модулями, когда вам нужно добавить или удалить их. Даже если у вас нет необходимости в этом сейчас, вы можете протестировать, как все работает, чтобы быть вооруженным потом.

После того, как репозиторий клонирован с гитхаба, ввожу npm install для установки зависимостей и терплю фейл. Вот листинг процесса:
bimbatron:bem bimba$ npm install > [email protected] postinstall /Users/bimba/BEM > npm run deps > [email protected] deps /Users/bimba/BEM > bower i --allow-root bower EACCES EACCES: permission denied, mkdir "/Users/bimba/.cache/bower/registry/bower.herokuapp.com" Stack trace: Error: EACCES: permission denied, mkdir "/Users/bimba/.cache/bower/registry/bower.herokuapp.com" at Error (native) at Object.fs.mkdirSync (fs.js:922:18) at sync (/Users/bimba/BEM/node_modules/bower/lib/node_modules/bower-registry-client/node_modules/mkdirp/index.js:55:12) at Function.sync (/Users/bimba/BEM/node_modules/bower/lib/node_modules/bower-registry-client/node_modules/mkdirp/index.js:61:24) at new Cache (/Users/bimba/BEM/node_modules/bower/lib/node_modules/bower-registry-client/lib/util/Cache.js:21:16) at RegistryClient. (/Users/bimba/BEM/node_modules/bower/lib/node_modules/bower-registry-client/lib/lookup.js:162:35) at Array.forEach (native) at RegistryClient.initCache (/Users/bimba/BEM/node_modules/bower/lib/node_modules/bower-registry-client/lib/lookup.js:149:34) at RegistryClient._initCache (/Users/bimba/BEM/node_modules/bower/lib/node_modules/bower-registry-client/Client.js:65:27) at new RegistryClient (/Users/bimba/BEM/node_modules/bower/lib/node_modules/bower-registry-client/Client.js:19:10) Console trace: Error at StandardRenderer.error (/Users/bimba/BEM/node_modules/bower/lib/renderers/StandardRenderer.js:81:37) at Logger. (/Users/bimba/BEM/node_modules/bower/lib/bin/bower.js:110:26) at emitOne (events.js:96:13) at Logger.emit (events.js:188:7) at Logger.emit (/Users/bimba/BEM/node_modules/bower/lib/node_modules/bower-logger/lib/Logger.js:29:39) at /Users/bimba/BEM/node_modules/bower/lib/commands/index.js:48:20 at _rejected (/Users/bimba/BEM/node_modules/bower/lib/node_modules/q/q.js:844:24) at /Users/bimba/BEM/node_modules/bower/lib/node_modules/q/q.js:870:30 at Promise.when (/Users/bimba/BEM/node_modules/bower/lib/node_modules/q/q.js:1122:31) at Promise.promise.promiseDispatch (/Users/bimba/BEM/node_modules/bower/lib/node_modules/q/q.js:788:41) System info: Bower version: 1.7.9 Node version: 6.9.1 OS: Darwin 15.6.0 x64 npm ERR! Darwin 15.6.0 npm ERR! argv "/Users/bimba/.nvm/versions/node/v6.9.1/bin/node" "/Users/bimba/.nvm/versions/node/v6.9.1/bin/npm" "run" "deps" npm ERR! node v6.9.1 npm ERR! npm v3.10.8 npm ERR! code ELIFECYCLE npm ERR! [email protected] deps: `bower i --allow-root` npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the [email protected] deps script "bower i --allow-root". npm ERR! Make sure you have the latest version of node.js and npm installed. npm ERR! If you do, this is most likely a problem with the bem-project-stub package, npm ERR! not with npm itself. npm ERR! Tell the author that this fails on your system: npm ERR! bower i --allow-root npm ERR! You can get information on how to open an issue for this project with: npm ERR! npm bugs bem-project-stub npm ERR! Or if that isn"t available, you can get their info via: npm ERR! npm owner ls bem-project-stub npm ERR! There is likely additional logging output above. npm ERR! Please include the following file with any support request: npm ERR! /Users/bimba/BEM/npm-debug.log npm ERR! Darwin 15.6.0 npm ERR! argv "/Users/bimba/.nvm/versions/node/v6.9.1/bin/node" "/Users/bimba/.nvm/versions/node/v6.9.1/bin/npm" "install" npm ERR! node v6.9.1 npm ERR! npm v3.10.8 npm ERR! code ELIFECYCLE npm ERR! [email protected] postinstall: `npm run deps` npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the [email protected] postinstall script "npm run deps". npm ERR! Make sure you have the latest version of node.js and npm installed. npm ERR! If you do, this is most likely a problem with the bem-project-stub package, npm ERR! not with npm itself. npm ERR! Tell the author that this fails on your system: npm ERR! npm run deps npm ERR! You can get information on how to open an issue for this project with: npm ERR! npm bugs bem-project-stub npm ERR! Or if that isn"t available, you can get their info via: npm ERR! npm owner ls bem-project-stub npm ERR! There is likely additional logging output above. npm ERR! Please include the following file with any support request: npm ERR! /Users/bimba/BEM/npm-debug.log

Первая ошибка, что бросается в глаза, это какой-то путь, в котором содержится упоминание heroku app. пробовал чистить кеш bower"a, не помогает, ошибка появляется снова (кстати, как удалить heroku полностью из системы?).

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

Данная строчка выводит на сайте информацию из компонентов, например статьи из com_content. Тип элементов вывода указывается в атрибуте.

1. type - типы элементов вывода.

  • component - как писал выше, выводит основное содержание страницы. Может вызываться только один раз в шаблоне.
  • head - объявляется так же один раз после открывающего тэга . Служит для вывода стилей, скриптов, и метаданных текущей страницы.</li><li><i>message </i><i>- </i> выводит системные сообщения. Объявляется один раз в теле документа (body).</li><li><i>installation </i> - ничего не выводит и представляет собой «инструкцию» для установки.</li><li><i>module - </i>выводит на странице единичный модуль. Количество объявлений не ограничено.</li><li><i>modules </i> - в отличии от предыдущего типа, позволяет выводить в своей позиции не единичое число модулей.</li> </ul><p>Для первых четырех <a href="/himicheskaya-svyaz-i-stroenie-molekul-sostavit-elektronnye-shemy.html">указанных типов</a> достаточно лишь указать их на странице. В случае с типом модуля задача немного усложняется. Для того, чтобы вывести на странице модуль нам нужно сперва создать для него <b>модульную позицию </b> с уникальным идентификатором (название позиции модуля). Это делается при помощи атрибута name=«имя позиции» и обязательным добавлением строки:</p><p> <position>название позиции</position> в файл templateDetails.xml. Описывая название позиции в templateDetails.xml мы обозначаем ее в системе и видим в менеджере модулей. Имена позиций могут быть произвольными, хотя name=«user3» позиция, по-умолчанию используется для отображения верхнего меню. </p><p><b>2. style - описание стиля вывода (mod chrome). </b></p> <p>От указанного стиля зависит <a href="/chto-sdelat-chtoby-ne-nervnichat-pered-vystupleniem-kak-ne.html">внешний вид</a> и структура оболочки модуля. Выглядит как</p><p> :<jdoc:include type="modules" name="user1" style="xhtml" /> По-умолчанию заложено несколько стилей вывода модулей: </p><ul><li><i>xhtml - </i> выводит модуль в блоке с заголовком function modChrome_xhtml($module, &$params, &$attribs)<br>{<br> if (!empty ($module->content)) : ?><br> <div class="moduletable<?php echo htmlspecialchars($params->get("moduleclass_sfx")); ?>"><br> <?php if ($module->showtitle != 0) : ?><br> <h3><?php echo $module->title; ?></h3><br> <?php endif; ?><br> <?php echo $module->content; ?><br> </div><br> <?php endif;<br>}</li><li><i>table - </i>выводит модуль в верстке табличной структуры<br> function modChrome_table($module, &$params, &$attribs)<br>{ ?><br> <table cellpadding="0" cellspacing="0" class="moduletable<?php echo htmlspecialchars($params->get("moduleclass_sfx")); ?>"><br> <?php if ($module->showtitle != 0) : ?><br> <tr><br> <th><br> <?php echo $module->title; ?><br> </th><br> </tr><br> <?php endif; ?><br> <tr><br> <td><br> <?php echo $module->content; ?><br> </td><br> </tr><br> </table><br> <?php<br>}</li><li><i>horz - </i>выводит содержимое модуля в ячейке таблицы, горизонтально function modChrome_horz($module, &$params, &$attribs)<br>{ ?><br> <table cellspacing="1" cellpadding="0" width="100%"><br> <tr><br> <td><br> <?php modChrome_table($module, $params, $attribs); ?><br> </td><br> </tr><br> </table><br> <?php<br>}</li><li><i>rounded </i> - выводит модуль в нескольких вложенных блоках для сложного стилевого оформления в виде графических границ (напр. закругленных углов) function modChrome_rounded($module, &$params, &$attribs)<br>{ ?><br> <div class="module<?php echo htmlspecialchars($params->get("moduleclass_sfx")); ?>"><br> <div><br> <div><br> <div><br> <?php if ($module->showtitle != 0) : ?><br> <h3><?php echo $module->title; ?></h3><br> <?php endif; ?><br> <?php echo $module->content; ?><br> </div><br> </div><br> </div><br> </div><br> <?php<br>}</li><li><i>outline </i> - добавляет к блоку модуля предустановленные стили css function modChrome_outline($module, &$params, &$attribs)<br>{<br> static $css=false;<br> if (!$css)<br> {<br> $css=true;<br> jimport("joomla.environment.browser");<br> $doc = JFactory::getDocument();<br> $browser = JBrowser::getInstance();<br> $doc->addStyleDeclaration(".mod-preview-info { padding: 2px 4px 2px 4px; border: 1px solid black; position: absolute; background-color: white; color: red;}");<br> $doc->addStyleDeclaration(".mod-preview-wrapper { background-color:#eee; border: 1px dotted black; color:#700;}");<br> if ($browser->getBrowser()=="msie")<br> {<br> if ($browser->getMajor() <= 7) {<br> $doc->addStyleDeclaration(".mod-preview-info {filter: alpha(opacity=80);}");<br> $doc->addStyleDeclaration(".mod-preview-wrapper {filter: alpha(opacity=50);}");<br> }<br> else {<br> $doc->addStyleDeclaration(".mod-preview-info {-ms-filter: alpha(opacity=80);}");<br> $doc->addStyleDeclaration(".mod-preview-wrapper {-ms-filter: alpha(opacity=50);}");<br> }<br> }<br> else<br> {<br> $doc->addStyleDeclaration(".mod-preview-info {opacity: 0.8;}");<br> $doc->addStyleDeclaration(".mod-preview-wrapper {opacity: 0.5;}");<br> }<br> }<br> ?><br> <div class="mod-preview"><br> <div class="mod-preview-info"><?php echo $module->position."[".$module->style."]"; ?></div><br> <div class="mod-preview-wrapper"><br> <?php echo $module->content; ?><br> </div><br> </div><br> <?php<br>}</li><li><i>none </i> - аналогично не указанному вообще style. Выводит модуль без оформления и заголовка function modChrome_none($module, &$params, &$attribs)<br>{<br> echo $module->content;<br>}</li> </ul><p>Все предустановленные стили располагаются в файле templates/system/html/modules.php. Но мы не ограничены использованием только предоставленных вариантов, а вполне можем создавать свои собственные.</p> <p><b>3. Создание пользовательского mode chrome. </b></p> <p><b><br></b>Итак, предоставленные по умолчанию типы представления модулей не удовлетворяют текущих требований. Нужно добавить свой собственный стиль оформления. В качестве примера выберем достаточно часто повторяющуюся ситуацию. По заданию нужно вместо <h3> поместить заголовок модуля в тэг <span>, который является семантически нейтральным. Так же требуется поместить контентблок модуля в отдельный <div>. Для создания собственного стиля вывода модуля, воспользуемся стандартными средствами. В большинстве шаблонов Joomla существет папка html/ (templates/имя шаблона/html/), используется для так называемой шаблонизации. То есть, если скопировать в эту папку шаблон модуля, то вместо шаблона из директории modules/my_module/tmpl/default будет выводиться файл из templates/имя шаблона/html/my_modules/default. Аналогично шаблонизируются и компоненты. Удобно и практично. В папке html/ Вашего шаблона создадим файл modules.php. Если такой папки в шаблоне нет, то создадим ее. В файл запишем</p><p> <?php<br>function modChrome_modbox($module, &$params, &$attribs) // Вызываем функцию<br>{<br> if (!empty ($module->content)) : /* Проверяем наличие в поиции включенного модуля */?><br> <div class="moduletable<?php echo htmlspecialchars($params->get("moduleclass_sfx")); /* выводим суффикс css класса модуля */ ?>"><br> <?php if ($module->showtitle != 0) : /* проверяем включен ли заголовок модуля */ ?><br> <span class="title"><?php echo $module->title; /* Выводим заголовок */ ?></span><br> <?php endif; ?><br> <div class="modcontent"><br> <?php echo $module->content; /* Выводим содержимое модуля */ ?><br> </div><br> </div><br> <?php endif;<br>}<br>?> Готово. Теперь нужно только указать его в качестве стиля вывода. <jdoc:include type="modules" name="user1" style="modbox"/> Назначаем в нашу позицию модуль и смотрим результат.</p> <ul><li>Перевод </li> </ul><h2>Захват Золотого Кольца-0</h2> Linux предоставляет мощный и обширный API для приложений, но иногда его недостаточно. Для взаимодействия с оборудованием или осуществления операций с доступом к привилегированной информации в системе нужен драйвер ядра.<p>Модуль ядра Linux - это скомпилированный двоичный код, который вставляется непосредственно в ядро Linux, работая в кольце 0, внутреннем и наименее защищённом кольце выполнения команд в процессоре x86–64. Здесь код исполняется совершенно без всяких проверок, но зато на невероятной скорости и с доступом к любым ресурсам системы.</p><h2>Не для простых смертных</h2> Написание модуля ядра Linux - занятие не для слабонервных. Изменяя ядро, вы рискуете потерять данные. В коде ядра нет стандартной защиты, как в обычных приложениях Linux. Если сделать ошибку, то повесите всю систему.<br><br> Ситуация ухудшается тем, что проблема необязательно проявляется сразу. Если модуль вешает систему сразу после загрузки, то это наилучший сценарий сбоя. Чем больше там кода, тем выше риск бесконечных циклов и утечек памяти. Если вы неосторожны, то проблемы станут постепенно нарастать по мере работы машины. В конце концов важные структуры данных и даже буфера могут быть перезаписаны.<p>Можно в основном забыть традиционные парадигмы разработки приложений. Кроме загрузки и выгрузки модуля, вы будете писать код, который реагирует на системные события, а не работает по последовательному шаблону. При работе с ядром вы пишете API, а не сами приложения.</p><p>У вас также нет доступа к стандартной библиотеке. Хотя ядро предоставляет некоторые функции вроде printk (которая служит заменой printf) и kmalloc (работает похоже на malloc), в основном вы остаётесь наедине с железом. Вдобавок, после выгрузки модуля следует полностью почистить за собой. Здесь нет сборки мусора.</p><h2>Необходимые компоненты</h2> Прежде чем начать, следует убедиться в наличии всех необходимых инструментов для работы. Самое главное, нужна машина под Linux. Знаю, это неожиданно! Хотя подойдёт любой дистрибутив Linux, в этом примере я использую Ubuntu 16.04 LTS, так что в случае использования других дистрибутивов может понадобиться слегка изменить команды установки.<p>Во-вторых, нужна или отдельная физическая машина, или виртуальная машина. Лично я предпочитаю работать на виртуальной машине, но выбирайте сами. Не советую использовать свою основную машину из-за потери данных, когда сделаете ошибку. Я говорю «когда», а не «если», потому что вы обязательно подвесите машину хотя бы несколько раз в процессе. Ваши последние изменения в коде могут ещё находиться в буфере записи в момент паники ядра, так что могут повредиться и ваши исходники. Тестирование в виртуальной машине устраняет эти риски.</p><p>И наконец, нужно хотя бы немного знать C. Рабочая среда C++ слишком велика для ядра, так что необходимо писать на чистом голом C. Для взаимодействия с оборудованием не помешает и некоторое знание ассемблера.</p><h2>Установка среды разработки</h2> На Ubuntu нужно запустить:<p>Apt-get install build-essential linux-headers-`uname -r` <br> Устанавливаем самые важные инструменты разработки и заголовки ядра, необходимые для данного примера.</p><p>Примеры ниже предполагают, что вы работаете из-под обычного пользователя, а не рута, но что у вас есть привилегии sudo. Sudo необходима для загрузки модулей ядра, но мы хотим работать по возможности за пределами рута.</p><h2>Начинаем</h2> Приступим к написанию кода. Подготовим нашу среду:<p>Mkdir ~/src/lkm_example cd ~/src/lkm_example <br> Запустите любимый редактор (в моём случае это vim) и создайте файл lkm_example.c следующего содержания:</p><p> #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> MODULE_LICENSE(“GPL”); MODULE_AUTHOR(“Robert W. Oliver II”); MODULE_DESCRIPTION(“A simple example Linux module.”); MODULE_VERSION(“0.01”); static int __init lkm_example_init(void) { printk(KERN_INFO “Hello, World!\n”); return 0; } static void __exit lkm_example_exit(void) { printk(KERN_INFO “Goodbye, World!\n”); } module_init(lkm_example_init); module_exit(lkm_example_exit); <br> Мы сконструировали самый простой возможный модуль, рассмотрим подробнее самые важные его части:</p><ul><li>В include перечислены файлы заголовков, необходимые для разработки ядра Linux.</li> <li>В MODULE_LICENSE можно установить разные значения, в зависимости от лицензии модуля. Для просмотра полного списка запустите: <p>Grep “MODULE_LICENSE” -B 27 /usr/src/linux-headers-`uname -r`/include/linux/module.h</p></li> <li>Мы устанавливаем init (загрузка) и exit (выгрузка) как статические функции, которые возвращают целые числа.</li> <li>Обратите внимание на использование printk вместо printf . Также параметры printk отличаются от printf . Например, флаг KERN_INFO для объявления приоритета журналирования для конкретной строки указывается без запятой. Ядро разбирается с этими вещами внутри функции printk для экономии памяти стека.</li> <li>В конце файла можно вызвать module_init и module_exit и указать функции загрузки и выгрузки. Это даёт возможность произвольного именования функций.</li> </ul> Впрочем, пока мы не можем скомпилировать этот файл. Нужен Makefile. Такого базового примера пока достаточно. Обратите внимание, что make очень привередлив к пробелам и табам, так что убедитесь, что используете табы вместо пробелов где положено.<p>Obj-m += lkm_example.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean <br> Если мы запускаем make , он должен успешно скомпилировать наш модуль. Результатом станет файл lkm_example.ko . Если выскакивают какие-то ошибки, проверьте, что кавычки в исходном коде установлены корректно, а не случайно в кодировке UTF-8.</p><p>Теперь можно внедрить модуль и проверить его. Для этого запускаем:</p><p>Sudo insmod lkm_example.ko <br> Если всё нормально, то вы ничего не увидите. Функция printk обеспечивает выдачу не в консоль, а в журнал ядра. Для просмотра нужно запустить:</p><p>Sudo dmesg <br> Вы должны увидеть строку “Hello, World!” с меткой времени в начале. Это значит, что наш модуль ядра загрузился и успешно сделал запись в журнал ядра. Мы можем также проверить, что модуль ещё в памяти:</p><p>Lsmod | grep “lkm_example” <br> Для удаления модуля запускаем:</p><p>Sudo rmmod lkm_example <br> Если вы снова запустите dmesg, то увидите в журнале запись “Goodbye, World!”. Можно снова запустить lsmod и убедиться, что модуль выгрузился.</p><p>Как видите, эта процедура тестирования слегка утомительна, но её можно автоматизировать, добавив:</p><p>Test: sudo dmesg -C sudo insmod lkm_example.ko sudo rmmod lkm_example.ko dmesg <br> в конце Makefile, а потом запустив:</p><p>Make test <br> для тестирования модуля и проверки выдачи в журнал ядра без необходимости запускать отдельные команды.</p><p>Теперь у нас есть полностью функциональный, хотя и абсолютно тривиальный модуль ядра!</p><p>Копнём чуть глубже. Хотя модули ядра способны выполнять все виды задач, взаимодействие с приложениями - один из самых распространённых вариантов использования.</p><p>Поскольку приложениям запрещено просматривать память в пространстве ядра, для взаимодействия с ними приходится использовать API. Хотя технически есть несколько способов такого взаимодействия, наиболее привычный - создание файла устройства.</p><p>Вероятно, раньше вы уже имели дело с файлами устройств. Команды с упоминанием /dev/zero , /dev/null и тому подобного взаимодействуют с устройствами “zero” и “null”, которые возвращают ожидаемые значения.</p><p>В нашем примере мы возвращаем “Hello, World”. Хотя это не особенно полезная функция для приложений, она всё равно демонстрирует процесс взаимодействия с приложением через файл устройства.</p><p>Вот полный листинг:</p><p> #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <asm/uaccess.h> MODULE_LICENSE(“GPL”); MODULE_AUTHOR(“Robert W. Oliver II”); MODULE_DESCRIPTION(“A simple example Linux module.”); MODULE_VERSION(“0.01”); #define DEVICE_NAME “lkm_example” #define EXAMPLE_MSG “Hello, World!\n” #define MSG_BUFFER_LEN 15 /* Prototypes for device functions */ static int device_open(struct inode *, struct file *); static int device_release(struct inode *, struct file *); static ssize_t device_read(struct file *, char *, size_t, loff_t *); static ssize_t device_write(struct file *, const char *, size_t, loff_t *); static int major_num; static int device_open_count = 0; static char msg_buffer; static char *msg_ptr; /* This structure points to all of the device functions */ static struct file_operations file_ops = { .read = device_read, .write = device_write, .open = device_open, .release = device_release }; /* When a process reads from our device, this gets called. */ static ssize_t device_read(struct file *flip, char *buffer, size_t len, loff_t *offset) { int bytes_read = 0; /* If we’re at the end, loop back to the beginning */ if (*msg_ptr == 0) { msg_ptr = msg_buffer; } /* Put data in the buffer */ while (len && *msg_ptr) { /* Buffer is in user data, not kernel, so you can’t just reference * with a pointer. The function put_user handles this for us */ put_user(*(msg_ptr++), buffer++); len--; bytes_read++; } return bytes_read; } /* Called when a process tries to write to our device */ static ssize_t device_write(struct file *flip, const char *buffer, size_t len, loff_t *offset) { /* This is a read-only device */ printk(KERN_ALERT “This operation is not supported.\n”); return -EINVAL; } /* Called when a process opens our device */ static int device_open(struct inode *inode, struct file *file) { /* If device is open, return busy */ if (device_open_count) { return -EBUSY; } device_open_count++; try_module_get(THIS_MODULE); return 0; } /* Called when a process closes our device */ static int device_release(struct inode *inode, struct file *file) { /* Decrement the open counter and usage count. Without this, the module would not unload. */ device_open_count--; module_put(THIS_MODULE); return 0; } static int __init lkm_example_init(void) { /* Fill buffer with our message */ strncpy(msg_buffer, EXAMPLE_MSG, MSG_BUFFER_LEN); /* Set the msg_ptr to the buffer */ msg_ptr = msg_buffer; /* Try to register character device */ major_num = register_chrdev(0, “lkm_example”, &file_ops); if (major_num < 0) { printk(KERN_ALERT “Could not register device: %d\n”, major_num); return major_num; } else { printk(KERN_INFO “lkm_example module loaded with device major number %d\n”, major_num); return 0; } } static void __exit lkm_example_exit(void) { /* Remember - we have to clean up after ourselves. Unregister the character device. */ unregister_chrdev(major_num, DEVICE_NAME); printk(KERN_INFO “Goodbye, World!\n”); } /* Register module functions */ module_init(lkm_example_init); module_exit(lkm_example_exit); </p><h2>Тестирование улучшенного примера</h2> Теперь наш пример делает нечто большее, чем просто вывод сообщения при загрузке и выгрузке, так что понадобится менее строгая процедура тестирования. Изменим Makefile только для загрузки модуля, без его выгрузки.<p>Obj-m += lkm_example.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean test: # We put a - in front of the rmmod command to tell make to ignore # an error in case the module isn’t loaded. -sudo rmmod lkm_example # Clear the kernel log without echo sudo dmesg -C # Insert the module sudo insmod lkm_example.ko # Display the kernel log dmesg <br> Теперь после запуска make test вы увидите выдачу старшего номера устройства. В нашем примере его автоматически присваивает ядро. Однако этот номер нужен для создания нового устройства.</p><p>Возьмите номер, полученный в результате выполнения make test , и используйте его для создания файла устройства, чтобы можно было установить коммуникацию с нашим модулем ядра из пространства пользователя.</p><p>Sudo mknod /dev/lkm_example c MAJOR 0 <br> (в этом примере замените MAJOR значением, полученным в результате выполнения make test или dmesg)</p><p>Параметр c в команде mknod говорит mknod, что нам нужно создать файл символьного устройства.</p><p>Теперь мы можем получить содержимое с устройства:</p><p>Cat /dev/lkm_example <br> или даже через команду dd:</p><p>Dd if=/dev/lkm_example of=test bs=14 count=100 <br> Вы также можете получить доступ к этому файлу из приложений. Это необязательно должны быть скомпилированные приложения -  даже у скриптов Python, Ruby и PHP есть доступ к этим данным.</p><p>Когда мы закончили с устройством, удаляем его и выгружаем модуль:</p><p>Sudo rm /dev/lkm_example sudo rmmod lkm_example </p><h2>Заключение</h2> Надеюсь, вам понравились наши шалости в пространстве ядра. Хотя показанные примеры примитивны, эти структуры можно использовать для создания собственных модулей, выполняющих очень сложные задачи.<p>Просто помните, что в пространстве ядра всё под вашу ответственность. Там для вашего кода нет поддержки или второго шанса. Если делаете проект для клиента, заранее запланируйте двойное, если не тройное время на отладку. Код ядра должен быть идеален, насколько это возможно, чтобы гарантировать цельность и надёжность систем, на которых он запускается.</p> <p>После обновления версии друпала на одном из сайтов, где было много рукописных модулей, я, к своему изумлению, обнаружил несколько подряд сообщений об ошибках такого вот содержания:</p> <h2>User warning: The following module is missing from the file system:...</h2> <p>дальше шли имена тех самых модулей, которые система не обнаружила. Модули эти когда-то писал я сам, но в процессе создания они как-то объединились с другими, переименовались или еще что-то... в общем для истории они потеряны. Сначала я решил плюнуть на все это, но очень быстро надпись меня стала раздражать, и я полез разбираться по ссылке, которая была указана рядом с сообщением о проблеме. Почитав инфы я понял, что был неправ, когда удалял модули сразу прямо с сервера, а не пользовался для этого опциями админпанели. Не буду сейчас в подробностях описывать чем это плохо, но делать этого не стоило, но вот сам Друпал таких недостойных поступков разработчиков никак не пресекал. И вот в версии 7.50 и выше создатели этой славной CMS решили призвать всех к порядку.</p> <p>Что же делать, если и вам тоже надоела эта назойливая надпись и захотелось устранить дефекты настройки сайта? Все очень просто и для решения проблемы даже не нужно снова искать в Интернете те модули, которые вы удалили, и снова их устанавливать на сайт (как это рекомендуется разработчиками Drupal). И даже то, что это был ваш собственнописный полуфабрикат и вы забыли о нем напрочь, не означает, что вам придется пройти сеанс гипноза и восстановить код из глубин подсознания. Проблема решается в три простых шага:</p> <p>Вот и все. Я обещал три шага, а получилось шесть. Но это не значит, что все сложно, просто я растягивал удовольствие:) Удачи!<br> ​</p> <script type="text/javascript"> <!-- var _acic={dataProvider:10};(function(){var e=document.createElement("script");e.type="text/javascript";e.async=true;e.src="https://www.acint.net/aci.js";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)})() //--> </script><br> <br> <script>document.write("<img style='display:none;' src='//counter.yadro.ru/hit;artfast_after?t44.1;r"+ escape(document.referrer)+((typeof(screen)=="undefined")?"": ";s"+screen.width+"*"+screen.height+"*"+(screen.colorDepth? screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+";h"+escape(document.title.substring(0,150))+ ";"+Math.random()+ "border='0' width='1' height='1' loading=lazy>");</script> </div> </article> </div> </main> <noindex> <aside class="sidebar sidebar_midle"> <div class="section-posts-box section"> <div class="title">Популярные статьи</div> <div class="section-posts"> <div class="section-posts__item"> <img src="/uploads/4be64ff6d222da4105692245d96c0c1c.jpg" width="300" height="180" class="section-posts__item-img" alt="Василий III. Биография. Правление. Семья. Интересные факты о Василии III Сообщение о василии 3 кратко" / loading=lazy> <div class="section-posts__item-title"> <a href="/vasilii-iii-biografiya-pravlenie-semya-interesnye-fakty-o-vasilii.html">Василий III. Биография. Правление. Семья. Интересные факты о Василии III Сообщение о василии 3 кратко</a> </div> <div class="section-posts__item-text"> Василий 3 (годы правления 1505-1533) ознаменовались окончательным сбором русских земель... </div> <div class="post-info section-posts__item-info"> <time class="post-info__time post-info__time_popular" datetime="">2024-04-15 01:49:22</time> </div> </div> <div class="section-posts__item"> <img src="/uploads/888d10e708a1a32369d88c15e49bf7ab.jpg" width="300" height="180" class="section-posts__item-img" alt="Переход от корней к степеням и обратно, примеры, решения Как решать примеры со степенями и корнями" / loading=lazy> <div class="section-posts__item-title"> <a href="/izvlechenie-kornei-sposoby-primery-resheniya-perehod-ot-kornei-k.html">Переход от корней к степеням и обратно, примеры, решения Как решать примеры со степенями и корнями</a> </div> <div class="section-posts__item-text"> Пришло время разобрать способы извлечения корней . Они базируются на свойствах корней , в... </div> <div class="post-info section-posts__item-info"> <time class="post-info__time post-info__time_popular" datetime="">2024-04-12 01:52:34</time> </div> </div> <div class="section-posts__item"> <img src="/uploads/c6b834710dd0f89e1c2f6accaac858c2.jpg" width="300" height="180" class="section-posts__item-img" alt="Знамение Невидимой Звезды (ЛП) Небо переходной местности между пригородами и городами" / loading=lazy> <div class="section-posts__item-title"> <a href="/pochemu-ne-vidno-zvezd-znamenie-nevidimoi-zvezdy-lp-nebo.html">Знамение Невидимой Звезды (ЛП) Небо переходной местности между пригородами и городами</a> </div> <div class="section-posts__item-text"> Экология познания. Наука и открытия: Вселенная бесконечна, и в ней нет числа звездам. В... </div> <div class="post-info section-posts__item-info"> <time class="post-info__time post-info__time_popular" datetime="">2024-04-11 01:52:27</time> </div> </div> </div> </div> <div class="section section_widget widget_text" id="text-7"> <div class="textwidget"> </div> </div> </aside> </noindex> </div> </div> <footer class="footer"> <link href="https://fonts.googleapis.com/css?family=Roboto:400,400i,500,700,700i&subset=cyrillic" rel="stylesheet"> <nav class="footer-nav"> <ul> <li class="menu-item type-post_type object-page "><a href="/feedback.html">Контакты</a></li> <li class="menu-item type-post_type object-page "><a href="/sitemap.xml">Карта сайта</a></li> </ul> </nav> <div class="footer-bottom"> <div class="copy">© 2024 netdenegnakino.ru - Двойкам - нет. Химия. Физика. Орфография. География</div> </div> </footer> </div> <script type='text/javascript'> /* <![CDATA[ */ var tocplus = { "smooth_scroll": "1", "visibility_show": "\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c", "visibility_hide": "\u0421\u043a\u0440\u044b\u0442\u044c", "width": "Auto" }; /* ]]> */ </script> <script type='text/javascript' src='https://netdenegnakino.ru/wp-content/plugins/table-of-contents-plus/front.min.js?ver=1509'></script> <script type='text/javascript' src='https://netdenegnakino.ru/wp-content/plugins/wp-postratings/js/postratings-js.js?ver=1.85'></script> <script type='text/javascript'> var q2w3_sidebar_options = new Array(); q2w3_sidebar_options[0] = { "sidebar": "sidebar-2", "margin_top": 10, "margin_bottom": 0, "stop_id": "", "screen_max_width": 0, "screen_max_height": 0, "width_inherit": false, "refresh_interval": 1500, "window_load_hook": false, "disable_mo_api": false, "widgets": ['text-7', 'text-6'] }; </script> <script type='text/javascript' src='https://netdenegnakino.ru/wp-content/plugins/q2w3-fixed-widget/js/q2w3-fixed-widget.min.js?ver=5.0.4'></script> <script type='text/javascript' src='/wp-includes/js/wp-embed.min.js?ver=4.9.2'></script> </div> </body> </html> <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>