суббота, 30 марта 2013 г.

К вопросу о создании LiveUSB

Преамбула. Я откладывал этот пост с лета прошлого года, потому-что он не предлагает готовых решений «бери и ешь», он наполнен догадками и предположениями. Но в целом, здесь приведен перечень вопросов, которые возникают при создании универсального LiveUSB.

Проблема создания загрузочной флешки, думаю всем знакома. Даже если такую флешку удалось сделать, то на одних компах она работает, на других нет. Другая флешка работает на тех и других, но не работает на третьих, где без проблем загружается первая. Почему так происходит? Когда я делал LiveCD по типу RIPLinux упаковывая системный раздел в initrd, то заметил, что читается такой архив очень медленно, в разы медленнее даже спецификации USB 1.0 при том, что при загрузке системы порт работает вполне сносно. Это собственно и является главным препятствием для LiveUSB такого типа. Initrd весом в 56Мб на GA-6OXT загружался 20 минут. Если кто перебирал ядро, должны помнить модули необходимые для работы флешек. Это хост-контроллер uhci/ohci, модуль usb2.0 ehci, модуль поддержки usb-носителей usb-storage. Так вот, насколько я понял, BIOS пытается реализовать данный функционал, при том, что сама флешка BIOS'а имеет емкость максимум 1Мб. Т.е. В итоге мы и получаем то, что имеем: какую-то сильно урезанную реализацию поддержки USB. У кого-то вендора эта реализация получается лучше, у кого-то хуже. Одно время в сети был проект BIOSpacher, где разбиралась работа BIOS. Рекомендую для ознакомления.

При создании загрузочной флешки я предполагал, что на современных компах с большими флешками BIOS поддержка загрузочных usb-носителей уже на приемлемом уровне, и приспосабливаться надо под старые компьютеры. Камнем преткновения стала материнка ASRock K7VTA PRO, которая никак не хотела принимать мою флешку. В итоге, я задался очередным вопросом, как BIOS отличает USB-HDD от USB-FDD и от USB-ZIP? Если конечно отбросить сортировку по device id, конечно. «Главным отличием дискеты от жесткого диска является отсутствие главной загрузочной записи». Т.е. Достаточно было отформатировать флешку не создавая таблицу разделов. И да, это сработало. ASRock приняла мою флешку за USB-FDD и без проблем загрузилась. В целом, у меня сложилось впечатление, что без загрузочной записи компьютеру легче загрузиться с флешки. Кто-то принимает такие флешки за USB-HDD, кто-то за USB-ZIP, кто-то за USB-FDD.


Другой проблемой было определение имени диска с которого стартовала система на этапе выполнения initrd, так что бы не перебирать все диски в поисках *.sfs файлов которые нужно загрузить в память. Здесь я опирался на наблюдение, что usb-носители определяются ядром последними и, следовательно, им присваиваются старшие суффиксы. Т.е. Выполнив реверсивную сортировку носителей по алфавиту, мы получим нашу флешку в первой строке. Это конечно не избавляет от перебора, но оптимизирует его. На практике это делается так:
for i in `ls -4r /dev/s[dr]?`; do
mount "$i" /mnt || mount "$i"1 /mnt
[ -e /mnt/base.sfs ] && { echo "storage on $i"; break; } || umount /mnt
done

Если делать инсталлятор LiveUSB, то в задачу ему, кроме самого создания флешки, можно поставить проверку условий создания загрузочной флешки, что бы пользователь, не дай бог, не отфарматировал жесткий диск. Кроме того если делать скрипт только на русском языке, то он становится бесполезным в английской локали или просто при несовпадении кодировок. Суммируя все вышесказанное у меня получился такой рабочий вариант:
#!/usr/bin/bash

ver='SYSLINUX 3.84'

m0[1]='
Инсталятор LiveUSB\n
Проект: SlavankaOS версия: 3.2\n\n
Формат запуска:\n
usb имя_флеш_носителя путь_к_содержимому_LiveCD_SlavankaOS\n\n
Пример запуска:\n
./usb /dev/sde /mnt/cdrom\n
или\n
./usb /dev/sdf ./'

