Как разделить модуль-драйвер клавиатуры (linux) на два?

Как разделить модуль-драйвер клавиатуры (linux) на два?

05.10.2015 08:31:02 Просмотров 26 Источник

По заданию:

Драйвер поддерживает чтение файла в формате ASCII и запись сообщений в него через пользовательский процесс: ioctl_set_msg(file_desc, msg). Поддерживает функцию удаления сообщения: ioctl_msg_delete.

То что он делает.


Запускаем программу...

gcc myioctl-app.c -o myioctl-app
insmod myioctl.ko
 echo HELLO_WORLD > text.txt
./myioctl-app -w text.txt
 cat /dev/mioc
HELLO_WORLD

..... Дело в том что В модуле мы записываем в файл hello_world он же копирует в буфер и потом мы можем выводить

  cat /dev/mioc 

  HELLO_WORLD

Вопрос: Как разделить на ДВА МОДУЛЯ?и как запускать? Первый модуль записывает в файл... Второй модуль читает из файла и записывает в буфер.

Заранее спасибо

Драйвер клавиатуры

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h> //Для отладки
#include <linux/fs.h> //Файл
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>

#include "myioctl.h"

#define MIOC_CHRDEV_COUNT   1 
#define MIOC_CHRDEV_NAME    "DRIVER"
#define MIOC_CLASS_NAME     "mioc"
#define MIOC_DEV_NAME       "mioc"
#define MIOC_MSG_SIZE       80      /* Кол-во символов для буфера */
#define MIOC_CMD_MAX        80      /* кол-во символов для командной строки */

//Ключевые слова
#define CMD_DIRECTION   "direction"  
#define ARG_FORWARD     "forward" //Чтение вперед
#define ARG_BACKWARD    "back" //Чтение назад

enum mioc_direction {
    DIR_FORWARD = 0, //Вперед
    DIR_BACKWARD    = 1, //Назад
};

struct mioc { //Структура регистрации символьного устройства
    dev_t dev;
    struct cdev cdev;
    struct class *class;
    char *msg; //Файл
    size_t msg_len; //Кол-во символов
    enum mioc_direction dir; //Направление
    struct mutex mutex; //Семафор для захвата потоков на чтение, запись и удаление файла
};

static struct mioc *mioc; //Указатель на струтуру

/* --------------------------- Основные функции ---------------------------- */

/*
 * Определение напрвления чтения
 */
static int mioc_set_direction(char *arg)
{
    enum mioc_direction dir;

    if (strcmp(arg, ARG_FORWARD) == 0)
        dir = DIR_FORWARD; //Читаем вперед
    else if (strcmp(arg, ARG_BACKWARD) == 0)
        dir = DIR_BACKWARD; //Читаем назад 
    else
        return -1;

    if (mutex_lock_interruptible(&mioc->mutex)) //Если прервано сигналом, взаимное исключение не получено
        return -ERESTARTSYS; //Вызов системного вызова
    mioc->dir = dir;
    mutex_unlock(&mioc->mutex); //Открыть

    return 0;
}

/*
 * Разбор команды пользователя и выбор направления 
 */
static int mioc_parse_and_perform(char *str)
{
    char *end, *token; //Последний знак, знаки
    char *cmd = NULL, *arg = NULL; //Начальные аргументы
    int token_nr = 0;
    int ret = 0; //Для возврата

    /* Убрать пробелы в начале строки */
    while (isspace(*str))
        ++str;
    if (*str == '\0') /* Все пробелы? */
        return -1;

    /* Убрать пробелы в конце строки */
    end = str + strlen(str) - 1;
    while (end > str && isspace(*end))
        --end;
    *(end + 1) = '\0';

    /* Строка оказалась пустой */
    if (strlen(str) == 0)
        return -1;

    /* Один символ в строке */
    if (strchr(str, ' ') == NULL)
        return -1;

    /* Разбор командной строки и аргументов*/
    while ((token = strsep(&str, " ")) != NULL) { //Извлечение знака из строки
        ++token_nr;
        if (token_nr == 1) {
            cmd = kmalloc(strlen(token) + 1, GFP_KERNEL); //Выделение памяти (Нормальное выделение памяти ядра)
            if (!cmd) //Если память не выделелась
                return -ENOMEM; //Ядру не хватило памяти
            strcpy(cmd, token); //Копируем знаки в cmd 
        } else if (token_nr == 2) {
            arg = kmalloc(strlen(token) + 1, GFP_KERNEL);//Выделение памяти (Нормальное выделение памяти ядра)
            if (!arg) {
                ret = -ENOMEM; //Ядру не хватило памяти
                goto err1;
            }
            strcpy(arg, token); //Копируем знаки в аргументы
        } else {
            ret = -1;
            goto err2;
        }
    }

    /* Проверка на корректность по счетчику */
    if (token_nr != 2) {
        ret = -1;
        goto err2;
    }

    /* Распознавание команды */
    if (strcmp(cmd, CMD_DIRECTION) == 0) //Копируем направление 
        ret = mioc_set_direction(arg);
    else
        ret = -2; //Ошибка чтения направления

//Освобождение памяти при неудачах
err2:
    kfree(arg); 
err1:
    kfree(cmd);
    return ret;
}

