[syslinux] [PATCH] Add support for DHCP-Options

Maurice Massar massar at unix-ag.uni-kl.de
Tue Apr 10 11:17:00 PDT 2007


hi,

I've written a start of an c32-module to do basic substition:

add subst.c32

this is a start of a generic substition module

---
commit 9a1f41a7e6599fe6a162197cd9ddc6610185e780
tree cfb799a0be9844926afe44e21b2eb96630666c44
parent 89478bdbfa7167bc1b627a478d042c99e46f06b7
author Maurice Massar <massar at unix-ag.uni-kl.de> Tue, 10 Apr 2007 20:13:39 +0200
committer Maurice Massar <massar at unix-ag.uni-kl.de> Tue, 10 Apr 2007 20:13:39 +0200

 com32/modules/Makefile |    3 -
 com32/modules/subst.c  |  229 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 231 insertions(+), 1 deletions(-)

diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index bef45a8..a7c2de9 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -45,7 +45,8 @@ INCDIR   = /usr/include
 COM32DIR = $(AUXDIR)/com32
 
 MODULES	  = chain.c32 menu.c32 vesamenu.c32 ethersel.c32 mboot.c32 \
-	    dmitest.c32 cpuidtest.c32 pcitest.c32 elf.c32 linux.c32
+	    dmitest.c32 cpuidtest.c32 pcitest.c32 elf.c32 linux.c32 \
+	    subst.c32
 TESTFILES =
 
 all: $(MODULES) $(TESTFILES)
