Узнайте, что представляет собой устройство /dev/root в Linux?

Вопрос или проблема

В Linux есть устройство /dev/root. Это будет тот же блочный устройство, что и другой узел устройства, например, /dev/sdaX. Как я могу разрешить /dev/root в ‘реальный’ узел устройства в этой ситуации, чтобы показать пользователю разумное имя устройства?

Например, я могу столкнуться с этой ситуацией при парсинге /proc/mounts.

Я ищу решения, которые будут работать из оболочки/скрипта Python, но не на C.

Парсите параметр root= из /proc/cmdline.

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

https://bootlin.com/blog/find-root-device/

Для точки монтирования / вам просто сообщается, что она соответствует
/dev/root, что не является тем реальным устройством, которое вы ищете.

Конечно, вы можете посмотреть на командную строку ядра и увидеть, на какой
начальной корневой файловой системе Linux был запущен (параметр root):

$ cat /proc/cmdline mem=512M console=ttyS2,115200n8
root=/dev/mmcblk0p2 rw rootwait

Однако это не значит, что то, что вы видите, является текущим корневым
устройством. Многие системы Linux загружаются на промежуточные корневые файловые системы (такие как initramdisks и initramfs), которые используются только для доступа к конечной.

Одна из вещей, на которую это указывает, заключается в том, что то, что находится в /proc/cmdline, не обязательно является фактическим конечным корнем, на котором оно действительно живет.

Это от людей из busybox, которые, как я предполагаю, знают, о чем говорят, когда речь идет о ситуации загрузки.

https://www.linuxquestions.org/questions/slackware-14/slackware-current-dev-root-688189/page2.html

Второй полезный ресурс, который я нашел, — это очень старая тема Slackware о вопросе /dev/root. Из возраста этой темы мы можем видеть, что все варианты всегда присутствовали, но я верю, что ‘большинство’ дистрибутивов использовали метод символической ссылки, но это был простой переключатель компиляции ядра, он мог создать одну или не создать, если я правильно понял авторов постов, то есть, переключи в одном направлении, и readlink /dev/root сообщает реальное имя устройства, переключи в другом, и не сообщает.

Поскольку основной темой этой темы было то, как избавиться от /dev/root, им пришлось углубиться в то, что это на самом деле, что его создает и т.д., что означает, что они должны были понять это, чтобы избавиться от него.

gnashly объяснил это хорошо:

/dev/root — это общее устройство, которое может использоваться в fstab. Также можно использовать ‘rootfs’. Это дает некоторые преимущества, поскольку позволяет быть менее конкретным. Что я имею в виду, так это то, что если корневая раздела находится на внешнем диске, она может не всегда отображаться как одно и то же устройство, и успешное монтирование его как / потребует изменения fstab для соответствия правильному устройству. Используя /dev/root, оно всегда будет соответствовать тому устройству, которое указано в параметрах загрузки ядра от lilo или grub.

/dev/root всегда присутствовал как виртуальная точка монтирования, даже если вы никогда его не видели. Так же как и rootfs (сравните это с специальными виртуальными устройствами, такими как proc и tmpfs, которые не имеют предшествующего /dev)

/dev/root — это виртуальное устройство, как ‘proc’ или /dev/tcp’. Не существует узла устройства в /dev для этих вещей — это уже в ядре как виртуальное устройство.

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

Я верю, что некоторые из предложенных здесь решений ‘часто’ будут работать и, вероятно, это то, что я буду делать, но они не являются настоящим истинным решением проблемы, которое, как заметил автор busybox, значительно сложнее реализовать в очень надежной манере.

[ОБНОВЛЕНИЕ:} После получения некоторых пользовательских тестовых данных я выбираю метод монтирования, который, по крайней мере, показался нормальным для некоторых случаев. /proc/cmdline не был полезен, потому что слишком много вариантов. В первом примере вы видите старый метод. Он становится все менее распространенным, потому что его строго не рекомендуется использовать (оригинальный синтаксис /dev/sdx[0-9]), потому что эти пути могут изменяться динамически (смена порядка диска, вставка нового диска и т.д., и внезапно /dev/sda1 становится /dev/sdb1).

root=/dev/sda1
root=UUID=5a25cf4a-9772-40cd-b527-62848d4bdfda
root=LABEL=случайная строка
root=PARTUUID=a2079bfb-02

В отличие от очень чистого и простого для парсинга:

mount
/dev/sda1 on / type ext4 (rw,noatime,data=ordered)

В случае с cmdline вы увидите, что единственный вариант, который является правильным ‘ответом’ теоретически, — это первый, устаревший, поскольку вы не должны ссылаться на корень как на движущуюся цель, такую как /dev/sdxy.

Следующие два требуют дальнейших действий по получению символической ссылки из этой строки либо из /dev/disk/by-uuid, либо из /dev/disk/by-label.

Последний, я полагаю, требует использования parted -l, чтобы узнать, на что указывает этот ID parted.

Это только те варианты, которые я знаю и которые видел, может быть, есть и другие, такие как GPTID, например.

Итак, решение, которое я использую, таково:

Сначала проверьте, является ли /dev/root символической ссылкой. Если это так, убедитесь, что она не указывает на /dev/disk/by-uuid или by-label, если это так, вам нужно сделать второй шаг обработки, чтобы получить последний реальный путь. Зависит от инструмента, который вы используете.