/*
 * Функция записи
 */
static long mioc_ioctl_write(const char __user *arg)
{
    long len;

    /* Длинна включает нулевой символ */
    len = strnlen_user(arg, MIOC_MSG_SIZE); //Буфер пространства пользователя доступен для чтения
    if (len >= MIOC_MSG_SIZE) { //Если превышено 
        pr_err("MIOC: too long string via ioctl\n");
        return -EFAULT; //По умолчанию
    }

    if (mutex_lock_interruptible(&mioc->mutex)) //Если программа может быть переведена в режим ожидания
        return -ERESTARTSYS; //Вызов системного вызова

    mioc->msg_len = 0;
    if (copy_from_user(mioc->msg, arg, len)) { //Копирование данных неопределенного размера 
        mutex_unlock(&mioc->mutex); // Снять взаимное исключение
        return -EFAULT; //По умолчанию
    }
    mioc->msg_len = len; //Передать символы

    mutex_unlock(&mioc->mutex); //Открыть 

    return 0;
}

/*
 * Функция удаления
 */
static int mioc_ioctl_erase(void)
{
    if (mutex_lock_interruptible(&mioc->mutex)) //Если прервано сигналом, взаимное исключение не получено (программа может быть переведена в режим ожидания)
        return -ERESTARTSYS; //Вызов системного вызова

    mioc->msg_len = 0; //Удалить   

    mutex_unlock(&mioc->mutex); //Открыть

    return 0;
}

/* ---------------------------- Файловые операции ---------------------------- */

/*
    Распечатать сообщение из буфера драйвера.
    Способ печати зависит от параметров направления ("вперед" по умолчанию).
 */
static ssize_t mioc_read(struct file *file, char __user *buf, size_t count, //Беззнаковый целый тип (получение данных из устройства)
        loff_t *ppos) //Смещение
{
    ssize_t ret;

    if (mutex_lock_interruptible(&mioc->mutex)) //Если прервано сигналом, взаимное исключение не получено (программа может быть переведена в режим ожидания)
        return -ERESTARTSYS; //Вызов системного вызова

    if (*ppos >= mioc->msg_len) { //Если смещение больше 
        ret = 0;
        goto out_unlock; //Открыть
    }
    if (*ppos + count > mioc->msg_len)
        count = mioc->msg_len - *ppos;

    switch (mioc->dir) { //Направление
    case DIR_FORWARD: //Чтение вперед
        if (copy_to_user(buf, mioc->msg + *ppos, count)) { //Копирование данных между адресными пространствами пользователя и ядра
            ret = -EFAULT; //Неправильный адрес
            goto out_unlock; //Открыть
        }
        break;
    case DIR_BACKWARD: { //Чтение назад
        int i;
        int start = mioc->msg_len - 1 - *ppos; //На конец
        int end = start - count; //На начало 

        for (i = start; i > end; --i) {
            if (put_user(mioc->msg[i], buf++)) { //Вывод в обратном порядке
                ret = -EFAULT;//Неправильный адрес
                goto out_unlock;//Открыть
            }
        }
        break;
    }
    default: //Нет такой команды
        pr_err("MIOC: unknown direction\n");
        ret = -EFAULT;//Неправильный адрес
        goto out_unlock;//Открыть
    }

    *ppos += count; //Сдвигаем позицию

    mutex_unlock(&mioc->mutex); //Открыть

    return count;

out_unlock:
    mutex_unlock(&mioc->mutex); //Открыть
    return ret;
}

