/pxe-menu

Dynamic menu (boot entry) generation over HTTP for SYSLINUX (and menu.c32)

Primary LanguagePerl

* menu.cgi - Dynamic syslinux menu generation

A weird imagination is most useful to gain full advantage of all the features. -- amd(8) manpage

* Notes
While this document itself is still valid (and the tool is also
actively used (at least by me)), many other things has changed:

- TAR package is not distributed anymore - please do a git clone from github.
- I no longer maintain live demo site.
-- I used to recommend trying BKO (http://boot.kernel.org/) as it was
   somewhat close, bt it also seems gone.
- AFAIK, instead of gPXE, iPXE (http://ipxe.org/) is now recommended.

* What is this?

Menu.cgi is a web CGI script to generate syslinux boot menu over HTTP.
Since its integration with gPXE/Etherboot, SYSLINUX 3.70 and after supports
non-TFTP protocols for network booting. This means you can do many
obscure^H^H^H useful things, such as:

- Browse and boot from files on remote web server through SYSLINUX menu.
- Generate miniroot image on-the-fly, customizing it dynamically as needed.
- Boot directly from image attached on some wiki page :-) 

This script handles first two use-cases.

As an example, I now do "mount --rbind /nfs /tftp/nfs" and let this
script generate appropriate boot entries for whatever kernels installed
under NFSroot environment. This is a real time saver for me, as
I no longer need to update bootmenu every time I setup new kernel
image or nfsroot tree for test environment.

* Major Features

With this script, you can:

- Freely browse folders and boot from any files.
- No more menu editing. Just place files and off you go.
- Generate menu dynamically from custom template.
- Embed scripts in Perl and simplify maintainance (or make more complex one).
- Search across menu entries and show result as a menu.
- Grep through numerous menu entries using Perl expression.
- Generate cpio/tar/gzip archive on-the-fly.
- Edit and boot directly from your custom initramfs in extracted form.
- Rewrite file content on-the-fly with s/match/replace/ expression.
- Stuck with hardcoded NFSroot path in *BSD pxeboot? Just substitute it.

More functionality can by added by extending custom menu template in
configuration file.

* Installation

Installation is easy. Just extract distributed package ("menu.tgz") in
your "tftpboot" folder and make it accessible from the Web. Everything,
including menu.c32 and depending Perl libraries are packaged (You might
want to update or relocate these dependent files).

After extraction is done, try booting with following syslinux entry:

  label remote
    kernel http://location/of/menu.c32
    append http://location/of/menu.cgi

Once booted, you should see syslinux menu entry with a list of folder content.

* Usage

Currently, menu.cgi supports 2 parameters: 'q=' and 'r='.
'q=' is the primary parameter used to specify target for menu generation.

- With "q=folder", folder listing will be returned.
- With "q=file", file content will be returned.
- With "q=query", menu entries are grepped with given query, and matching
  entries will be returned.

For "q=query", you can specify Perl expression.

- With "q=m,debian,", menu entries with the word "debian" will be listed.
- With "q=m,debian,+and+m,sid,", menu entries with the word "debian"
  AND "sid" will be listed.
- With "q=m,debian,+and+not+m,sid,", menu entries with the word "debian"
  BUT NOT "sid" will be listed.

This syntax is somewhat limited, as you need to avoid using "/" and
various non-alphanumeral characters due to security restrictions and
URI escaping rule.

When "q=file" is specified, "r=" can be optionally specified to filter
file content. For example, with "r=s,/nfsroot,/n/fb70a,g", all "/nfsroot"
in that file will be replaced into "/n/fb70a".

This kludgy feature exists to rewrite hardcoded NFSroot path in *BSD
pxeboot image. Although *BSD pxeboot can obtain NFSroot path through
DHCP option, that won't work when I'm chainloading into *BSD pxeboot
from PXELINUX. If anyone can provide me better way to boot NFSroot-ed *BSD,
that is very appreciated.

Lastly, you can pass other parameters, and they can be referenced in
template to customize evaluation behavior. However, please avoid using
single-character parameter as it is reserved for future usage.

* Configuration

Configuration can be done in either "/etc/syslinux/mcgi.config" or
"./.mcgi.config" file. These are loaded as Perl script file, and
customization is done by defining certain variables.

Following is an example of configuration:

  # define location of various files
  $CONFIG->{LIB_URI} = "http://boot/m/syslinux/lib/";
  $CONFIG->{CGI_URI} = "http://boot/menu.cgi";
  1;
  
  # define template as Perl __DATA__ block
  __DATA__
  label reload
    kernel <%= $LIB_URI %>/menu.c32
    append <%= $CGI_URI %>?<%= $ENV{QUERY_STRING} %>
  
Configuration variables "$CONFIG->{LIB_URI}" and "$CONFIG->{CGI_URI}"
are used to specify location of syslinux module folder and menu.cgi itself.
By default, these are automatically determined, but you should probably
specify "$CONFIG->{LIB_URI}" to use latest syslinux modules (or just
overwrite bundled one).

Custom menu template goes after __DATA__ block. "__DATA__" is a
special Perl token to define data block which can be read like normal
external file. Content of __DATA__ block should contain
Text::ScriptTemplate(3pm) template, expandable to SYSLINUX menu
format (details in next section).

* Template Configuration

Menu template is expanded by evaluating embedded Perl expression.
Two rules of expansion are:

  Rule #1:
  Block surrounded by '<%=' and '%>' will be replaced with its evaluated
  result. This means '<%= 1 + 2 %>' will result to '3' in final output.

  Rule #2:
  Block surrounded by '<%' and '%>' defines non-expanded part of a script.
  This means '<% $FOO = 123 %>' defines variable '$FOO', but no output is
  generated.

So, with template like below, only user with correct keyword will be able
to access hidden boot entry:

  <% if ($CGI->param('keyword') eq 'hogehoge') { %>
  label betatest
    kernel http://example.com/boot/really-beta-kernel
    initrd http://example.com/boot/really-beta-initrd
    append root=/dev/nfs rw ip=dhcp nfsroot=<%= $ENV{HTTP_HOST} %>:/betatest
  <% } %>

Now, the question is: what variables do I have access to in template?
Well, here's the list of available variables:

- $CONFIG
  This is a hash which contains whatever you defined in configuration.
  So if you wrote "$CONFIG->{FOO} = 123;", you can refer to it by
  "$CONFIG->{FOO}".

- $CGI
  This is a CGI::Simple object which holds decoded query parameter.
  So if you called CGI as "http://host/menu.cgi?myparam=123", you can
  refer to "myparam" value by "$CGI->param('myparam')".

- $CGI_URI
  This variable contains URL of called CGI.

- $LIB_URI
  This variable contains URL of SYSLINUX library folder.

- $UPLEVEL
  This variable contains "parent" path of the path specified with
  "q=" CGI parameter.

- $LIST
  This holds a list of menu entries to expand in template.
  Each element is a hash with following structure:

    $entry = {
      name => "entry name probably suitable for LABEL entry",
      type => "typecode or suffix of found entry",
      path => "relative path, valid as menu.cgi?q= parameter",
      uri => "absolute URL of above 'menu.cgi?q=path' location"
      ... # other fields depends on type
    };

  For actual typecode or field content, please refer to included samples.

Other standard variables like "%ENV" are available as well.

* License

This script is free software; you can redistribute it and/or modify
it under the same terms as SYSLINUX. Other bundled copyrighted materials
follow each license.

* References
- Syslinux Project
-- http://www.syslinux.org/wiki/index.php/The_Syslinux_Project
- Etherboot/gPXE Project
-- http://etherboot.org/wiki/start
- gPXE - HTTP booting
-- http://etherboot.org/wiki/httpboot
- Syslinux - syntax
-- http://www.syslinux.org/wiki/index.php/SYSLINUX
- Syslinux - menu.c32
-- http://www.syslinux.org/wiki/index.php/Comboot/menu.c32

* Authors/Contributors
- Taisuke Yamada <tai+syslinux@remove-this-if-not-spam.cc.rakugaki.org>