diff --git a/com32/modules/subst.c b/com32/modules/subst.c
new file mode 100644
index 0000000..60241c9
--- /dev/null
+++ b/com32/modules/subst.c
@@ -0,0 +1,229 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2007 Maurice Massar <massar at unix-ag.uni-kl.de>
+ *
+ *   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, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * subst.c
+ *
+ * this is a start of a generic substitution module
+ *
+ * Currently only DHCP string options are supported.
+ *
+ * To use, set up a syslinux config file like this:
+ *
+ * LABEL something
+ *   KERNEL subst.c32
+ *   APPEND vmlinuz-${dhcp/option-123} initrd=initrd.img-${dhcp/option-123}.gz
+ *
+ * further:  ".localboot ###" is supported (like menu.c32 does)
+ *
+ * TODO:
+ *  - add support for concatenating options (current len limit: 255 bytes)
+ *  - add support for options overflowing into filename and server-name area
+ *  - add support to recode binary data to text
+ *  - add support for non-option dhcp data
+ *  - support to declare variables inside config-file
+ *
+ *  - if the comboot-api gets a methode to pass a configfile
+ *    (contents, not filename)  back to syslinux, use it!
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <console.h>
+#include <netinet/in.h>
+#include <syslinux/boot.h>
+#include <syslinux/pxe.h>
+
+typedef struct {
+	uint8_t opcode;
+	uint8_t hardware;
+	uint8_t hardware_len;
+	uint8_t gatehops;
+	uint32_t ident;
+	uint16_t seconds;
+	uint16_t flags;
+	
+	in_addr_t cip;
+	in_addr_t yip;
+	in_addr_t sip;
+	in_addr_t gip;
+	uint8_t caddr[16];
+	uint8_t sname[64];
+	uint8_t bootfile[128];
+	uint8_t options[];
+} __packed bootp_t;
+
+bootp_t *dhcpack;
+size_t dhcpack_len;
+
+int find_dhcp_option(uint8_t search, const uint8_t **str, int *len)
+{
+	uint8_t *p;
+	int l;
+	
+	p = dhcpack->options;
+	l = dhcpack_len - 236;
+	
+	p += 4; l -= 4; /* skip magic */
+	
+	while (l > 0) {
+		if (*p == 0) {
+			p++; l--;
+			continue;
+		}
+		if (*p == 255)
+			return 0;
+		if (*p == search)
+			break;
+		l -= 2 + p[1];
+		p += 2 + p[1];
+	}
+	
+	l -= 2;
+	l = (p[1] <= l) ? p[1] : l;
+	p += 2;
+	
+	*str = p;
+	*len = l;
+	return 1;
+}
+
+char *getvar_dhcp(const char *str, size_t len)
+{
+	const uint8_t *opt_str;
+	char *out = NULL;
+	int num, opt_len;
+	
+	if (len >= 7 && memcmp(str, "option-", 7) == 0) {
+		len -= 7; str += 7;
+		num = 0;
+		while (len-- > 0)
+			num = num*10 + *str++ - '0';
+		if (find_dhcp_option(num, &opt_str, &opt_len)) {
+			out = malloc(opt_len + 1);
+			memcpy(out, opt_str, opt_len);
+			out[opt_len] = '\0';
+		}
+	}
+	
+	return out;
+}
+
+char *getvar(const char *str, size_t len)
+{
+	char *out = NULL;
+	const char test[] = "UNKNOWN";
+	
+	if (len >= 5 && memcmp(str, "dhcp/", 5) == 0) {
+		out = getvar_dhcp(str+5, len-5);
+	}
+	
+	if (out == NULL) {
+		out = malloc(sizeof(test));
+		strcpy(out, test);
+	}
+	
+	return out;
+}
+
+void append_output(char **out, size_t *outlen, const char *str, size_t len)
+{
+	size_t used;
+	
+	used = (*out != NULL) ? strlen(*out) : 0;
+	if (used + len + 1 > *outlen) {
+		*outlen += 256 + (len & ~255);
+		*out = realloc(*out, *outlen);
+	}
+	memcpy(*out + used, str, len);
+	(*out)[used+len] = '\0';
+}
+
+char *do_subst(const char *str)
+{
+	int i;
+	enum {NORMAL, LITERAL, QUOTE} state = NORMAL;
+	char *out = NULL, *replacement;
+	const char *start, *stop;
+	size_t outlen = 0;
+	
+	for (i = 0; str[i] != '\0'; i++) {
+		switch (state) {
+		case LITERAL:
+			append_output(&out, &outlen, str+i, 1);
+			state = NORMAL;
+			break;
+		case QUOTE:
+			if (str[i] == '\'') {
+				state = NORMAL;
+				break;
+			}
+			append_output(&out, &outlen, str+i, 1);
+			break;
+		case NORMAL:
+			if (str[i] == '\\') {
+				state = LITERAL;
+				break;
+			} else if (str[i] == '\'') {
+				state = QUOTE;
+				break;
+			} else if (str[i] != '$') {
+				append_output(&out, &outlen, str+i, 1);
+				break;
+			}
+			start = (str[i+1] == '{') ? str+i+1 : NULL;
+			stop = strchr(str+i+2, '}');
+			if (start == NULL || stop == NULL) {
+				append_output(&out, &outlen, str+i, 1);
+				break;
+			}
+			replacement = getvar(start + 1, stop-start-1);
+			append_output(&out, &outlen, replacement, strlen(replacement));
+			free(replacement);
+			i += stop-start+1;
+			break;
+		} 
+	}
+	
+	return out;
+}
+
+int main(int argc, char *argv[])
+{
+	int i;
+	char *out, *cmdline = NULL;
+	void *buf;
+	size_t cmd_len = 0;
+	
+	openconsole(&dev_stdcon_r, &dev_stdcon_w);
+	if (pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, &buf, &dhcpack_len) != 0) {
+		fprintf(stderr, "failed to get dhcp infos\n");
+		return 1;
+	}
+	dhcpack = (bootp_t *)buf;
+	
+	for (i = 1; i < argc; i++) {
+		out = do_subst(argv[i]);
+		append_output(&cmdline, &cmd_len, out, strlen(out));
+		free(out);
+		if (i+1 < argc)
+			append_output(&cmdline, &cmd_len, " ", 1);
+	}
+	printf("subst: cmdline=%s\n", cmdline);
+	if (memcmp(cmdline, ".localboot ", 11) == 0) {
+		syslinux_local_boot(strtol(cmdline+11, NULL, 0));
+	}
+	syslinux_run_command(cmdline);
+	
+	return 0;
+}




More information about the Syslinux mailing list