/*
    Разобрать и выполнить команду от пользователя.
    Пока доступна только команда "направление". Она имеет один аргумент:
    - "вперед": сообщение будет напечатано, как написано
    - "назад": сообщение будет напечатано задом наперед
 */
static ssize_t mioc_write(struct file *file, const char __user *buf, //Беззнаковый целый тип (пишет данные в устройство)
        size_t count, loff_t *ppos) //Смещение
{
    char *cmd;

    if (count > MIOC_CMD_MAX) { //Если строка слишком длинная  
        pr_err("MIOC: too long string\n");
        return -EINVAL; //Количество реально записанных байт
    }

    cmd = kmalloc(sizeof(char) * (count + 1), GFP_KERNEL); //Выделение памяти (Нормальное выделение памяти ядра)
    if (!cmd)
        return -ENOMEM; //Ядру не хватило памяти

    if (copy_from_user(cmd, buf, count)) //Копирование данных между адресными пространствами пользователя и ядра
        goto err_copy; //Ошибка копирования

    cmd[count] = '\0'; /* для строковых операций в процедуре разбора */
    if (mioc_parse_and_perform(cmd) < 0) { //Если не удалось разобрать команду 
        pr_err("MIOC: unable to parse command\n");
        goto err_copy; //Ошибка
    }

    kfree(cmd); //Освободить память
    return count;

err_copy:
    kfree(cmd);
    return -EFAULT; //Неправильный адрес
}

/*
    В ioctls поддерживаются 2 задачи: "написать сообщение" и "удалить сообщение".
 */
static long mioc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    switch (cmd) { //Команда
    case MIOC_IOCWRITE: //Записать 
        return mioc_ioctl_write((char __user *)arg);
    case MIOC_IOCERASE: //Удалить
        return mioc_ioctl_erase();
    default:
        return -ENOTTY; //Код ошибки
    }

    return 0;
}

static int mioc_open(struct inode *inode, struct file *file) //Открытие
{
    return 0;
}

static int mioc_release(struct inode *inode, struct file *file) //Удаление 
{
    return 0;
}

static struct file_operations mioc_fops = { //Структура с возможными операциями (файл операций)
    .owner = THIS_MODULE,
    .read = mioc_read, //Чтение
    .write = mioc_write, //Запись
    .unlocked_ioctl = mioc_ioctl,
    .open = mioc_open, //Открытие
    .release = mioc_release, //Удаление
};

/* --------------------------- Модульные операции --------------------------- */

static int __init mioc_init(void) //Инициализация модуля
{
    int ret;
    struct device *d; //Устройство

    mioc = kzalloc(sizeof(*mioc), GFP_KERNEL);  //Выделение памяти устройству (нормальное выделение памяти ядра)
    if (mioc == NULL)
        return -ENOMEM; //Код ошибки

    mioc->msg = kmalloc(sizeof(char) * MIOC_MSG_SIZE, GFP_KERNEL); //Выделение памяти для сообщения (нормальное выделение памяти ядра)
    if (mioc->msg == NULL) {
        ret = -ENOMEM; //Код ошибки
        goto err_msg;
    }

    ret = alloc_chrdev_region(&mioc->dev, 0, MIOC_CHRDEV_COUNT, 
            MIOC_CHRDEV_NAME); //Динамическое выделение памяти для получения старшего номера устройства
    if (ret < 0) //Если не выделено 
        goto err_chrdev; 

    mioc->class = class_create(THIS_MODULE, MIOC_CLASS_NAME); //Класс драйвера
    if (IS_ERR_OR_NULL(mioc->class)) {//Если ошибка класса драйвера
        if (mioc->class == NULL) //Какой тип ошибки 
            ret = -ENOMEM; //Код ошибки
        else
            ret = PTR_ERR(mioc->class);
        goto err_class;
    }

    d = device_create(mioc->class, NULL, mioc->dev, NULL, MIOC_DEV_NAME); //Создать устройство
    if (IS_ERR_OR_NULL(d)) { //Какой тип ошибки 
        if (d == NULL)
            ret = -ENOMEM; //Код ошибки
        else
            ret = PTR_ERR(d);
        goto err_device;
    }

    mutex_init(&mioc->mutex); //атрибуты для мьютекса

    cdev_init(&mioc->cdev, &mioc_fops); //Инициализация устройства и структуры 
    ret = cdev_add(&mioc->cdev, mioc->dev, MIOC_CHRDEV_COUNT); //Инициализация устройства 
    if (ret < 0)
        goto err_cdev;

    return 0;

err_cdev:
    mutex_destroy(&mioc->mutex);  //Освобождение всех ресурсов
    device_destroy(mioc->class, mioc->dev);
err_device:
    class_destroy(mioc->class); //Освобождение устройства
err_class:
    unregister_chrdev_region(mioc->dev, MIOC_CHRDEV_COUNT); //Очистка модуля 
err_chrdev:
    kfree(mioc->msg); //Очистка сообщения
err_msg:
    kfree(mioc); //Очистка устройства
    return ret;
}

