Вопрос или проблема
В 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. Вот некоторые решения:
Решение с использованием командной строки
-
Используя
readlink
:
Если/dev/root
является символической ссылкой, вы можете использовать командуreadlink
для получения фактического устройства:readlink /dev/root
Или для получения полного пути:
readlink -f /dev/root
-
Используя
mount
илиfindmnt
:
Командаmount
позволяет найти текущее устройство, к которому подключена файловая система/
:mount | grep ' on / '
Или для более простой обработки:
findmnt -n -o SOURCE /
Эта команда вернет устройство, на котором смонтирована корневая файловая система.
-
Используя информацию из
/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
является более надежным подходом.