[gPXE-devel] [PATCH] [scriptlet] Add "scriptlet" NonVolatile Option (NVO) support.

Glenn Brown glenn at myri.com
Tue Jun 29 03:43:44 EDT 2010


If the "scriptlet" NVO is set, gPXE will execute its value as a script
before executing any embedded script and before attempting to
autoboot.  This allows users to override or augment compiled-in boot
behaviour by setting "scriptlet" using the gPXE command line
interface.  Scriptlets may be up to 255 characters long, but may be limitted
by available NVO storage.

Useful scriptlets need not be long.  Some examples are:
"ifopen net0\nsanboot ${net0/root-path}":
  sanboot without DHCP, using NVO "ip", "netmask", and "root-path" settings.
"autoboot\nloopif 1"
  autoboot, retrying forever, using the experimental "loopif" command.

Being able to modify boot behaviour without recompiling can be useful
to users under the following circumstances:
* The user does not have tools required to burn a ROM.
* The user cannot conveniently recompile because they use an OS
  that cannot rebuild gPXE, or cannot reprogram ROMs.
* The user cannot conveniently access the web (for ROM-o-matic), because
  they are in a secure facility without Internet access.
* The user cannot reprogram NICs without removing them from a machine.
  (This is a big deal when you have hundreds of machines.)

Signed-off-by: Glenn Brown <glenn at myri.com>
---
 src/core/main.c              |   16 ++++++--
 src/hci/scriptlet.c          |   87 ++++++++++++++++++++++++++++++++++++++++++
 src/include/gpxe/dhcp.h      |    9 ++++
 src/include/gpxe/errfile.h   |    1 +
 src/include/gpxe/scriptlet.h |    8 ++++
 5 files changed, 117 insertions(+), 4 deletions(-)
 create mode 100644 src/hci/scriptlet.c
 create mode 100644 src/include/gpxe/scriptlet.h

diff --git a/src/core/main.c b/src/core/main.c
index d07d24c..620d30b 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -17,6 +17,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <stdio.h>
 #include <gpxe/init.h>
 #include <gpxe/features.h>
+#include <gpxe/scriptlet.h>
 #include <gpxe/shell.h>
 #include <gpxe/shell_banner.h>
 #include <gpxe/image.h>
@@ -67,10 +68,17 @@ __asmcall int main ( void ) {
 		/* User wants shell; just give them a shell */
 		shell();
 	} else {
-		/* User doesn't want shell; load and execute the first
-		 * image, or autoboot() if we have no images.  If
-		 * booting fails for any reason, offer a second chance
-		 * to enter the shell for diagnostics.
+		/* User doesn't want shell; execute any nonvolatile
+		 * scriptlet first, so the user can override compiled
+		 * in boot images by setting a scriptlet using the
+		 * preboot shell.
+		 */
+		scriptlet_exec ();
+
+		/* Load and execute the boot images, or autoboot() if
+		 * we have no image.  If booting fails for any reason,
+		 * offer a second chance to enter the shell for
+		 * diagnostics.
 		 */
 		if ( have_images() ) {
 			for_each_image ( image ) {
diff --git a/src/hci/scriptlet.c b/src/hci/scriptlet.c
new file mode 100644
index 0000000..cafd9e7
--- /dev/null
+++ b/src/hci/scriptlet.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2010 Myricom, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <gpxe/dhcp.h>
+#include <gpxe/scriptlet.h>
+#include <gpxe/settings.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+/** Scriptlet setting */
+struct setting scriptlet_setting __setting = {
+	.name = "scriptlet",
+	.description = "small boot script",
+	.tag = DHCP_EB_SCRIPTLET,
+	.type = &setting_type_string,
+};
+extern struct setting scriptlet_setting __setting;
+
+/**
+ * Find a "scriptlet" NonVolatile Option (NVO), if one has been set,
+ * and execute it.  Script lines are separated by the "\n" escape
+ * sequence.  Other escape sequences are translated from "\X" to "X".
+ *
+ * If multiple NICs with NVO support are present, it is possible to set
+ * multiple scriptlets, but this routine will only execute the first one
+ * found.
+ */
+void scriptlet_exec (void)
+{
+	char script[256];
+	char *line, *from, *to;
+
+	DBGP ( "scriptlet_exec\n" );
+
+	/* Find a startup scriptlet, if one has been set. */
+	if ( 0 >= fetch_setting ( NULL,
+				  &scriptlet_setting,
+				  script,
+				  sizeof ( script ) ) ) {
+		DBG2 ("No scriptlet\n");
+		return;
+	}
+
+	/* Convert escape sequences, and execute each line of the script. */
+	line = from = to = script;
+	while ( *from ) {
+		/* Handle escape sequences. */
+		if ( *from == '\\' ) {
+			from++;
+			/* backslash at end of script is ignored. */
+			if ( *from == 0 ) {
+				break;
+			}
+			/* backslash-n translates as end-of-line. */
+			if ( *from == 'n' ) {
+				from++;
+				*to++ = 0;
+				DBG2 ( "> %s\n", line );
+				system ( line );
+				line = to;
+				continue;
+			}
+		}
+		*to++ = *from++;
+	}
+	/* Execute the last line of the script. */
+	*to++ = 0;
+	DBG2 ( "> %s\n", line );
+	system ( line );
+}
diff --git a/src/include/gpxe/dhcp.h b/src/include/gpxe/dhcp.h
index c747948..8a3cffa 100644
--- a/src/include/gpxe/dhcp.h
+++ b/src/include/gpxe/dhcp.h
@@ -386,6 +386,15 @@ struct dhcp_netdev_desc {
  */
 #define DHCP_EB_REVERSE_PASSWORD DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xc1 )
 
+/** Scriptlet
+ *
+ * A smal initialization script that can be stored in nonvolatile memory.
+ * Since the Etherboot UI does not support newlines in settings, the
+ * escape sequence '\n' is treated as a newline.  All other '\X'
+ * escape sequences pass through the the escaped character unchanged.
+ */
+#define DHCP_EB_SCRIPTLET DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xc2 )
+
 /** gPXE version number */
 #define DHCP_EB_VERSION DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xeb )
 
diff --git a/src/include/gpxe/errfile.h b/src/include/gpxe/errfile.h
index a17da90..ff06725 100644
--- a/src/include/gpxe/errfile.h
+++ b/src/include/gpxe/errfile.h
@@ -183,6 +183,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ERRFILE_segment		      ( ERRFILE_IMAGE | 0x00030000 )
 #define ERRFILE_efi_image	      ( ERRFILE_IMAGE | 0x00040000 )
 #define ERRFILE_embedded	      ( ERRFILE_IMAGE | 0x00050000 )
+#define ERRFILE_scriptlet	      ( ERRFILE_IMAGE | 0x00060000 )
 
 #define ERRFILE_asn1		      ( ERRFILE_OTHER | 0x00000000 )
 #define ERRFILE_chap		      ( ERRFILE_OTHER | 0x00010000 )
diff --git a/src/include/gpxe/scriptlet.h b/src/include/gpxe/scriptlet.h
new file mode 100644
index 0000000..64495ab
--- /dev/null
+++ b/src/include/gpxe/scriptlet.h
@@ -0,0 +1,8 @@
+#ifndef _GPXE_SCRIPTLET_H
+#define _GPXE_SCRIPTLET_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+void scriptlet_exec ( void );
+
+#endif
-- 
1.7.0.4



More information about the gPXE-devel mailing list