static void __exit mioc_clean(void) //Выгрузка модуля 
{
    //Освобождение памяти и ресурсов 
    cdev_del(&mioc->cdev);
    mutex_destroy(&mioc->mutex);
    device_destroy(mioc->class, mioc->dev);
    class_destroy(mioc->class);
    unregister_chrdev_region(mioc->dev, 1); //Очистка модуля

    kfree(mioc->msg);//Очистка сообщения
    kfree(mioc); //Очистка устройства
}

//Макросы
module_init(mioc_init); 
module_exit(mioc_clean);

MODULE_DESCRIPTION("MIOC: ioctl example driver"); //Название модуля  
MODULE_LICENSE("GPL"); //Лицензия

Программа

#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h> //Для файлового дескриптора 
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "myioctl.h"

#define DEV_FILE "/dev/mioc"

//Опции для файла
enum option {
    OPT_UNKNOWN,
    OPT_WRITE,
    OPT_ERASE
};

struct params {
    enum option option;
    char *msg_filename; /* Указатель на имя файла */
};

//При неправильном вводе команды показать помощь
static void print_usage(char *appname)
{
    fprintf(stderr, "Usage: %s OPTION\n\n", appname);
    fprintf(stderr, "  -del            erase message in MIOC driver\n");
    fprintf(stderr, "  -write FILE       write specified file content "
            "to MIOC driver\n");
}

//Распознание команды из командной строки
static int parse_params(int argc, char *argv[], struct params *params)
{
    params->option = OPT_UNKNOWN;
    params->msg_filename = NULL;

    if (argc == 2) {
        if (strcmp(argv[1], "-del") == 0)
            params->option = OPT_ERASE;
        else
            goto err_parse;
    } else if (argc == 3) {
        if (strcmp(argv[1], "-write") == 0) {
            params->option = OPT_WRITE;
            params->msg_filename = argv[2];
        } else {
            goto err_parse;
        }
    } else {
        goto err_parse;
    }

    return 1;

err_parse:
    print_usage(argv[0]);
    return 0;
}

//Проверка параметров
static int check_params(struct params * const params)
{
    if (params->option == OPT_WRITE) {
        /* Существует ли данный файл и можно к нему получить доступ? */
        if (access(params->msg_filename, F_OK) == -1) {
            fprintf(stderr, "Specified file doesn't exist\n");
            return 0;
        }
    }

    return 1;
}

//Пользовательский процесс записи
static void do_ioctl_write(int fd, char *msg_filename)
{
    FILE *msg_file; //Файл
    long msg_file_size; //Размер сообщения
    char *buf; //Буфер

    msg_file = fopen(msg_filename, "r"); //Открыть файл
    if (msg_file == NULL) { //Проверка на открытие
        perror("Error opening message file");
        return;
    }

    /* Получение размера файла */
    fseek(msg_file, 0L, SEEK_END);
    msg_file_size = ftell(msg_file);
    rewind(msg_file); //Перевод на начало

    /* Выделение памяти в буфере для всего содержимого файла */
    buf = malloc(sizeof(char) * (msg_file_size + 1));
    if (!buf) { //Ошибка веделения памяти
        fprintf(stderr, "Memory allocation failed");
        goto err_buf;
    }

    /* Копирование содержимого файла в буфер */
    if (fread(buf, msg_file_size, 1, msg_file) != 1) { //Ошибка копирования 
        fprintf(stderr, "File reading failed");
        goto err_fread;
    }

    fclose(msg_file); //Закрытие файла

    if (ioctl(fd, MIOC_IOCWRITE, buf) == -1) //Ошибка записи в IOCTL
        perror("Error occurred on write ioctl");

    free(buf); //Освобождение буфера

    return;

//Обработка ошибок
err_fread:
    free(buf);
err_buf:
    fclose(msg_file);
}

