Тема в рассылке: https://lists.altlinux.org/pipermail/sisyphus/2019-February/367590.html
Created attachment 7989 [details] Скрипт в первом приближении Срипт из сообщения https://lists.altlinux.org/pipermail/sisyphus/2019-February/367605.html
Лёня, хотелось бы видеть твой скрипт в виде задания на сборку grub.
Ну и можно в апстрим отправить.
(In reply to comment #3) > Ну и можно в апстрим отправить. В апстриме хорошо бы ещё проверку ввода для grub-reboot и grub-set-default реализовать. И можно на основе вывода этого скрипта, но тогда он должен все варианты уметь показывать, например, с ключиком -f/--full. А вариантов получается 9 на первый уровень подменю: любой из трёх слева, любой из трёх справа. Чуть-чуть вариантов для примера: gnulinux-advanced-97dc55e0-56b2-4f33-ae5a-a0c9d2c5daf3>5 gnulinux-advanced-97dc55e0-56b2-4f33-ae5a-a0c9d2c5daf3>ALT p8 starter kit, 4.4.116-std-def-alt0.M80C.1 1>5
(В ответ на комментарий №2) > Лёня, хотелось бы видеть твой скрипт в виде задания на сборку grub. Это не проблема. Как только появится возможность -- отправлю. Но сначала хотелось бы понять, чего (и в каком виде) этот скрипт должен выводить? Каково будет типовое использование? И в плане безопасности: нынешний вариант слишком рисковый, хотя у нас весь /boot зарутованный и содержимому grub.cfg root может доверять.
(In reply to comment #5) > Но сначала хотелось бы понять, чего (и в каком виде) этот > скрипт должен выводить? Каково будет типовое использование? Я вопросом использования Grub озадачился из-за bug 34363. Соответственно, лично мне требуется удобное отображение вариантов загрузки для реализации чего-то похожего на "lilo -R". То есть в /etc/sysconfig/grub2 меняю GRUB_SAVEDEFAULT на false, устанавливаю некоторое проверенное ядро на загрузку через grub-set-default, а после обновления ядра выбираю на следующую перезагрузку свежепоставленное, чтобы, если что, можно было послать кого-то нажать кнопку, либо дёрнуть компьютер PDU-шкой и т.п. Для этого удобно иметь под руками выведенный список вариантов загрузки, откуда можно просто скопировать, а не смотреть каждый раз в /boot/grub/grub.cfg > И в плане безопасности: нынешний вариант слишком рисковый, хотя > у нас весь /boot зарутованный и содержимому grub.cfg root может > доверять. А чем рисковый? Да, шаблон исполняется, но в начале строк есть вариант только из трёх функций, и они в скрипте определены. Для endmenu только пробел добавить для однозначности, либо конец строки поставить.
Да, мне скрипт тоже не понравился тем что ты фактически соурсишь содержимое grub.cfg.
(In reply to comment #6) > То есть в /etc/sysconfig/grub2 меняю GRUB_SAVEDEFAULT на false, Ещё GRUB_DEFAULT='saved', но это по-умолчанию в ALT, на сколько я вижу. > Для этого удобно иметь под руками выведенный список вариантов загрузки Ещё подумалось, что можно придумать ситуацию, когда обновление делается при отсутствии удобной возможности скопировать. На этот случай, всё же, хорошо видеть и сокращённый вариант из номеров. Для grub-set-default это плохо, так как номера могут меняться, но для grub-reboot вполне годится.
Created attachment 7990 [details] Пример конфига для отладки (от Ubuntu) Если что-то будет доделываться, то вот достаточно развесистый конфиг от Ubuntu (два подменю первого уровня, второго нет). Скрипт из первого аттача обрабатывает его нормально.
(В ответ на комментарий №4) > В апстриме хорошо бы ещё проверку ввода для grub-reboot и grub-set-default > реализовать. Насчёт апстрима пока ничего не скажу, но то что увидел у нас, поменять легко. > И можно на основе вывода этого скрипта, но тогда он должен все > варианты уметь показывать, например, с ключиком -f/--full. А вариантов > получается 9 на первый уровень подменю: любой из трёх слева, любой из трёх > справа. Чуть-чуть вариантов для примера: > > gnulinux-advanced-97dc55e0-56b2-4f33-ae5a-a0c9d2c5daf3>5 > gnulinux-advanced-97dc55e0-56b2-4f33-ae5a-a0c9d2c5daf3>ALT p8 starter kit, > 4.4.116-std-def-alt0.M80C.1 > 1>5 Пока не понял как вы считали, смотрю документацию и смотрю ваш конфиг, где есть не только такие ID, но и похлеще: osprober-gnulinux-/boot/vmlinuz-4.13.0-25-generic-root=UUID=843c9318-4d20-49be-83cf-c09a6e4926c5 ro recovery nomodeset-843c9318-4d20-49be-83cf-c09a6e4926c5 А это точно ID? Вы уверены, что ID бывают во всех конфигах, если уж говорить про апстрим? Вот лишь пара примеров из многих, где ID не указывается: https://github.com/thias/glim/tree/master/grub2 https://github.com/aguslr/multibootusb/tree/master/mbusb.d и, судя по синтаксису menuentry/submenu, даже у опции его задающего, нет устойчивого имени. Исходя из этого я бы предложил про ID забыть, хоть в документации про него и упоминается. (В ответ на комментарий №6) > А чем рисковый? Да, шаблон исполняется, но в начале строк есть вариант только > из трёх функций, и они в скрипте определены. Именно тем, что шаблон исполняется, исполняемый код может пролезть в аргументы, а если делать проверку или очистку аргументов, то проще разобрать первый аргумент с заголовком пункта меню. Для скорости и простоты так сделал, но конечно надо переделывать. Мне кажется, что бы там не говорилось в документации, проверять и сохранять для многоуровневых меню стоит только числовые варианты a.k.a '1>5', а для одноуровневых меню ещё название пункта, при условии, что он не дублируется.
16.1.1 menuentry menuentry title [--class=class …] [--users=users] [--unrestricted] [--hotkey=key] [--id=id] [arg …] { command; … } The --id may be used to associate unique identifier with a menu entry. id is string of ASCII aphanumeric characters, underscore and hyphen and should not start with a digit. 16.1.2 submenu submenu title [--class=class …] [--users=users] [--unrestricted] [--hotkey=key] [--id=id] { menu entries … } All options are the same as in the menuentry command (see menuentry). То есть, документация по конфигу противоречит документации по grub-set-default и grub-reboot, которые не описаны на сайте gnu.org, зато там есть пример в разделе 15.1.10 default, где такой дикости с ID нет и ID указаны везде, тогда как по логике авторов эти ID опциональны. Именно поэтому я не вижу смысла их поддерживать.
Короче, приведённый выше пример ID по-любому написан в нарушении документации, так как содержит пробелы, точки, прямой слэш и символ равенства. Пример в документации в разделе "15.1.10 default", хоть и выглядит разумнее этого ID, тоже противоречит разделу "16.1.1 menuentry", поскольку в ID используются точки, хотя не должны! Или "aphanumeric" с пропущенной буквой "l" допускает десятичные точки? :) Кроме того, у всего grubenv блока есть ограничение на общий размер в 1024 байта, а хранится там может три значения вместе с именами переменных, так что многоуровневые меню с такими сумасшедшими ID и заголовками могут попросту не влезть.
echo -n "Дополнительные параметры для Ubuntu Bionic Beaver (development branch) (18.04) (на /dev/sdb6)>Ubuntu, с Linux 4.4.0-109-generic (recovery mode) (на /dev/sdb6)" | wc -c 189 (байт). А всего вместе с именем переменной -- 341 байт в блоке. Ещё один уровень с таким названием -- и уже не влезет в блок. И это мы, русские, о себе любимых думаем (x2 на символ), а у Японцев/Китайцев до x6 может UTF8 зашкаливать!
Created attachment 7996 [details] Скрипт во втором приближении Сделал безопасней. Переделать его теперь совсем несложно. Просто решите, КАК.
(In reply to comment #13) > а у Японцев/Китайцев до x6 может UTF8 зашкаливать! Как-то при обсуждении длинны имени файла в рассылке про ext4 на эту тему привели контраргумент вида "зато этот символ как абзац текста у европейцев" (или что-то в этом роде). :-)
(In reply to comment #14) > Сделал безопасней. Переделать его теперь совсем несложно. Просто решите, КАК. Вот это надо: --- grub-entries.sh.old 2019-02-07 10:57:42.000000000 +0400 +++ grub-entries.sh 2019-02-07 11:20:13.000000000 +0400 @@ -8,7 +8,9 @@ prefix="___vxZZZy275___" grubmenu="$(mktemp -q "${TMPDIR-/tmp}/grubmenu-XXXXXXXX.tmp")" -cat "$1" | sed \ +grubcfg=${1-/boot/grub/grub.cfg} + +cat "$grubcfg" | sed \ -re "s/^[[:space:]]*menuentry[[:space:]]+'([^']+)'.*\$/${prefix}M: \1/g" \ -re "s/^[[:space:]]*submenu[[:space:]]+'([^']+)'.*\$/${prefix}S: \1/g" \ -re "s/^[[:space:]]*}[[:space:]]*\$/${prefix}E: -/g" \ И вывод. Сейчас как-то вот так: ALT p8 starter kit Advanced options for ALT p8 starter kit>ALT p8 starter kit, vmlinuz Advanced options for ALT p8 starter kit>ALT p8 starter kit, vmlinuz (recovery mode) А хорошо бы 0 ALT p8 starter kit 1>0 Advanced options for ALT p8 starter kit>ALT p8 starter kit, vmlinuz 1>1 Advanced options for ALT p8 starter kit>ALT p8 starter kit, vmlinuz (recovery mode) То есть, с числовой альтернативой. Только что-то не соображу, как красиво без массивов обойтись. Или уж перейти на bash4... И, наверное, всё тогда. (In reply to comment #11) > То есть, документация по конфигу противоречит документации по grub-set-default > и grub-reboot Как же проще и понятнее с lilo... :-) Тут тогда проще потом баг в апстрим с этим скриптом, и пусть дальше сами за совместимостью следат.
(В ответ на комментарий №14) > Переделать его теперь совсем несложно. Кстати, такая регулярка попроще будет и тоже работает: -re '/^\s*(menuentry\s+|submenu\s+|})/!d' \ -re "s/^\s*menuentry\s+'([^']+)'.*\$/M \1/g" \ -re "s/^\s*submenu\s+'([^']+)'.*\$/S \1/g" \ -re "s/^\s*}\s*\$/E -/g" > "$grubmenu" Может ему вообще данные из входного потока брать?
(In reply to comment #17) > Может ему вообще данные из входного потока брать? Вообще да. Хоть сейчас /tmp на tmpfs, но, всё равно, лишние операции файлами. Для отладки только удобно, посмотреть, что там в grubmenu получается.
Created attachment 7998 [details] Скрипт в третьем приближении Вы это имели ввиду? Там есть одна логическая ветка, протестировать которую можно только многомерным меню. Проверить это лучше до опакечивания.
(В ответ на комментарий №19) > Проверить это лучше до опакечивания. Проверять теперь так: ./grub-entries.sh /path/to/grub.cfg
(В ответ на комментарий №19) > Проверить это лучше до опакечивания. Проверять теперь так: ./grub-entries.sh < /path/to/grub.cfg
(In reply to comment #19) > Вы это имели ввиду? Да, так. > Там есть одна логическая ветка, протестировать > которую можно только многомерным меню. С самим бы этим многомерным меню не ошибиться... :-) (In reply to comment #21) > Проверять теперь так: > ./grub-entries.sh < /path/to/grub.cfg В окончательном варианте лучше название сделать grub-entries для однообразия и конфиг по-умолчанию /boot/grub/grub.cfg
(In reply to comment #22) > grub-entries для однообразия без .sh то есть.
Created attachment 7999 [details] пример grub.cfg, ALT p8, с memtest А вот и разнообразие пошло. У нас элемент меню с memtest сокращённый, не ловится.
(В ответ на комментарий №24) > А вот и разнообразие пошло. У нас элемент меню с memtest сокращённый, не > ловится. Да, не ловится из-за двойныйх кавычек. Могу поправить регулярку.
Created attachment 8000 [details] пример grub.cfg, ALT p8, с memtest, два уровня Сделал пример с двумя уровнями вложенности. В общем-то работает и по номерам строк, если учесть пропущенный memtest.
(In reply to comment #25) > Да, не ловится из-за двойныйх кавычек. Могу поправить регулярку. Так для ALT же в первую очередь, надо, разумеется. :-)
Created attachment 8001 [details] Теперь и с двойными, и с одинарными кавычками (В ответ на комментарий №27) > Так для ALT же в первую очередь, надо, разумеется. :-) Пофиксил.
(В ответ на комментарий №26) > Сделал пример с двумя уровнями вложенности. В общем-то работает и по номерам > строк, если учесть пропущенный memtest. Этот пример не тестирует логическую ветвь, про которую я говорил. Здесь возврат происходит сразу на нулевой уровень.
Created attachment 8002 [details] Окончательная версия скрипта Там тоже была ошибка, исправил. Вот это уже можно опакечивать? P.S.: в названии конфига какой смысл, если данные берутся из stdin?
На всякий случай: Task #221001, там ещё man(8) добавил.
было бы отлично убрать из этого скрипта временный файл $grubmenu".
(In reply to comment #30) > P.S.: в названии конфига какой смысл, если данные берутся из stdin? А зачем так? В 99.9% случаев интересен только один конфиг, и удобно запускать скрипт просто без параметров. Для 0.1% случаев можно оставить возможность ввода параметра, а stdn - задел на использование в скрипте для проверки правильности ввода у grub-reboot и grub-set-default? Так там тоже не надо выбирать ничего, просто запускать и проверять вывод.
Created attachment 8003 [details] пример grub.cfg, ALT p8, с memtest, два уровня, с переходом на первый Вот этот конфиг последний скрипт (аттач 8002) нормально разбирает.
Created attachment 8004 [details] Вариант скрипта без промежуточного файла В окончательном виде вот так предлагаю сделать.
(В ответ на комментарий №32) > было бы отлично убрать из этого скрипта временный файл $grubmenu". Боюсь, это невозможно, поскольку это единственно возможный вариант работы с данными, лежащими за пределами цикла их обработки: глобальное = ... for/while ... do что_то_делать_с_глобальным() done < $временный_файл Если делать иначе, данные не сохраняются между итерациями. (В ответ на комментарий №35) > В окончательном виде вот так предлагаю сделать. И чего, он правильно работает!? Проверяли? ;-)
> (В ответ на комментарий №35) > > В окончательном виде вот так предлагаю сделать. > > И чего, он правильно работает!? Проверяли? ;-) Конечно. Я себе его так и переделал. Какая разница, скармливать в wile поток данных через "|" или или через "<"? Вот если бы речь шла о передаче значений переменных из цикла наружу... Вот там что-то такое вспоминается.
(In reply to comment #37) > Вот там что-то такое вспоминается. Да, как раз именно это, из comment #36. "глобальное" будет иметь значение, как до цикла. Но внутри цикла всё должно быть хорошо.
(В ответ на комментарий №37) > Вот если бы речь шла о передаче значений > переменных из цикла наружу... Вот там что-то такое вспоминается. Пожалуй, Вы правы! (В ответ на комментарий №38) > Да, как раз именно это, из comment #36. "глобальное" будет иметь значение, как > до цикла. Но внутри цикла всё должно быть хорошо. Нет, с массивами и внутри всё плохо, и снаружи всё плохо. Использовал mkfifo чтобы обойти эту проблему. Поэтому давно не использую |while конструкцию.
Created attachment 8007 [details] Варинт скрипта с опциями и проверкой Может лучше так?
если делать с временным файлом, то надо предусмотреть падение скрипта и удаление временных файлов.
(В ответ на комментарий №41) > если делать с временным файлом, то надо предусмотреть падение скрипта и > удаление временных файлов. В последнем варианте без временного файла с проверкой результата. Проверку сделать через временный файл можно понадёжней. Здесь я не уверен, что grep во всех случаях отработает корректно.
Да, возможно единственный правильный вариант с grep -- это когда счётчик вернул одно полное совпадение, тогда как 0 -- отсутствие элемента, а >1 -- наличие дубликатов, что может привести к неоднозначности.
(In reply to comment #43) > Да, возможно единственный правильный вариант с grep -- это когда счётчик вернул > одно полное совпадение, тогда как 0 -- отсутствие элемента, а >1 -- наличие > дубликатов, что может привести к неоднозначности. Да. (In reply to comment #40) > Created an attachment (id=8007) [details] > Варинт скрипта с опциями и проверкой # ./grub-entries sdf To many arguments: 'sdf' Наверное правильнее unrecognized arguments: 'sdf' И проверка. В-первых, сама её нужность тут под вопросом. Проверять нужно именно в момент задания, в grub-reboot и grub-set-default. Или уж, если отдельно, то проверять, что написано в /boot/grub/grubenv, и, может быть, в /etc/sysconfig/grub2 в GRUB_DEFAULT, если в GRUB_DEFAULT не saved. Во-вторых вот это место: case "$search_item" in [0-9]*) numbers_only=1; titles_only=0;; *) numbers_only=0; titles_only=1;; esac А какова гарантия, что текстовая строка с цифры не начнётся? Проверять не так уж много, можно просто проверить все варианты. В остальном всё хорошо на мой взгляд.
Created attachment 8008 [details] Окончательная версия скрипта (В ответ на комментарий №44) > В остальном всё хорошо на мой взгляд. Готов на 146%!
(In reply to comment #45) > Готов на 146%! На мой взгляд да.
Коля, забери коммит у Леонида, как только тот будет готов.
Created attachment 8009 [details] Патч с добавление скрипта и man-страницы к grub (В ответ на комментарий №47) > Коля, забери коммит у Леонида, как только тот будет готов. Вот он, если что.
grub-2.02-alt15 -> sisyphus: Tue Feb 12 2019 Nikolai Kostrigin <nickel@altlinux> 2.02-alt15 - add rhboot/grub2 SB patch set to prevent unauthorized code execution at boot time when SB is enabled - add grub-entries script by klark@ for list grub menu (closes: #36048) - add patch preventing boot failure for unsigned kernel in SB environment + add an optional patch application flag for convenience