Convert a legacy menu.lst safely with grub-menulst2cfg
You will turn a legacy GRUB menu.lst into GRUB 2 configuration text, save it separately, and inspect the translated entries before anything touches the boot partition. Allow about 15 minutes for a small file, plus time to test the result on the machine that will use it.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide uses grub-menulst2cfg from the installed grub-common package, version 2.12-1ubuntu7.3. The local manual page is dated March 2025 and documents the syntax as grub-menulst2cfg [INFILE [OUTFILE]]. The manual page has no option list or conversion reference, so the examples below show behaviour verified from this installed command.
1. Check the tool and preserve the source
Run the command as your ordinary user. Conversion reads the legacy file and writes generated text; it does not need root when both files are in a directory you can access.
$ command -v grub-menulst2cfg
/usr/bin/grub-menulst2cfg
$ dpkg-query -W grub-common
grub-common 2.12-1ubuntu7.3
Make a working copy of the input before experimenting. Keep the original somewhere safe because the converter is a migration aid, not an editor with an undo command.
$ cp --preserve=all /path/to/menu.lst /path/to/menu.lst.before-conversion
$ test -r /path/to/menu.lst && echo 'input is readable'
input is readable
Checkpoint: you should have a readable source file and a separate backup. Do not edit /boot/grub/grub.cfg in place as the first step.
2. Review the legacy input
Look for the directives that will become menu entries and boot commands. A small legacy file might contain a default entry, a timeout, one or more title blocks, a root device, a kernel line and an optional initrd line.
default 0
timeout 5
title Ubuntu 24.04
root (hd0,0)
kernel /vmlinuz root=/dev/sda1 ro quiet
initrd /initrd.img
title Recovery
root (hd0,0)
kernel /vmlinuz root=/dev/sda1 single
The example is illustrative input, not a configuration you should copy into a real system without replacing the kernel paths, root device and entry titles. Check the existing file instead:
$ sed -n '1,240p' /path/to/menu.lst
Pay particular attention to disk numbering. Legacy GRUB and GRUB 2 do not present every disk and partition number in the same way. The installed converter translated (hd0,0) in the test file to (hd0,1) in its generated output. Treat that as a value to verify, not as a reason to edit the source blindly.
3. Generate a review copy
Pass the input as the first argument and a new output path as the second. The output file is created or replaced, so choose a staging name that is not your live configuration.
$ grub-menulst2cfg /path/to/menu.lst /tmp/grub.cfg.converted
$ printf 'converter status: %s\n' "$?"
converter status: 0
$ sed -n '1,240p' /tmp/grub.cfg.converted
For the sample input, the result contains this shape:
set default='0'; if [ x"$default" = xsaved ]; then load_env; set default="$saved_entry"; fi
set timeout=5
menuentry 'Ubuntu 24.04' {
set root='(hd0,1)'; set legacy_hdbias='0'
legacy_kernel '/vmlinuz' '/vmlinuz' 'root=/dev/sda1' 'ro' 'quiet'
legacy_initrd '/initrd.img' '/initrd.img'
}
menuentry 'Recovery' {
set root='(hd0,1)'; set legacy_hdbias='0'
legacy_kernel '/vmlinuz' '/vmlinuz' 'root=/dev/sda1' 'single'
}
The converter writes generated configuration to standard output when you provide only the input path. That is useful for a quick inspection or a shell pipeline:
$ grub-menulst2cfg /path/to/menu.lst | sed -n '1,120p'
With an explicit output path, it writes no normal progress message and returns status 0 on success. The generated text is not a report: it contains GRUB commands, including compatibility helpers such as legacy_kernel. Review it in the context of the GRUB installation that will load it.
4. Check the translated entries before installation
Compare every important value with the legacy file. The menu titles should be recognisable, the default index should point at the intended entry, and the timeout should be deliberate. Check that each kernel argument survived as a separate argument and that an initrd line produced a corresponding legacy_initrd command.
$ grep -nE '^(set default|set timeout|menuentry| set root| legacy_)' /tmp/grub.cfg.converted
1:set default='0'; if [ x"$default" = xsaved ]; then load_env; set default="$saved_entry"; fi
2:set timeout=5
3:menuentry 'Ubuntu 24.04' {
4: set root='(hd0,1)'; set legacy_hdbias='0'
5: legacy_kernel '/vmlinuz' '/vmlinuz' 'root=/dev/sda1' 'ro' 'quiet'
6: legacy_initrd '/initrd.img' '/initrd.img'
9:menuentry 'Recovery' {
10: set root='(hd0,1)'; set legacy_hdbias='0'
11: legacy_kernel '/vmlinuz' '/vmlinuz' 'root=/dev/sda1' 'single'
This text check catches missing entries, but it cannot prove that the selected disk contains the named kernel or that the machine will boot. If the output has the wrong root device or kernel path, stop and correct the source or the migration plan. Do not compensate by guessing at GRUB numbering.
5. Decide how to deploy it
Do not copy the review file over a working /boot/grub/grub.cfg merely because conversion returned status 0. A successful conversion means that the program parsed and wrote the input. It does not validate your disks, kernels, modules, firmware mode or complete GRUB setup.
If your system has a documented migration procedure, follow that procedure and take a dated backup first. Reading the live file is unprivileged:
$ sudo cp --preserve=all /boot/grub/grub.cfg /boot/grub/grub.cfg.before-menu-lst-migration
$ sudo test -r /boot/grub/grub.cfg && echo 'live configuration is readable'
live configuration is readable
The backup command requires elevated privileges because /boot/grub is normally protected. The converter itself does not. Installation may also require elevated privileges, but the exact destination and surrounding GRUB fragments are distribution-specific and are outside the sparse local manual page. A boot configuration change can leave the machine unbootable, so arrange console or rescue access before making one.
To undo a deliberate replacement, boot into your recovery path or a working system and restore the backup only after checking the destination:
$ sudo test -f /boot/grub/grub.cfg.before-menu-lst-migration
$ sudo cp --preserve=all /boot/grub/grub.cfg.before-menu-lst-migration /boot/grub/grub.cfg
Do not delete the backup until you have successfully booted and confirmed the menu. Deleting that recovery copy is irreversible.
6. Diagnose failures without changing boot state
A missing or unreadable input produces a non-zero exit status and an error on standard error. Check the path and permissions first:
$ grub-menulst2cfg /path/to/missing-menu.lst /tmp/grub.cfg.converted
cannot open \`/path/to/missing-menu.lst': No such file or directory
$ printf 'converter status: %s\n' "$?"
converter status: 1
$ ls -l /path/to/menu.lst
$ test -r /path/to/menu.lst && echo readable
The command accepts at most two positional paths. The installed help output is only Usage: grub-menulst2cfg [INFILE [OUTFILE]], so do not invent long options for selecting a root device, changing numbering or validating a configuration. Put those decisions in the reviewed input and deployment process.
Done means
- The installed
grub-commonversion and input file were checked. - The original
menu.lsthas a separate preserved copy. - A converted file was written to a staging path and returned status 0.
- Titles, default, timeout, root device, kernel arguments and initrd commands were reviewed.
- The translated disk numbering was verified against the actual machine.
- No live boot configuration was overwritten without a backup and a recovery path.