//Пользовательский процесс на удаление 
static void do_ioctl_erase(int fd)
{
    if (ioctl(fd, MIOC_IOCERASE) == -1)
        perror("Error occurred on erase ioctl");
}

int main(int argc, char *argv[])
{
    struct params params; //Структура
    int fd; //Дескриптор 

    if (!parse_params(argc, argv, &params)) //Определение команды из командной строки
        return EXIT_FAILURE; //макрос неудачного завершения программы
    if (!check_params(&params))
        return EXIT_FAILURE; //макрос неудачного завершения программы


    fd = open(DEV_FILE, O_WRONLY); //Открытие файла
    if (fd == -1) { //Ошибка открытия файла? 
        perror("Failed to open MIOC dev file");
        return EXIT_FAILURE;
    }

    switch (params.option) { //Выбранная команда
    case OPT_WRITE: 
        do_ioctl_write(fd, params.msg_filename); //Запись
        break;
    case OPT_ERASE:
        do_ioctl_erase(fd); //Удаление
        break;
    default:
        fprintf(stderr, "Unknown option\n"); //Не предусмотренная
        return EXIT_FAILURE;
    }

    close(fd); //Закрыть файл

    return EXIT_SUCCESS; //Возвращение макроса успешного завершения программы
}
У вопроса есть решение - Посмотреть?

https://ru.stackoverflow.com/questions/455936/%d0%9a%d0%b0%d0%ba-%d1%80%d0%b0%d0%b7%d0%b4%d0%b5%d0%bb%d0%b8%d1%82%d1%8c-%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d1%8c-%d0%b4%d1%80%d0%b0%d0%b9%d0%b2%d0%b5%d1%80-%d0%ba%d0%bb%d0%b0%d0%b2%d0%b8%d0%b0%d1%82%d1%83%d1%80%d1%8b-linux-%d0%bd%d0%b0-%d0%b4%d0%b2%d0%b0#comment492378_455936
опять кросс-компиляция? без утилит, собранных для целевой платформы, не получится.
https://ru.stackoverflow.com/questions/455936/%d0%9a%d0%b0%d0%ba-%d1%80%d0%b0%d0%b7%d0%b4%d0%b5%d0%bb%d0%b8%d1%82%d1%8c-%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d1%8c-%d0%b4%d1%80%d0%b0%d0%b9%d0%b2%d0%b5%d1%80-%d0%ba%d0%bb%d0%b0%d0%b2%d0%b8%d0%b0%d1%82%d1%83%d1%80%d1%8b-linux-%d0%bd%d0%b0-%d0%b4%d0%b2%d0%b0#comment493620_455936
@alexanderbarakin что за утилиты? какие?
https://ru.stackoverflow.com/questions/455936/%d0%9a%d0%b0%d0%ba-%d1%80%d0%b0%d0%b7%d0%b4%d0%b5%d0%bb%d0%b8%d1%82%d1%8c-%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d1%8c-%d0%b4%d1%80%d0%b0%d0%b9%d0%b2%d0%b5%d1%80-%d0%ba%d0%bb%d0%b0%d0%b2%d0%b8%d0%b0%d1%82%d1%83%d1%80%d1%8b-linux-%d0%bd%d0%b0-%d0%b4%d0%b2%d0%b0#comment493621_455936
почитайте, пожалуйста, про кросс-компиляцию. начинать можно, например, отсюда .
https://ru.stackoverflow.com/questions/455936/%d0%9a%d0%b0%d0%ba-%d1%80%d0%b0%d0%b7%d0%b4%d0%b5%d0%bb%d0%b8%d1%82%d1%8c-%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d1%8c-%d0%b4%d1%80%d0%b0%d0%b9%d0%b2%d0%b5%d1%80-%d0%ba%d0%bb%d0%b0%d0%b2%d0%b8%d0%b0%d1%82%d1%83%d1%80%d1%8b-linux-%d0%bd%d0%b0-%d0%b4%d0%b2%d0%b0#comment674712_455936
Как оказалось, проблема заключается в кириллическом названии папки, а именно «рабочий стол».
https://ru.stackoverflow.com/questions/455936/%d0%9a%d0%b0%d0%ba-%d1%80%d0%b0%d0%b7%d0%b4%d0%b5%d0%bb%d0%b8%d1%82%d1%8c-%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d1%8c-%d0%b4%d1%80%d0%b0%d0%b9%d0%b2%d0%b5%d1%80-%d0%ba%d0%bb%d0%b0%d0%b2%d0%b8%d0%b0%d1%82%d1%83%d1%80%d1%8b-linux-%d0%bd%d0%b0-%d0%b4%d0%b2%d0%b0#comment674713_455936
@Stein_ Откуда в линуксе папка "рабочий стол"? Причём тут кириллица, если вопрос: "как разделить модуль на два"?
https://ru.stackoverflow.com/questions/455936/%d0%9a%d0%b0%d0%ba-%d1%80%d0%b0%d0%b7%d0%b4%d0%b5%d0%bb%d0%b8%d1%82%d1%8c-%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d1%8c-%d0%b4%d1%80%d0%b0%d0%b9%d0%b2%d0%b5%d1%80-%d0%ba%d0%bb%d0%b0%d0%b2%d0%b8%d0%b0%d1%82%d1%83%d1%80%d1%8b-linux-%d0%bd%d0%b0-%d0%b4%d0%b2%d0%b0#comment674767_455936
@NickVolynkin, автор вопроса зачем-то переделал его в другой. все ответы и комментарии относятся к первоначальному варианту.
https://ru.stackoverflow.com/questions/455936/%d0%9a%d0%b0%d0%ba-%d1%80%d0%b0%d0%b7%d0%b4%d0%b5%d0%bb%d0%b8%d1%82%d1%8c-%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d1%8c-%d0%b4%d1%80%d0%b0%d0%b9%d0%b2%d0%b5%d1%80-%d0%ba%d0%bb%d0%b0%d0%b2%d0%b8%d0%b0%d1%82%d1%83%d1%80%d1%8b-linux-%d0%bd%d0%b0-%d0%b4%d0%b2%d0%b0#comment674777_455936
@NickVolynkin, в домашнем каталоге пользователя по умолчанию создаются несколько каталогов согласно стандартам xdg, и один из них в локализованном варианте вполне может называться «рабочий стол». см. , к примеру, этот ответ: ru.stackoverflow.com/a/481303/178576