m0[0]='
Installator LiveUSB\n
Project: SlavankaOS version: 3.2\n\n
SYNTAX:\n
usb flash_drive [path_with_LiveCD_SlavankaOS]\n\n
EXAMPLE:\n
./usb /dev/sde /mnt/cdrom\n
or\n
./usb /dev/sdf ./'


m1[1]='ОШИБКА: для работы скрипта требуются права суперпользователя(root)!'
m1[0]='ERROR: for run you must be superuser(root)!'

m2[1]='ОШИБКА: не найдена программа syslinux!'
m2[0]='ERROR: not found syslinux!'

m3[1]="ОШИБКА: версия syslinux не соответствует версии $ver!"
m3[0]="ERROR: version of the syslinux not equal $ver!"

m4[1]='сделано.'
m4[0]='done.'

m5[1]="ОШИБКА: устройство $1 не является флеш-диском!"
m5[0]="ERROR: device $1 is not flash drive!"

m6[1]="ОШИБКА: путь $2 не является директорией!"
m6[0]="ERROR: path $2 is not directory!"

m7[1]="Отмена"
m7[0]="Cancel"

m8[1]="ВНИМАНИЕ: данный диск будет отформатирован, все данные на нем будут уничтожены!"
m8[0]="WARNING! This disk now will be formatted, ALL data will DESTROYED!"

m9[1]="\nВведите Y/y для продолжения или любую другую клавишу для отмены"
m9[0]="\nEnter Y/y for continue or any OTHER key for cancel"

m10[1]="ОШИБКА: диск $1 примонтирован, форматирование невозможно!"
m10[0]="ERROR: drive $1 mounted, formatting impossible!"

# локаль
echo $LANG|grep -E "ru|RU" > /dev/null  && l=1 || l=0

# Если без параметров
if [  -s $1  ]; then
        echo -e ${m0[$l]}
        exit 1
fi

# если  -h или --help первым параметром
if [  $1 = '-h' -o $1 = '--help' ]; then
        echo  -e ${m0[$l]}
        exit 1
fi

# является ли первый параметр флешкой
if ! ls -l /dev/disk/by-id|grep `echo $1|awk -F / '{print $NF}'`|grep -i "FLASH"|grep -i "USB" > /dev/null; then
        echo ${m5[$l]}
        exit 1
fi

# не смонтирован ли он?
if grep "$1" /etc/mtab > /dev/null; then
        echo ${m10[$l]}
        exit 1
fi

# яляется ли второй параметр директорией
if [ ! -d $2 ]; then
        echo ${m6[$l]}
        exit 1
fi

# если запуск не root'ом
if [ $UID != 0 ]; then
        echo ${m1[$l]}
        exit 1
fi

# если не найден syslinux
if ! sl=`which syslinux`; then
        echo ${m2[$l]}
        exit 1
fi

# если несоответсвие версий syslinux
if ! grep "$ver" $sl > /dev/null 2>&1;then
        echo ${m3[$l]}
        exit 1
fi

# преупреждение
echo ${m8[$l]}
fdisk -l $1|head -n2 || exit 1
echo -e ${m9[$l]}
read answer

# сам процесс
if [ "$answer" = "y" -o "$answer" = "Y" ]; then
        mkfs.msdos -I -F32 $1 || exit 1
        syslinux -s $1 || exit 1
        f=`tempfile` || exit 1
        rm -v $f
        mkdir $f
        mount $1 $f || exit 1
        cp -av $2/*  $f
        [ \( ! -e $f/syslinux.cfg \) -a \( -e $f/isolinux.cfg \) ] && cp -v $f/isolinux.cfg $f/syslinux.cfg
        umount $f || exit 1
        rmdir $f || exit 1

        # завершение
        echo ${m4[$l]}
else
        echo ${m7[$l]}
fi
здесь конечно нужно будет потом добавить функционала:
- создание без форматирования, т. е. Используя существующую ФС,
- избавления от контроля версий syslinux, т. е. Используя служебные файлы той версии
syslinux который установлен в хост-системе,
- создание флешки с главной загрузочной записью,
и пр. Но сначала, думаю, надо обкатать имеющуюся версию.

Комментариев нет:

Отправить комментарий