Если ничего нет, то перейдите к mount и посмотрите, как там. В качестве последнего резервного варианта, который я не использую, потому что аргументы против него, не обязательно являющегося актуальным разделом или устройством, достаточно хороши, чтобы я отверг это решение для своей программы. mount не является полностью надежным решением, и я уверен, что с достаточным количеством образцов будет легко найти случаи, когда это совершенно неверно, но я верю, что эти два случая охватывают ‘большинство’ пользователей, что и требовалось.

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

Я не считаю ни одно из этих решений ‘хорошими или надежными’, но вариант mount, похоже, удовлетворяет условию ‘достаточно хорошего’, и если требуется действительно надежное решение, воспользуйтесь тем, что рекомендовал busybox.

На системах, которые я рассматривал, /dev/root является символической ссылкой на реальное устройство, так что readlink /dev/root (или readlink -f /dev/root, если вам нужен полный путь) сделает это.

Итак, /dev/root — это всего лишь символическая ссылка на реальное устройство, поэтому вы можете использовать readlink(2), чтобы узнать, куда она указывает из программы, или readlink(1), чтобы сделать то же самое из скрипта оболочки.

Возможно, я что-то упускаю, но что насчет:

mount|grep "https://unix.stackexchange.com/"|cut -d' ' -f 1

Если то, что вы ищете, это устройство, на которое смонтирована файловая система /, то самым простым ответом, вероятно, будет использование: findmnt / (или findmnt -n -o SOURCE / для машиночитаемого вывода).

findmnt является частью util-linux, который должен присутствовать на всех основных дистрибутивах Linux.

Более актуальный файл proc mountinfo из последних ядер может быть использован здесь. Он дает major:minor блочного устройства, где корень текущего процесса находится. Следующая команда bash может помочь:

cat /sys/dev/block/$(grep ' / / ' /proc/1/mountinfo | awk '{print $3}')/uevent |
    grep DEVNAME |
    sed 's/DEVNAME=/\/dev\//'

Эта команда предполагает множество вещей (что является стандартами в любом случае), поэтому она может работать или не работать (код предоставлен “как есть” и т.д.).

Просто адаптируйте это к своим нуждам, суть вышеуказанного кода такова:

  • он получает major:minor из /proc/1/mountinfo (корень процесса #1, init)
  • он использует /sys/dev/block/MAJOR:MINOR/uevent, чтобы получить имя устройства, которое, скорее всего, будет использоваться udev, systemd или другим инструментом для создания узла в /dev

Ответ или решение

/dev/root в Linux представляет собой виртуальное устройство, которое используется как общий интерфейс для обозначения корневой файловой системы. Это устройство обычно является символической ссылкой, указывающей на фактический блок-устройство, которое содержит корневую файловую систему (например, /dev/sda1 или другую реальную сущность). Однако, в некоторых случаях /dev/root может быть установлен в зависимости от конфигурации ядра или системы, и его поведение может варьироваться.

Чтобы выяснить, на какое реальное устройство указывает /dev/root, вы можете воспользоваться несколькими методами — с помощью командной строки Linux или через скрипты на Python. Вот некоторые решения:

Решение с использованием командной строки

  1. Используя readlink:
    Если /dev/root является символической ссылкой, вы можете использовать команду readlink для получения фактического устройства:

    readlink /dev/root

    Или для получения полного пути:

    readlink -f /dev/root
  2. Используя mount или findmnt:
    Команда mount позволяет найти текущее устройство, к которому подключена файловая система /:

    mount | grep ' on / '

    Или для более простой обработки:

    findmnt -n -o SOURCE /

    Эта команда вернет устройство, на котором смонтирована корневая файловая система.

  3. Используя информацию из /proc:
    Вы можете получить информацию о корневом устройстве процесса init:

    cat /proc/1/mountinfo | grep ' / '

    После этого можно извлечь major:minor, чтобы узнать реальное устройство:

    major_minor=$(grep ' / ' /proc/1/mountinfo | awk '{print $3}')
    cat /sys/dev/block/$major_minor/uevent | grep DEVNAME

Решение с использованием Python

Если вам нужно реализовать это в Python, вы можете использовать модуль os или subprocess для выполнения команд оболочки и обработки их вывода:

import subprocess

def get_root_device():
    try:
        # Проверяем, является ли /dev/root символической ссылкой
        root_device = subprocess.check_output(['readlink', '/dev/root']).strip().decode('utf-8')
        return root_device

    except subprocess.CalledProcessError:
        # Если /dev/root не является символической ссылкой, используем комбинацию mount/findmnt
        try:
            root_device = subprocess.check_output(['findmnt', '-n', '-o', 'SOURCE', '/']).strip().decode('utf-8')
            return root_device
        except subprocess.CalledProcessError:
            return None

print(get_root_device())

Заключение

Использование /dev/root облегчает процессы управления файловыми системами, позволяя более абстрактно ссылаться на корневую файловую систему. Однако, для получения актуальной информации о том, на какую реальную файловую систему ссылается /dev/root, необходимо использовать подходы, описанные выше. Как упоминалось, данные в /proc/cmdline могут быть не всегда актуальными, так как многие системы используют промежуточные файловые системы, такие как initramfs, перед доступом к окончательному корневому устройству. Поэтому использование mount, findmnt и информации из /proc является более надежным подходом.

Оцените материал
Добавить комментарий

Капча загружается...