Ответы - Как разделить модуль-драйвер клавиатуры (linux) на два? / Как разделить модуль-драйвер клавиатуры (linux) на два?

Является ответом!
Hermann Zheboldov

05.10.2015 10:18:23

sudo dpkg -s binutils

Если пакет binutils не установлен, то нужно установить: sudo apt-get install binutils

Затем пробуйте снова

https://ru.stackoverflow.com/questions/455936/%d0%9a%d0%b0%d0%ba-%d1%80%d0%b0%d0%b7%d0%b4%d0%b5%d0%bb%d0%b8%d1%82%d1%8c-%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d1%8c-%d0%b4%d1%80%d0%b0%d0%b9%d0%b2%d0%b5%d1%80-%d0%ba%d0%bb%d0%b0%d0%b2%d0%b8%d0%b0%d1%82%d1%83%d1%80%d1%8b-linux-%d0%bd%d0%b0-%d0%b4%d0%b2%d0%b0/455951#comment492218_455951
Увы Не помогает
https://ru.stackoverflow.com/questions/455936/%d0%9a%d0%b0%d0%ba-%d1%80%d0%b0%d0%b7%d0%b4%d0%b5%d0%bb%d0%b8%d1%82%d1%8c-%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d1%8c-%d0%b4%d1%80%d0%b0%d0%b9%d0%b2%d0%b5%d1%80-%d0%ba%d0%bb%d0%b0%d0%b2%d0%b8%d0%b0%d1%82%d1%83%d1%80%d1%8b-linux-%d0%bd%d0%b0-%d0%b4%d0%b2%d0%b0/455951#comment492380_455951
потрясяающий ответ! без программ, входящих в пакет binutils, операционная система и загрузиться не сможет. загрузится только программа linux и сообщит о том, что «она в панике» (kernel panic!!!).
Закрыть X