Преобразование имени раздела и устройства в формат SYSLINUX

Преамбула

Меня спрашивают, а где на практике можно применить «номер буквы в алфавите», про получение которого в bash-скрипте было недавно написано. Вот пример такого практического применения. Известно, что в Linux дисковые устройства представлены в виде /dev/sda, /dev/sdb, /dev/sdc и т.д., а разделы диска в виде /dev/sda1, /dev/sda2
SYSLINUX, точнее его модуль chain.c32, который может передавать управление другим загрузчикам, использует другой формат:

hdD P
где:
D — номер устройства (диска) в BIOS
P — номер раздела на диске
Отсчет дисков ведется с 0, разделов — с 1 (0 — главная загрузочная запись диска)
Например, hd0 2 — загрузка должна производиться со 2 раздела первого диска, hd1 1 — с 1 раздела второго жесткого диска, hd3 0 — необходимо передать управление главной загрузочной записи (MBR) четвертого диска.

Вот часть конфига syslinux.cfg, где chainloading используется для загрузки Windows со второго раздела на первом жестком диске:

LABEL windows
   menu label Microsoft Windows 7
   kernel modules/chain.c32
   append hd0 2

Некоторые минусы

— Минус, связанный с BIOS. Если вдруг порядок устройств в BIOS поменяется, то загрузчик SYSLINUX «заблудится» и попытается передать управление не туда.
— Некоторые линуксы меняют порядок именования жестких дисков, т.е. /dev/hda может и не соответствовать первому загрузочному диску. Тут уже зависит от конкретного дистрибутива.

Первый минуса можно избежать, используя вместо номера диска MBR ID, но это уже тема для отдельной заметки.

Получаем ID для chain.c32

Я организовал это в отдельной функции get_sysl_hd(), чтобы было удобно утащить в другой скрипт, буде понадобится. Первый параметр функции — имя устройства, например, /dev/sda1

1. Получаем имя устройства без пути к нему.
T_DN=`basename $1`

2. Можно проверить, соответствует ли имя устройства формату имени дисков, а то вдруг нам CD-ROM подсунули 🙂
Имя диска начинается с первой буквы s или h на некоторых пожилых дистрибутивах, далее следует буква d, далее — латинская буква a-z, потом могут следовать цифры (номера разделов). Можно сообразить вот такое простенькое регулярное выражение:

^[sh]d[a-z][1-9]*$

Далее пропускаем результат работы basename через grep, и проверяем выхлоп в переменной. Если переменная пустая, подсунули что-то не то.

T_DN=`basename $1|grep '^[sh]d[a-z][1-9]*$'`
if [ -z "$T_DN" ]; then
	return 1
fi

Но на самом деле, эта проверка не очень-то и нужна, можно пропустить этот пункт

3. Получаем третью букву в имени диска с помощью команды expr:
expr substr pos len

где:
substr — операция получения подстроки
pos — позиция символа в строке (отсчет ведется с единицы)
len — длина подстроки

T_3LET=`expr substr $T_DN 3 1`

4. Получаем номер буквы в алфавите. Я воспользовался вторым копия из ранее описанных способов.

S_CODE=`printf '%d' \'$T_3LET`
A_CODE=`printf '%d' \'a`
SYSL_ID="hd"`expr $S_CODE - $A_CODE`

5. Получим номер раздела, удалив sed‘ом все латинские буквы с начала имени устройства в переменной $T_DN:

T_VOLNUM=`echo "$T_DN" | sed 's/^[a-z]*//'`
if [ -z "$T_VOLNUM" ]; then
	T_VOLNUM=0
fi

Если переменная окажется пустой, значит нам подсунули устройство, без указания раздела — необходимо сослаться на MBR. Присваиваем T_VOLNUM значение 0.

6. Добавляем полученные данные в переменную SYSL_ID

SYSL_ID="$SYSL_ID $T_VOLNUM"

7. Пример вызова функции:

if [ -z "$1" ]; then
    echo "Use "`basename $0` "<device>"
    exit
fi

get_sysl_hd "$1"

if [ $? -ne 0 ];then
    echo "Bad device name!"
else
    echo "$1: $SYSL_ID"
fi

Скрипт целиком

На PasteBin
На GitHub

Источники

1. Syslinux (Русский)
2. Работа со строками
3. BASH: Получить номер буквы в латинском алфавите, более элегантное решение. Копия

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*