Был у меня старенький SSD объёмом 240 Гбайт от Kingston, который внезапно перестал работать, вообще перестал распознаваться в системе. Попробовал я подключить SSD к другому компьютеру, попробовал использовать как внешний диск, ничего не дало результата. Поэтому я купил новый, а этот разобрал.
Внешних признаков, указывающих на то, что SSD сгорел, я не заметил, а интуиция говорила: «Проблема программная». Выбрасывать диск не хотелось, поэтому он остался пылиться до «лучших» времён. И вот недавно захотелось попробовать его починить. К своему удивлению, я достаточно быстро нашёл необходимую статью на Хабре, где рассказывалось, как можно оживить SSD на том же контроллере, что и мой, отдельную тему на форуме Ru-Board, а также статью с подробной инструкцией, по ней я и восстановил свой SSD. Но кроме восстановленного SSD я еще приобрёл и закрепил знания по Linux, которые изложил в этой статье. Всем, кому интересно, добро пожаловать под кат.
Содержание
- Вместо введения
- Как я восстановил свой SSD
- Создание ISO-образа Live-диска
- Внутреннее устройство дистрибутивов Linux
- Создание дистрибутива на внешнем диске
- Создание Live USB-диска
- Выводы
В статье по восстановлению SSD рекомендовалось использовать 32-разрядную версию Fedora 14. Немного погуглив, я нашёл загрузочный ISO-образ этой операционной системы и с помощью программы Balena Etcher записал на флешку. Попытался загрузиться с флешки на своём мини-ПК, но меня ждало разочарование: Fedora 14 зависала при загрузке.
И с этого момента началось неожиданное и интересное для меня погружение в Linux на несколько месяцев, позволившее мне углубить и систематизировать свои знания в Linux.
Я подумал, что, возможно, операционная система очень старая, и могут быть особенности загрузки с флешки. Поэтому решил использовать старый и проверенный способ — карман Zalman, но и это не помогло. Использование Ventoy также не дало результата — операционная система не загружалась. В моём понимании проблема была в том, что Live-диск Fedora 14 не поддерживал загрузку с USB 3.0 и чипсет моего мини-ПК.
Желание починить диск было велико, поэтому я нашёл на антресолях свой старый ноутбук ASUS K53E и без труда, установив древнюю Fedora 14, по инструкции восстановил свой SSD. Но непреодолимый интерес понять, как же выполнить эту процедуру на мини-ПК с современной версией Linux, не покидал меня.
В основном я работаю с дистрибутивами Linux, основанных на Debian. На мини-ПК была установлен Kali Linux. SATA-разъём, куда можно было подключить SSD, был свободен, поэтому я использовал данную конфигурацию для своих экспериментов. Я думаю, что настроить всё можно и на любом дистрибутиве, основанном на Debian.
Успешное восстановление диска дало мне мотивацию, так возникли приятные ощущения полезности, применимости и завершённости, которые, как мне кажется, мотивируют в изучении нового. В итоге я создал свой Live-диск, содержащий всё необходимое для восстановления SSD на контроллерах SandForce SF-2XXX.
Я решил задокументировать своё понимание и действия в виде статьи и думаю, что сведения, изложенные в ней, могут оказаться полезными тем, кто хочет улучшить своё понимание внутреннего устройства Linux.
Вместо введения
Задумывались ли вы когда-нибудь, почему исполняемый файл для Linux не запускается в Windows, или даже один и тот же исполняемый файл в различных дистрибутивах Linux также может не работать?
Всё дело в том, что исполняемый файл имеет определённый формат, содержит инструкции для определённой архитектуры процессора (Instruction Set Architecture) и в большинстве случаев рассчитывает на наличие определённых разделяемых (динамических) библиотек определённых версий, скомпилированных под определённый Application Binary Interface (ABI). Если правильно настроить операционную систему, то файл запустится и выполнится. Не во всех случаях, но с большой долей вероятности. Получилось это и у меня.
Основная задача, которая стояла передо мной, — заставить приложения с графическим пользовательским интерфейсом, успешно запускаемые в 32-разрядной Fedora 14 запуститься на современном компьютере с 64-разрядным дистрибутивом Linux, основанном на Debian.
▍ Instruction Set Architecture
Instruction Set Architecture (ISA) определяет, какие инструкции поддерживает процессор, как организована его работа с памятью, как хранятся различные типы данных, поддерживаемые процессором. Для настольных компьютеров и ноутбуков в большинстве случаев используется ISA x86. Под x86 понимают две версии архитектуры: 32-разрядную IA-32 и 64-разрядную AMD64. Разрядность платформы определяется разрядностью регистров процессора.
По историческим причинам и из-за маркетологов IA-32 и AMD64 имеют много других названий. Например, вместо AMD64 вы можете встретить X86-64, Intel64, EMT64, а вместо IA-32 — x86. Часто x86 используют как общий термин для 32-разрядной IA-32 и 64-разрядной архитектуры AMD64. Я считаю, что AMD64 и IA-32 наиболее правильные термины, так как они отражают вклад AMD и Intel в разработку ISA и разрядность архитектуры. Интересно, но X32 — не является синонимом IA-32, a IA-64 мало имеет общего с AMD64.
В рамках ISA неважно, как реализована аппаратная архитектура процессора. Процессор может реализовывать несколько ISA, работая в разных режимах, а процессоры с разной аппаратной архитектурой реализовывать одну и ту же ISA. Поэтому современные процессоры Intel и AMD реализовывают ISA AMD64, в то же время процессор, реализующий ISA AMD64, может работать в режиме, соответствующем ISA IA-32.
▍ Application Binary Interface
Как говорилось ранее, исполняемый файл или разделяемая (динамическая) библиотека создаётся под определённый Application Binary Interface (ABI). ABI разрабатывается для конкретной ISA и содержит низкоуровневые требования к исполняемым файлам, библиотекам, системным вызовам операционной системы и их взаимодействию, а именно:
- как вызываются функции,
- как хранятся данные в оперативной памяти,
- как происходят системные вызовы операционной системы.
Если ISA определяется процессором, то ABI определяется ядром операционной системы. Ядро реализовывает один или несколько ABI. Для каждого ISA может существовать одно или несколько ABI. Например, для ISA AMD64 существуют System V ABI x86-64 в Linux и x64 ABI в Windows. В названиях ABI, как и в случае с ISA можно запутаться. Linux, Free BSD используют System V ABI: x86_64, i386, AArch32, AArch64, Windows использует ABI x86, x64, ARM32, ARM64.
Спецификация System V ABI содержит ещё описание формата ELF, в котором хранятся исполняемые файлы и библиотеки.
▍ Application Program Interface
Системные вызовы ядра и библиотечные функции определяют Application Program Interface (API). Если приложение или библиотека зависит от отсутствующего системного вызова или функции в операционной системе, они не будут работать корректно.
▍ Форматы исполняемых файлов и библиотек
Операционная система в качестве основного использует определённый формат исполняемого файла. Например, Windows использует формат Portable Executable (PE), Linux — очень часто Executable and Linkable Format (ELF), macOS — Mach-O. Формат исполняемого файла и ABI — это не одно и то же.
В Linux существует несколько команд, которые позволяют изучить структуру исполняемого файла.
-
Команда file:
# file /bin/bash
Позволяет посмотреть на формат исполняемого файла и используемый ABI. В приведённом примере это файл /bin/bash. Чтобы вы могли воспользоваться этой командой, должен быть установлен пакет file.
-
Команда ldd:
# ldd /bin/bash
Команда требует установленного пакета libc-bin.
-
Команда readelf:
# readelf -dh /bin/bash
Команда требует установленного пакета binutils.
Вы можете спросить, откуда у меня информация, какой пакет содержит команду?
Для дистрибутивов, основанных на Debian, эту информацию можно получить, установив пакет apt-file и выполнив команду apt-file:
# apt update && apt install apt-file
# apt-file search имя команды
▍ Выполнение требований к исполняемому файлу
Таким образом, чтобы исполняемый файл для 32-разрядного дистрибутива Linux x86 запустился в 64-разрядном дистрибутиве Linux x86, нужно выполнить требования к ISA, ABI, API и формату исполняемого файла.
Выполнение требования к ISA обеспечивается установленным процессором, это требование выполнится автоматом, так как процессоры c ISA AMD64 поддерживают ISA IA-32.
-
Выполнение требования к ABI, обеспечивается ядром Linux. Оно должно поддерживать i386. Большинство ядер, которые рассчитаны на ABI x86-64, скомпилированы так, что эмулируют ABI i386. Чтобы узнать, поддерживается ABI i386 или нет, нужно посмотреть параметр компиляции ядра CONFIG_IA32_EMULATION с помощью команд:
# cat /boot/config-$(uname -r) | grep CONFIG_IA32_EMULATION
или
# zcat /proc/config.gz | grep CONFIG_IA32_EMULATION
в зависимости от дистрибутива. К счастью, у большинства дистрибутивов Linux в ядре этот параметр включён.
Выполнение требования к API обеспечивается установленными библиотеками. Нужно добиться того, чтобы все требуемые разделяемые библиотеки были доступны загрузчику образа исполняемого файла. Как узнать, какие библиотеки требуются для выполнения исполняемого файла, мы рассмотрим позже.
Требование к формату исполняемому файлу выполняется, так как и Linux x64, и Linux x86 используют один и тот же формат.
▍ Multiarch в дистрибутивах, основанных на Debian
В дистрибутивах, основанных на Debian, реализована возможность для удобной работы с исполняемыми файлами для ABI, которые не являются родными для дистрибутива. Например, в дистрибутиве с ABI x86-64 работать с библиотеками, рассчитанными для ABI i386. Эта возможность называется Multiarch, а для ABI используется термин архитектура.
Обратите внимание, что Multiarch только позволяет установить библиотеки для другого ABI и делает их доступными для запускаемых исполняемых файлов. Multiarch не выполняет никакой эмуляции, то есть, если процессор не поддерживает ISA, на которое рассчитывает исполняемый файл, он не выполнится. Если вам это необходимо, то можно воспользоваться функцией ядра binfmt_misc совместно с эмулятором, например, QEMU. Но это уже отдельная тема, не относящаяся к моей статье.
Здесь вы можете посмотреть, какие архитектуры поддерживают дистрибутивы Debian.
Посмотреть, какая у вас основная архитектура в Debian можно командой:
# dpkg --print-architecture
Посмотреть, исполняемые библиотеки каких архитектур можно установить в ваш дистрибутив Debian:
# dpkg --list-foreign-architectures
Установить поддержку архитектуры i386:
# dpkg --add-architecture i386 && apt update
Удалить архитектуру сложнее, поэтому расскажу, как это сделать позже.
Как я восстановил свой SSD
Я восстановил SSD в Kali Linux, но, я думаю, без проблем можно воспользоваться любым 64-разрядным дистрибутивом Linux, основанном на Debian 12.
Находим и загружаем набор приложений для восстановления SSD-дисков на контроллере SandForce, о котором рассказывалось в статье Восстановление SSD дисков на контроллере SandForce SF-2XXX.
Переходим в директорию SF_Genesis-v1.7.0.01020130612-fc14-32bit.
-
Выполняем команду:
# file SF_Genesis
Видим, что этот исполняемый файл рассчитан на System V i386 ABI, поэтому нам нужно включить поддержку System V i386 в Debian.
-
Проверяем, что поддержка System V i386 ABI не установлена:
# dpkg --print-foreign-architectures
-
Устанавливаем поддержку System V i386 ABI:
# dpkg --add-architecture i386 && apt update
-
Исполняемый файл ELF c разделяемыми библиотеками содержит в себе информацию о том, какой загрузчик он ожидает для разворачивания файла в оперативной памяти. Узнать, какой файл требуется, можно при помощи команды:
# readelf -dh SF_Genesis
В нашем случае это будет файл ld-linux.so.2
-
Находим пакет, который его содержит, и устанавливаем его:
# apt-file update && apt-file search -a i386 ld-linux.so.2 # apt-file install libc:i386
Обратите внимание, что в обеих командах используется название ABI i386 (-a i386 и libc:i386)
-
Проверяем, что все зависимости для файла SF_Genesis разрешены:
# ldd SF_Genesis
-
Берём следующий файл, например, SF_ConfigurationManager и проверяем, разрешены ли все зависимости:
# ldd SF_ConfigurationManager
-
Идём по списку неразрешённых зависимостей, ищем пакеты, которые содержат нужные файлы и устанавливаем их. Чтобы сэкономить ваше время, я ниже приведу, какие пакеты необходимо в конечном счёте установить:
# apt install -y libsm6:i386 \ libxrender1:i386 \ libfontconfig1:i386 \ libxext6:i386 \ libstdc++6:i386
Проверяем, что исполняемые файлы в директории SF_Genesis-v1.7.0.01020130612-fc14-32bit запускаются и работают в 64-разрядной версии Debian.
-
Нужно ещё установить пакет lsscsi, остальные пакеты из статьи по восстановлению SSD мне не понадобились. Можно смело ставить 64-разрядную версию пакета:
# apt install -y apt install -y lsscsi
Теперь вы можете восстанавливать SSD.
Инструкция полезная и содержательная, но мне вспомнилась история из моих студенческих лет. На одном из предметов мы изучали AutoCAD, и одно из практических занятий было посвящено созданию кастомного меню в AutoCAD. Преподаватель очень подробно рассказывал, как его сделать, но забывал рассказать, как вернуть стандартное меню на место. На старших курсах, приходя в компьютерный класс, мы всегда знали, когда студенты младших курсов изучали создание пользовательского меню в AutoCAD. Поэтому приведу инструкцию, как убрать поддержку ABI 386.
-
Выводим список пакетов с ABI i386:
# dpkg -l | grep i386
-
Удаляем все пакеты с ABI i386:
# apt-get purge --allow-remove-essential ".*:i386"
-
Проверяем, что пакеты удалились:
# dpkg -l | grep i386
-
Деактивирует поддержку ABI i386:
# dpkg --remove-architecture i386
-
Проверяем, что её нет среди поддерживаемых архитектур:
# dpkg --print-foreign-architectures
Создание ISO-образа Live-диска
Эйфория от восстановленного своими руками SSD, побудила меня создать ISO-образа Live-диска, сразу содержащий все установленные пакеты и специально предназначенный для восстановления SSD. Я привык работать с командной строкой Linux, поэтому решил использовать приложения из пакета live-build, а чтобы можно было без труда повторить создание Live-диска на различных компьютерах и операционных системах, я использовал Docker.
-
Создаём директорию, в которой будем собирать ISO-образ. Создадим директорию и в директорию Applications поместим приложения, для восстановления диска. Для Linux и macOS это будет выглядеть следующим образом:
# mkdir ~/asld-iso && cd ~/asld-iso # mkdir -p Applications # cp -r ~/Genesis ./Applications
-
Запускаем Docker-контейнер:
-
macOS:
# docker run --platform=linux/amd64 --privileged \ -v $(pwd):/app -it --rm debian /bin/bash
-
Linux:
# sudo docker run --platform=linux/amd64 --privileged \ -v $(pwd):/app -it --rm debian /bin/bash
-
Windows:
# cmd /c "docker run -v %cd%:/app -it --privileged --platform linux/amd64 debian"
-
-
Устанавливаем пакет live-build:
# apt update && apt install -y live-build
-
Создаём директорию, куда будет помещаться образ:
# mkdir -p ~/build && cd ~/build
-
Создаём конфигурацию сборки:
# lb config \ --archive-areas "main contrib non-free-firmware non-free" \ -b iso-hybrid \ --clean \ --iso-application asld-live \ --distribution bookworm
-
Добавляем в конфигурацию пакеты с ABI i386, необходимые приложениям по восстановлению диска, дисплейный менеджер, несколько графических приложений (терминал, текстовый редактор, файловые менеджеры nautilus и mc), офисный пакет libreoffice, open-vm-tools-desktop для интеграции с VMWare, и apt–file — для упрощения поиска пакетов по содержащихся в них файлах:
# echo "libc6:i386 libsm6:i386 libxrender1:i386 \ libfontconfig1:i386 libxext6:i386 libstdc++6:i386 lsscsi \ gdm3 gnome-shell gnome-terminal gnome-text-editor nautilus \ libreoffice mc open-vm-tools-desktop apt-file" > \ ./config/package-lists/extra-packages.list.chroot
Вы можете добавить ещё дополнительные пакеты, если хотите их наличие из коробки. Обратите внимание, что нам не нужно добавлять поддержку архитектуры i386, это live-build сделает за нас.
-
Добавляем браузер Chrome в конфигурацию. Можно и без Сhrome, или установить браузер, который находится в репозитории Debian, например, Firefox, но я решил сделать чуть интереснее:
# wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \ -P ./config/packages.chroot/
-
Помещаем в конфигурацию исполняемые файлы:
# mkdir -p config/includes.chroot/home/user # cp --verbose -r /app/Applications config/includes.chroot/home/user
-
Запускаем сборку загрузочного ISO-образа:
# lb build
-
Копируем созданный образ в рабочую директорию хостовой операционной системы:
# mkdir -p /app/out # cp --verbose live-image-amd64.hybrid.iso /app/out/asld-live.iso
-
Завершаем работу Docker-контейнера:
# exit
-
Проверяем, что образ корректно работает. Можно предварительно проверить в эмуляторе, но в эмуляторе вы не сможете проверить полностью корректную работу программ по восстановлению диска, только то, что они запускаются. В качестве эмулятора я выбирал QEMU, но удовлетворительные результаты по скорости работы были только в Linux. В Windows для проверки я использовал VMWare Workstation. Запустить QEMU в Linux можно командой:
# cd out # sudo qemu-system-x86_64 \ -accel kvm \ -boot d \ -display gtk \ -vga virtio \ -drive file=live-image-amd64.hybrid.iso,media=cdrom \ -m 4096
Внутреннее устройство дистрибутивов Linux
Создание ISO-образа Live-диска с помощью live-build достаточно простой для пользователя процесс.
Многие вещи можно делать не сильно понимая их суть: по примеру или методом научного тыка. Но всё-таки лучше, когда у тебя есть понимание предмета. Поэтому я продолжил разбираться и установил Linux на внешний SSD «с нуля» без всяких установщиков. Ниже я приведу немного теории, чтобы лучше были понятны выполненные действия.
▍ Загрузка операционной системы
Процесс передачи управления от встроенного программного обеспечения (BIOS/UEFI) системному (операционная система) можно назвать загрузкой операционной системы. В загрузке операционной системы участвуют:
- BIOS/UEFI,
- загрузчик,
- ядро операционной системы.
▍ BIOS/UEFI
Исторически так сложилось, что в понятиях BIOS и UEFI существует путаница. Производители материнских плат, вероятно, чтобы не пугать неподготовленного пользователя новыми терминами, под BIOS понимают как BIOS, так и UEFI. Но на самом деле между BIOS и UEFI существует три принципиальных отличия:
- В каком режиме работает процессор при передаче управления загрузчику (реальный в случае BIOS и защищённый в случае UEFI).
- Механизм загрузки загрузчика.
- Механизм взаимодействия с системным программным обеспечением (программные прерывания в BIOS и протоколы в UEFI).
В BIOS (если не рассматривать расширения Eltorito и PXE) используется простейший механизм передачи управления загрузчику:
- нулевой сектор с загрузочного устройства помещается в оперативную память по адресу 0x07c00,
- процессор начинает выполнение команды расположенному по адресу 0x07c00.
В UEFI механизм загрузки немного сложнее. UEFI на загрузочном устройстве пытается найти и выполнить файл /EFI/BOOT/BOOTX64.EFI или /EFI/BOOT/BOOTIA32.EFI в зависимости от того 64-разрядный или 32-разрядный UEFI, но 32-разрядный UEFI я не встречал. BOOTX64.EFI или BOOTIA32.EFI являются полноценными исполняемыми файлами формата Portable Executable. Но в Windows вы их не запустите (оставляю читателю самому ответить на вопрос почему).
Многие UEFI поддерживают режим Compatibility Support Mode (CSM), который позволяет эмулировать BIOS. Его можно активировать в программе настройки UEFI. Обычно он называется CSM или Legacy.
▍ Загрузчик
Задача загрузчика — подготовить компьютер к передаче управления ядру операционной системы. Реализации загрузчика для BIOS и UEFI различаются, так как различаются механизмы взаимодействия загрузчика с BIOS и UEFI. В Linux наиболее распространённым является GRUB 2. Существуют его реализации для BIOS и UEFI.
▍ Ядро операционной системы
Ядро операционной системы позволяет драйверам и пользовательским программам взаимодействовать с аппаратным обеспечением компьютера. После передачи управления от загрузчика ядру операционной системы ядро уже использует свои драйверы для работы с устройствами компьютера.
▍ Разметка диска и файловые системы
Жёсткий диск, SSD, флешку можно рассматривать как устройство, хранящее данные блоками по 512 (4096) байт. Для идентификации каждого блока используется Logical Block Address (LBA), зная который можно записать данные на диск или считать с него. Блок часто ещё называется сектором. Ранее существовала адресация CHS (Cylinder, Head, Sector), но сейчас она почти не используется.
Существует сложившаяся практика разделять пространство диска на несколько независимых пространств, называемых разделами. Наиболее распространены разметка MBR и GPT. Разметка является особой записью на диске, которая содержит информацию:
- с какого сектора начинается каждый из разделов,
- сколько секторов занимает раздел,
- дополнительную метаинформацию.
Таблица MBR может содержать максимум 4 записи с описанием разделов, один из которых может быть расширенный, позволяющий создать практически неограниченное количество логических разделов.
Таблица GPT может содержать практически неограниченное количество разделов, хотя благодаря Microsoft обычно оно ограничено 128 разделами. Каждый из разделов обычно содержит директории и файлы. Для организации хранения директорий и файлов используются файловые системы. Файловая система — это соглашение о том, как хранятся файлы и метаинформация о них. Выбор файловых систем огромен, но для установки Linux важны FAT16/FAT32 и ext4.
▍ Ядро Linux
Ядро Linux, если рассматривать его как набор файлов, представляет собой три компонента:
- файл ядра, который располагается на доступном загрузчику носителе,
- модули ядра, динамически подключаемые компоненты ядра, расширяющие его функциональность,
- файлы firmware, бинарные файлы, необходимые для инициализации аппаратного обеспечения компьютера при загрузке файла ядра операционной системы или модулей ядра.
▍ Загрузка Linux
При загрузке Linux загрузчику нужно указать, где расположены два файла — файл ядра операционной системы и файл образа начальной корневой файловой системы (initramfs, который по историческим причинам часто имеет имя initrd). Возможен вариант загрузки без файла initramfs, но для архитектуры x86 этот вариант в настоящее время можно отнести к редким.
▍ Virtual File System и корневая файловая система Linux
Вероятно, вы слышали, что в Linux всё является файлом. Эта концепция обеспечивается компонентом Linux c названием Virtual File System (VFS). VFS позволяет организовать сущности в иерархическую структуру, состоящую из директорий и файлов.
Директория в VFS, может быть точкой монтирования. Точка монтирования служит для подключения файловой системы в иерархию VFS. Файловая система предоставляет интерфейс для VFS и реализовывается в виде драйвера. Драйвер файловой системы содержит программный код для доступа к данным, хранящихся где-либо.
Файловая система с точкой монтирования «/» называется корневой файловой системой. В ней располагаются файлы, необходимые для нормального функционирования ядра Linux. Важны директории /bin, /sbin, /dev, /proc, /sys, /run, /lib, /var. Для структуры корневой файловой системы существует стандарт Filesystem Hierarchy Standard, которого стараются придерживаться разработчики дистрибутивов Linux.
Из интересностей могу добавить, что модули ядра (не файл ядра) находятся в директории /lib/modules корневой файловой системы, а файлы firmware располагается в директории /lib/firmware.
▍ Пространство ядра и пользовательское пространство
Программный код выполняется в Linux изолированно. Ядро и пользовательские программы выполняются в различных пространствах, пространстве ядра (kernel space) и пользовательском пространстве (user space) соответственно. Точка входа в инициализацию kernel space — передача управления от загрузчика ядру, точка входа в инициализацию user space — запуск ядром пользовательского процесса с PID 1. Сейчас большинство дистрибутивов Linux загружается с использованием файла initramfs.
В этом случае корневой файловой системой изначально является ramfs, файл initramfs распаковывается ядром в неё и запускает процесс с PID 1 на основе /init корневой файловой системы.
Этот процесс инициализирует раннее пользовательское пространство, которое делает возможным поиск и монтирование постоянной корневой файловой системы и инициализацию позднего пользовательского пространства.
Для инициализации пользовательского пространства используются так называемые системы инициализации (init system). Обычно это systemd, но может быть sysvinit, OpenRC, runit и др.
▍ Графический пользовательский интерфейс Linux
Сейчас никого не удивишь операционной системой с графическим пользовательским интерфейсом. Эх, а были времена…
В Linux, конечно, можно работать в текстовом режиме, но только не в нашем случае — приложения для восстановления SSD требуют наличие графического пользовательского интерфейса.
Графический интерфейс Linux унаследовал графический интерфейс Unix с изменениями и улучшениями. Основа графического интерфейса — Display Server. Его возможности используют другие высокоуровневые компоненты, такие как Window Manager, Widget Toolkit и Desktop Environment.
Назначения компонентов:
- Display Server (дисплейный сервер) для низкоуровневых операций с вводом/выводом и дисплеем.
- Window Manager (менеджер окон) для управления положением и внешним видом окон.
- Widget Toolkit для элементов графического интерфейса (кнопки, ползунки, поля ввода).
- Desktop Environment (окружение рабочего стола), содержит набор графических пользовательских приложений.
Наиболее распространённые окружения рабочего стола Сinnamon, KDE, GNOME, LXDE, MATE и Xfce. Всегда есть из чего выбирать.
▍ Менеджер компьютерной сети
Невозможно представить современную операционную систему, которая не предоставляет сетевых возможностей, а тем более Linux. Чтобы были доступны сетевые возможности, необходимо иметь корректно настроенный сетевой интерфейс. Если раньше для этого требовались достаточные глубокие знания Linux, то теперь в простейшем случае с домашним роутером, достаточно, чтобы в Linux был установлен Network Manager, а на роутере — активирован DHCP. Если ваши сетевые адаптеры будут распознаны Linux, подключение к Ethernet или WiFi сети будет интуитивно простым, особенно при работе с использованием графического интерфейса.
▍ Менеджер пакетов
Обычно дистрибутив Linux является не монолитным, а состоит из пакетов. Пакет — это набор исполняемых файлов, библиотек, конфигурационных файлов по умолчанию, документации, который рассматривается атомарно, т. е. его можно установить, удалить, обновить как единое целое. Пакет может зависеть от других пакетов, и они должны быть установлены, чтобы программы или библиотеки из пакета работали корректно. У пакетов могут быть различные форматы, пакеты хранятся в репозитории, репозиторием может быть сетевое хранилище, а может CD/DVD диск.
Пакет хранит в себе определённую метаинформацию:
- имя пакета,
- версию пакета,
- описание пакета,
- список зависимостей.
Форматы пакетов:
- deb — Debian, Ubuntu, Linux Mint,
- rpm — Red Hat, Fedora, CentOS,
Для управления пакетами используется специальная программа, которая называется пакетным менеджером. Пакетный менеджер позволяет:
- устанавливать пакеты,
- удалять пакеты,
- обновлять пакеты,
- искать пакеты,
- просматривать информацию о пакетах.
Известные пакетные менеджеры:
- аpt — Debian, Ubuntu, Linux Mint,
- dnf, yum — Red Hat, Fedora, CentOS,
В Linux дистрибутивах, основанных на Debian, для управления пакетами используется apt и dpkg, что часто вводит в заблуждение. Однако всё становится понятнее, если рассматривать dpkg как «движок для работы с пакетами», используемый apt.
Apt содержит функционал, позволяющий работать с зависимостями пакетов, а также устанавливать пакеты из репозиториев, находящихся в сети.
▍ Создание «своего» дистрибутива Linux
Я перечислил основные составляющие типичной операционной системы Linux. Подведём итоги, чтобы вы знали, какие компоненты вам нужно собрать и заставить их работать вместе.
Операционная система Linux, которую можно назвать полноценной, должна содержать:
- загрузчик, который загружает и инициализирует ядро Linux,
- файл ядра,
- модули ядра,
- firmware,
- систему инициализации,
- пакетный менеджер,
- сетевой менеджер,
- базовый набор приложений и утилит,
- графическую подсистему.
В своей статье я уже рассказывал, как собрать свой Linux, но тогда упор делался на сборку из исходников. В результате у него был ряд ограничений. Например, он использовал не постоянную корневую файловую систему, а ограничивался временной, созданной на основе содержимого файла initramfs.
В дистрибутивах Debian есть пакет debootstrap, который упрощает собирание всех этих компонентов Linux. Далее я приведу последовательность шагов, как можно это сделать, используя команду debootstrap из этого пакета совместно с командой chroot.
Создание дистрибутива на внешнем диске
Работа Docker-контейнера в различных операционных системах может отличаться. Например, в Windows или macOS внешний диск в Docker-контейнерe не виден как блочное устройство. Поэтому, чтобы охватить большую аудиторию, будем использовать образ диска и loop-устройства. Следует заметить, что для приведённых в статье действий понадобится немало свободного места на диске.
-
Инициализируем директорию, где будем выполнять сборку:
# mkdir ~/asld-hdd && cd ~/asld-hdd # mkdir -p Applications # cp -r ~/Genesis ./Applications
-
Запускаем Docker-контейнер:
# docker run --platform=linux/amd64 --privileged \ -v $(pwd):/app -it --rm debian /bin/bash
-
Создаём директорию, где будем собирать содержимое корневой файловой системы:
# mkdir -p ~/build/chroot && cd ~/build/chroot
-
Устанавливаем debootstrap, необходимый для первоначального наполнения корневой файловой системы:
# apt update && apt install -y debootstrap
-
Выполняем команду debootstrap:
# debootstrap \ --include=linux-image-amd64,firmware-linux \ --components=main,contrib,non-free-firmware \ --arch=amd64 bookworm . https://deb.debian.org/debian
-
Можно посмотреть, откуда apt будет брать пакеты:
# cat ./etc/apt/sources.list
-
Для полноценной работы в chroot-окружении нужно смонтировать в него системные директории:
# for dir in dev dev/pts proc sys run; \ do mount --bind /$dir ./$dir; done
-
Переключаемся в chroot окружение:
# LANG=C.UTF-8 chroot . /bin/bash
-
Устанавливаем пароль для root:
# passwd root
-
Настраиваем сеть:
# apt install -y network-manager # echo asld-linux > /etc/hostname
-
Устанавливаем пакет sudo:
# apt install -y sudo
-
Добавляем пользователя user с домашней директорией и оболочкой bash по умолчанию:
# useradd -m -s /bin/bash user
-
Добавляем пользователя user в группу sudo:
# usermod -aG sudo user
-
Устанавливаем пароль для user:
# passwd user
-
Добавляем поддержку архитектуры i386. Поддержка архитектуры означает, что теперь Debian сможет устанавливать пакеты для архитектуры i386:
# dpkg --add-architecture i386 && apt update
-
Устанавливаем недостающие пакеты:
# apt install -y \ libc6:i386 libsm6:i386 libxrender1:i386 libfontconfig1:i386 libxext6:i386 \ libstdc++6:i386 lsscsi gdm3 gnome-shell gnome-terminal gnome-text-editor \ nautilus mc libreoffice open-vm-tools-desktop apt-file
-
Устанавливаем Google Chrome:
# apt install -y wget # wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb # apt install -y ./google-chrome-stable_current_amd64.deb # rm ./google-chrome-stable_current_amd64.deb
-
Настраиваем Autologin:
# cat > /etc/gdm3/daemon.conf <<EOF [daemon] AutomaticLoginEnable = true AutomaticLogin = user EOF
-
Выходим из chroot:
# exit
-
Размонтируем системные директории:
# for dir in dev/pts dev proc sys run; do umount ./$dir; done
-
Определяем размер файла-образа. Внутри файла-образа будет два раздела: ESP — для установки загрузчика GRUB и Linux-раздел, где будет располагаться корневая файловая система:
# du -sh ~/build/chroot # du -sh /app/Applications
-
Создаём файл образа размером, достаточным для размещения всех файлов из директорий /build/chroot и /app/Applications: В моём случае я выбрал размер 10 Гбайт:
# fallocate -l 10G ~/build/asld-hdd.img
-
Устанавливаем пакеты, необходимые для разметки диска, форматирования разделов и установки загрузчика:
# apt update && apt install -y fdisk dosfstools grub-efi kpartx
-
Выполняем разметку образа:
# echo -e ",200M,U\n,+\n" | sfdisk -X gpt ~/build/asld-hdd.img
-
Чтобы можно было работать с разделами, необходимо создать loop-устройство, которое будет представлять образ:
# BLOCK_DEVICE=$(losetup --show -f ~/build/asld-hdd.img) # LOOP_NAME="${BLOCK_DEVICE##*/}" # echo "BLOCK_DEVICE=$BLOCK_DEVICE LOOP_NAME=$LOOP_NAME"
-
Чтобы разделы, расположенные в образе, были видны как блочные устройства, используем команду kpartx. Особенностью команды является то, что она работает в пространстве пользователя и не зависит от udev, соответственно её можно использовать в Docker-контейнере:
# kpartx -av $BLOCK_DEVICE
-
Форматируем ESP и Linux-раздел:
# ESP_PARTITION="/dev/mapper/${LOOP_NAME}p1" # ROOT_PARTITION="/dev/mapper/${LOOP_NAME}p2" # mkfs.vfat "$ESP_PARTITION" # mkfs.ext4 "$ROOT_PARTITION"
-
Монтируем отформатированные разделы:
# ESP_PATH=/mnt/esp # ROOTFS_PATH=/mnt/rootfs # mkdir -p $ESP_PATH # mkdir -p $ROOTFS_PATH # mount $ESP_PARTITION $ESP_PATH # mount $ROOT_PARTITION $ROOTFS_PATH
-
Копируем содержимое корневой файловой системы и пользовательские программы на созданный раздел Linux:
# cp --verbose -rT ~/build/chroot/ $ROOTFS_PATH/ # cp -r --verbose /app/Applications $ROOTFS_PATH/home/user
-
Устанавливаем GRUB в образ:
# grub-install --removable --root-directory $ROOTFS_PATH --efi-directory $ESP_PATH --target=x86_64-efi $BLOCK_DEVICE
-
Обратите внимание, что файлы GRUB 2 будут установлены на два раздела. На ESP-раздел будет установлено минимальное количество файлов, которые нужны UEFI для начальной загрузки GRUB2. Остальные будут установлены на Linux-раздел:
# ls -lA $ESP_PATH/EFI/BOOT # ls -lA $ROOTFS_PATH/boot/grub # ls -lA $ROOTFS_PATH/boot/grub/x86_64-efi
-
Теперь необходимо, чтобы ядро Linux знало, на какой раздел использует корневая файловая. Раньше использовали имена блочных устройств для работы с разделами на диске, например, /dev/sda1. Но этот способ неудобен из-за непереносимости. Более удобно использовать метки файловых систем, идентификаторы разделов или идентификаторы файловых систем. Наиболее распространённой практикой является использование идентификаторов файловых систем. Определяем UUID файловой системы на разделе и создаём соответствующую конфигурацию GRUB 2:
# UUID=$(blkid -s UUID -o value $ROOT_PARTITION) # echo $UUID # cat > $ROOTFS_PATH/boot/grub/grub.cfg <<EOF set timeout=30 menuentry "ASLD Linux" { linux /vmlinuz root=UUID=$UUID initrd /initrd.img } EOF # cat $ROOTFS_PATH/boot/grub/grub.cfg
Обращу ваше внимание, что поиск раздела с файловой системой по UUID выполняют скрипты, находящиеся в initramfs, а не ядро Linux. Скрипты используют параметры, передаваемые ядру, поэтому это может вводить в заблуждение.
-
Чтобы Linux корректно смонтировал корневую файловую систему, создаём файл /etc/fstab, содержащий информацию о том, как монтировать файловую систему, находящуюся на диске в корневую файловую систему Linux. Также используем UUID вместо имени блочного устройства:
# echo "UUID=$UUID / ext4 defaults,errors=remount-ro 0 1" > $ROOTFS_PATH/etc/fstab
-
Корректно освобождаем ресурсы — смонтированные файловые системы, mappings, созданные командой kpartx и loop-устройство, созданное для образа:
# umount $ESP_PATH # umount $ROOTFS_PATH # kpartx -dv $BLOCK_DEVICE # losetup -d $BLOCK_DEVICE
Важен порядок освобождения ресурсов, а также то, что loop-устройства, созданные в Docker-контейнере, разделяются среди всех контейнеров. Поэтому не забывайте их освобождать командой losetup -d.
-
Копируем созданный образ в папку хостовой операционной системы, чтобы его можно было записать на диск.
# mkdir -p /app/out # cp ~/build/asld-hdd.img /app/out
-
Завершаем работу контейнера:
# exit
Теперь файл asld-hdd.img можно записать на внешний диск с помощью balenaEtcher и загрузиться с диска.
▍ Live-диски
Live-диск — это внешний USB-накопитель или оптический диск, на который особым образом установлена операционная система. Для работы с операционной системой, установленной таким способом, достаточно загрузиться с Live-диска. Никакой дополнительной установки не требуется. Операционная система не сохраняет своё состояние, и при перезагрузке вы всегда имеете «чистую» операционную систему без ваших изменений.
Вероятно, название Live-диск получил, потому что он позволяет «оживить» компьютера в случае программного сбоя в основной операционной системе компьютера.
▍ Как устроен Live-диск с Linux
Live-диск для операционной системы Linux подразумевает, что squashfs-файл хранит образ корневой файловой системы. Этот файл на диске не изменяется, но вы можете создавать изменять корневую файловую систему во время сессии работы с операционной системой. Эта возможность реализуется при помощи использования OverlayFS и tmpfs совместно с squashfs. Squashfs-файл — это особый вид архива, специально оптимизированного для использования в Live-дисках.
OverlayFS за основу использует одну файловую систему (squashfs), а изменения хранит в другой файловой системе (tmpfs).
Основные задачи, которые стоят при создании Live диска:
- Создать squashfs-файл с образом корневой файловой системы.
- Сделать так, чтобы ядро Linux смонтировало в качестве корневой файловой системы OverlayFS.
В файл initramfs добавляются дополнительные файлы, позволяющие найти и использовать этот файл в качестве основы для корневой файловой системы. В дистрибутивах, основанных на Debian, для этой цели есть пакеты live-build и live-boot. Live-build является более высокоуровневым, и с помощью его утилит можно создать гибридный загрузочный образ. Live-boot более низкоуровневый и основное его назначение — создать корректный файл для Live-загрузки.
▍ Отличие Live USB-диска от USB-диска с установленным на нём Linux
Создание Live USB-диска отличается от обычного USB-диска с Linux только наличием нескольких дополнительных шагов.
- Среди пакетов, помещаемых в корневую файловую систему, должны быть live-boot и live-boot-initramfs-tools, они позволят сгенерировать initramfs-файл, позволяющий загрузить Linux в лайв режиме.
- Файлы корневой файловой системы необходимо поместить в squashfs-файле.
- Linux уже не нужен UUID раздела с корневой файловой системой, так как корневая система Linux находится в squashfs-файле.
- Запись в файле /etc/fstab также не нужна.
- Немного будет отличаться установка GRUB 2. ESP-раздел остаётся без изменений, а на Linux-разделе изменяется конфигурационный файл grub.cfg, так как содержимое корневой файловой системе хранится в squashfs-файле, а не размещается на разделе диска.
- Linux-раздел будет содержать squashfs-файл с корневой файловой системой, initramfs-файл и файл ядра Linux.
Для удобства приведу последовательность шагов для создания Live USB-диска, выделив те шаги, которые отличаются от шагов в варианте с установкой Linux на внешний USB-диск.
Создание Live USB-диска
-
Инициализируем директорию, где будем выполнять сборку:
# mkdir asld-live-usb && cd asld-live-usb # mkdir -p Applications # cp -r ~/Genesis ./Applications
-
Запускаем Docker-контейнер:
# docker run -v $(pwd):/app --platform=linux/amd64 --privileged -it --rm debian /bin/bash
-
Создаём директорию, где будем собирать содержимое корневой файловой системы:
# mkdir -p ~/build/chroot && cd ~/build/chroot
-
Устанавливаем debootstrap:
# apt update && apt install -y debootstrap
-
Выполняем команду debootstrap:
# debootstrap \ --include=linux-image-amd64,firmware-linux \ --components=main,contrib,non-free-firmware \ --arch=amd64 bookworm . https://deb.debian.org/debian
-
Можно посмотреть, откуда apt будет брать пакеты:
# cat ./etc/apt/sources.list
-
Для полноценной работы в chroot-окружении нужно смонтировать в него системные директории:
# for dir in dev dev/pts proc sys run; do mount --bind /$dir ./$dir; done
-
Переключаемся в chroot окружение:
# LANG=C.UTF-8 chroot . /bin/bash
-
Устанавливаем пароль для root:
# passwd root
-
Настраиваем сеть:
# apt install -y network-manager # echo asld-linux > /etc/hostname
-
Устанавливаем пакет sudo:
# apt install -y sudo
-
Добавляем пользователя user с домашней директорией и оболочкой bash по умолчанию:
# useradd -m -s /bin/bash user
-
Добавляем пользователя user в группу sudo:
# usermod -aG sudo user
-
Устанавливаем пароль для user:
# passwd user
-
Добавляем поддержку архитектуры i386. Поддержка архитектуры означает, что теперь Debian сможет устанавливать пакеты для архитектуры i386:
# dpkg --add-architecture i386 && apt update
-
Устанавливаем недостающие пакеты:
# apt install -y libc6:i386 libsm6:i386 libxrender1:i386 libfontconfig1:i386 \ libxext6:i386 libstdc++6:i386 lsscsi gdm3 gnome-shell gnome-terminal gnome-text-editor \ nautilus mc libreoffice open-vm-tools-desktop apt-file \ live-boot live-boot-initramfs-tools
Обратите внимание, что в список устанавливаемых пакетов были добавлены live-boot и live-boot-initramfs-tools.
-
Устанавливаем Google Chrome:
# apt install -y wget # wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb # apt install -y ./google-chrome-stable_current_amd64.deb # rm ./google-chrome-stable_current_amd64.deb
-
Настраиваем Autologin:
# cat > /etc/gdm3/daemon.conf <<EOF [daemon] AutomaticLoginEnable = true AutomaticLogin = user EOF
-
Выходим из chroot:
# exit
-
Размонтируем системные директории:
# for dir in dev/pts dev proc sys run; do umount ./$dir; done
-
Устанавливаем пакеты, необходимые для разметки диска, форматирования разделов, создания squashfs-файла и установки загрузчика:
# apt update && apt install -y fdisk dosfstools grub-efi kpartx squashfs-tools
-
Определяем размер файла-образа. Внутри файла-образа будет два раздела: ESP — для установки загрузчика GRUB и Linux-раздел, где будет squashfs-файл, ядро Linux, initramfs-файл, файл конфигурации GRUB 2 и большая часть файлов GRUB 2.
# du -sh ~/build/chroot # du -sh /app/Applications
-
Чтобы не добавлять дополнительную сложность, размер будем определять исходя из того, сколько занимают директории ~/build/chroot и /app/Applications В моём случае я выбрал размер 8 Гбайт:
# ASLD_IMAGE_FILE=~/build/asld-live-usb.img # fallocate -l 8G $ASLD_IMAGE_FILE
-
Выполняем разметку образа:
# echo -e ",200M,U\n,+\n" | sfdisk -X gpt $ASLD_IMAGE_FILE
-
Для работы с разделами необходимо создать loop-устройство, которое будет представлять образ:
# BLOCK_DEVICE=$(losetup --show -f $ASLD_IMAGE_FILE) # LOOP_NAME="${BLOCK_DEVICE##*/}" # echo "BLOCK_DEVICE=$BLOCK_DEVICE LOOP_NAME=$LOOP_NAME"
Чтобы разделы, расположенные в образе, были видны как блочные устройства, используем команду kpartx.
-
Форматируем ESP и Linux разделы:
# ESP_PARTITION="/dev/mapper/${LOOP_NAME}p1" # ROOT_PARTITION="/dev/mapper/${LOOP_NAME}p2" # mkfs.vfat "$ESP_PARTITION" # mkfs.ext4 "$ROOT_PARTITION"
-
Монтируем отформатированные разделы:
# ESP_PATH=/mnt/esp # ROOTFS_PATH=/mnt/rootfs # mkdir -p $ESP_PATH # mkdir -p $ROOTFS_PATH # mount $ESP_PARTITION $ESP_PATH # mount $ROOT_PARTITION $ROOTFS_PATH
-
Создаём squashfs-файл, копируем его, файл ядра Linux, initrafs-файл на созданный раздел Linux:
# cp --verbose -r /app/Applications ~/build/chroot/home/user # mkdir -p $ROOTFS_PATH/live # mksquashfs ~/build/chroot \ $ROOTFS_PATH/live/filesystem.squashfs -no-xattrs -info # cp --verbose -a ~/build/chroot/vmlinuz $ROOTFS_PATH # cp --verbose -a ~/build/chroot/initrd.img $ROOTFS_PATH # cp --verbose -r ~/build/chroot/boot $ROOTFS_PATH
-
Устанавливаем GRUB в образ:
# grub-install \ --removable \ --root-directory $ROOTFS_PATH \ --efi-directory $ESP_PATH \ --target=x86_64-efi $BLOCK_DEVICE
-
Проверяем, что файлы GRUB 2 скопировались в файловые системы образа:
# ls -lA $ESP_PATH/EFI/BOOT # ls -lA $ROOTFS_PATH /boot/grub # ls -lA $ROOTFS_PATH/boot/grub/x86_64-efi
-
Создаём файл конфигурации GRUB 2:
# cat > $ROOTFS_PATH/boot/grub/grub.cfg <<EOF set timeout=30 menuentry "ASLD Linux Live USB" { linux /vmlinuz root=live initrd /initrd.img } EOF # cat $ROOTFS_PATH/boot/grub/grub.cfg
Запись в файле /etc/fstab не нужна.
-
Корректно освобождаем ресурсы – смонтированные файловые системы, mappings, созданные командой kpartx и loop-устройство, созданное для образа:
# umount $ESP_PATH # umount $ROOTFS_PATH # kpartx -dv $BLOCK_DEVICE # losetup -d $BLOCK_DEVICE
-
Копируем созданный образ в папку хостовой операционной системы, чтобы его можно было записать на диск:
# mkdir -p /app/out # cp $ASLD_IMAGE_FILE /app/out
-
Завершаем работу контейнера:
# exit
Теперь файл asld-live-usb.img можно записать на внешний диск с помощью balenaEtcher и загрузиться с диска.
Выводы
Вы дочитали эту статью до конца, а я подведу итоги. Если вы осознанно выполнили действия, описанные в статье, то вы, помимо того, что восстановили свой SSD, почили навыки и разобрались со следующим:
- Работа 32-разрядных приложений на 64-разрядном дистрибутиве Linux.
- Создания ISO-образов Live-дисков.
- Загрузка Linux, и состав дистрибутива Linux.
- Подробности создания Live-дисков.
Даже если у вас и не было SSD для восстановления, или вы не смогли найти программы для его восстановления, надеюсь, что информация, приведённая в статье, позволит вам лучше понимать внутреннее устройство Linux и выделить важные моменты.
Я ставил целью дать начальные знания и умения в непростой теме создания дистрибутива Linux. Из-за того, что это всё-таки статья, и я старался изложить информацию последовательно, многие вещи не были освещены. Например, я вообще не рассказал о том, как реализовывается режим secure boot при загрузке Linux, не упомянул и возможности загрузить Linux без использования загрузчика (EFIStub), как можно установить BIOS вариант GRUB 2 на диск GPT-разметкой, или как установить UEFI вариант GRUB 2 на диск с MBR-разметкой и много чего ещё.
Надеюсь, интересующийся читатель разберётся с тем, что не изложено в статье, а я побудил вас к более углублённому изучению темы, избавив от неприятного ощущения, когда понимаешь предмет лишь отчасти. Всё знать невозможно, но, когда обладаешь базовыми знаниями о предмете, страх и неуверенность от непонимания сути исчезают. Разумеется, что знания должны быть усилены практическими навыками.
У меня было желание охватить всё по максимуму, это заметно увеличило время написания статьи. Но, в конце концов, я отказался от этой невыполнимой затеи, так как в любом случае, хорошо разобраться в теме невозможно без чтения книг, документации и исходных кодов, закрепления знаний на практике.
Процедура восстановления диска стала проще, я улучшил и систематизировал свои познания в Linux, а также я ещё раз убедился, что если что-то не получается с первого раза — это уникальная возможность углубить и закрепить свои знания.
Спасибо, что дочитали статью до конца.
© 2024 ООО «МТ ФИНАНС»
Telegram-канал со скидками, розыгрышами призов и новостями IT ?
Комментарии (9)
gumanzoy
02.09.2024 11:19Проверил, в моей сборке DogLinux (Debian 12 Bookworm) только libsm6:i386 не хватает. Соответственно можно в Live режиме запустить apt и доустановить.
Скрытый текст
artyomsoft Автор
02.09.2024 11:19+1Просто я рассматривал более общий случай. Думаю, есть уже готовые дистрибутивы Linux, где уже все будет.
Johan_Palych
Шедеврально. Без хейта.
artyomsoft Автор
Спасибо. Убрал, чтобы не смущать
radioxoma
msys2 не хватает, там тоже pacman.