[syslinux:lwip] Additional sysappend strings from DMI; pre-bake the http cookies

syslinux-bot for H. Peter Anvin hpa at linux.intel.com
Tue Apr 26 14:45:20 PDT 2011


Commit-ID:  b6401220c0bf7482ad5b204d08ba831a7cf9eabb
Gitweb:     http://syslinux.zytor.com/commit/b6401220c0bf7482ad5b204d08ba831a7cf9eabb
Author:     H. Peter Anvin <hpa at linux.intel.com>
AuthorDate: Tue, 26 Apr 2011 14:41:31 -0700
Committer:  H. Peter Anvin <hpa at linux.intel.com>
CommitDate: Tue, 26 Apr 2011 14:41:31 -0700

Additional sysappend strings from DMI; pre-bake the http cookies

- Add additional sysappend strings from DMI; we may want to add even
  more but let's think about it first.
- Pre-generate http cookies.
- Add a "sendcookies" command to mask out some of the information.

Signed-off-by: H. Peter Anvin <hpa at linux.intel.com>


---
 com32/include/syslinux/sysappend.h |    6 +-
 com32/lib/Makefile                 |    2 +-
 core/dmi.c                         |  256 ++++++++++++++++++++++++++++++++++++
 core/extern.inc                    |    5 +-
 core/fs/pxe/http.c                 |   61 +++++----
 core/fs/pxe/pxe.c                  |  111 ++--------------
 core/fs/pxe/pxe.h                  |    1 +
 core/include/core.h                |    1 +
 core/init.inc                      |    6 +
 core/keywords                      |    1 +
 core/keywords.inc                  |    3 +
 core/parseconfig.inc               |    9 ++
 core/sysappend.c                   |   67 +++++++++-
 13 files changed, 401 insertions(+), 128 deletions(-)

diff --git a/com32/include/syslinux/sysappend.h b/com32/include/syslinux/sysappend.h
index dcc42dc..b767bf2 100644
--- a/com32/include/syslinux/sysappend.h
+++ b/com32/include/syslinux/sysappend.h
@@ -37,7 +37,11 @@
 enum syslinux_sysappend {
     SYSAPPEND_IP,		/* PXELINUX: ip= address */
     SYSAPPEND_BOOTIF,		/* PXELINUX: BOOTIF= address */
-    SYSAPPEND_UUID,		/* System UUID from PXE or DMI */
+    SYSAPPEND_SYSUUID,		/* System UUID from PXE or DMI */
+    SYSAPPEND_SYSVENDOR,	/* System vendor from DMI */
+    SYSAPPEND_SYSPRODUCT,	/* System product from DMI */
+    SYSAPPEND_SYSVERSION,	/* System version from DMI */
+    SYSAPPEND_SYSSERIAL,	/* System serial from DMI */
     SYSAPPEND_MAX		/* Total number of strings */
 };
 
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index 105c2bd..20002ac 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -134,7 +134,7 @@ LIBCOREOBJS = 	\
 	strlen.o stpcpy.o strcpy.o strcmp.o strlcpy.o strlcat.o		\
 	strchr.o strncmp.o strncpy.o					\
 	\
-	snprintf.o sprintf.o vsnprintf.o				\
+	asprintf.o snprintf.o sprintf.o vsnprintf.o			\
 	\
 	dprintf.o vdprintf.o						\
 	\
diff --git a/core/dmi.c b/core/dmi.c
new file mode 100644
index 0000000..674d27c
--- /dev/null
+++ b/core/dmi.c
@@ -0,0 +1,256 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2011 Intel Corporation; author: H. Peter Anvin
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Search DMI information for specific data or strings
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <syslinux/sysappend.h>
+#include "core.h"
+
+struct dmi_table {
+    uint8_t type;
+    uint8_t length;
+    uint16_t handle;
+};
+
+struct dmi_header {
+    char signature[5];
+    uint8_t csum;
+    uint16_t tbllen;
+    uint32_t tbladdr;
+    uint16_t nstruc;
+    uint8_t revision;
+    uint8_t reserved;
+};
+
+struct smbios_header {
+    char signature[4];
+    uint8_t csum;
+    uint8_t len;
+    uint8_t major;
+    uint8_t minor;
+    uint16_t maxsize;
+    uint8_t revision;
+    uint8_t fmt[5];
+
+    struct dmi_header dmi;
+};
+
+static const struct dmi_header *dmi;
+
+static uint8_t checksum(const void *buf, size_t len)
+{
+    const uint8_t *p = buf;
+    uint8_t csum = 0;
+
+    while (len--)
+	csum += *p++;
+
+    return csum;
+}
+
+static bool is_old_dmi(size_t dptr)
+{
+    const struct dmi_header *dmi = (void *)dptr;
+
+    return !memcmp(dmi->signature, "_DMI_", 5) &&
+	!checksum(dmi, 0x0f);
+    return false;
+}
+
+static bool is_smbios(size_t dptr)
+{
+    const struct smbios_header *smb = (void *)dptr;
+
+    return !memcmp(smb->signature, "_SM_", 4) &&
+	!checksum(smb, smb->len) &&
+	is_old_dmi(dptr+16);
+}
+
+/*
+ * Find the root structure
+ */
+static void dmi_find_header(void)
+{
+    size_t dptr;
+
+    /* Search for _SM_ or _DMI_ structure */
+    for (dptr = 0xf0000 ; dptr < 0x100000 ; dptr += 16) {
+	if (is_smbios(dptr)) {
+	    dmi = (const struct dmi_header *)(dptr + 16);
+	    break;
+	} else if (is_old_dmi(dptr)) {
+	    dmi = (const struct dmi_header *)dptr;
+	    break;
+	}
+    }
+}
+
+/*
+ * Return a specific data element in a specific table, and verify
+ * that it is within the bounds of the table.
+ */
+static const void *dmi_find_data(uint8_t type, uint8_t base, uint8_t length)
+{
+    const struct dmi_table *table;
+    size_t offset, end;
+    unsigned int tblcount;
+
+    if (!dmi)
+	return NULL;
+
+    if (base < 2)
+	return NULL;
+
+    end = base+length;
+
+    offset = 0;
+    tblcount = dmi->nstruc;
+
+    while (offset+2 < dmi->tbllen && tblcount) {
+	table = (const struct dmi_table *)(dmi->tbladdr + offset);
+
+	if (table->length < sizeof *table)
+	    break;		/* Invalid length */
+
+	offset += table->length;
+
+	if (table->type == type && end <= table->length)
+	    return (const char *)table + base;
+
+	/* Search for a double NUL terminating the string table */
+	while (offset+2 < dmi->tbllen &&
+	       *(const uint16_t *)(dmi->tbladdr + offset) != 0)
+	    offset++;
+
+	offset += 2;
+	tblcount--;
+    }
+
+    return NULL;
+}
+
+/*
+ * Return a specific string in a specific table.
+ */
+static const char *dmi_find_string(uint8_t type, uint8_t base)
+{
+    const struct dmi_table *table;
+    size_t offset;
+    unsigned int tblcount;
+
+    if (!dmi)
+	return NULL;
+
+    if (base < 2)
+	return NULL;
+
+    offset = 0;
+    tblcount = dmi->nstruc;
+
+    while (offset+2 < dmi->tbllen && tblcount) {
+	table = (const struct dmi_table *)(dmi->tbladdr + offset);
+
+	if (table->length < sizeof *table)
+	    break;		/* Invalid length */
+
+	offset += table->length;
+
+	if (table->type == type && base < table->length) {
+	    uint8_t index = ((const uint8_t *)table)[base];
+	    const char *p = (const char *)table + table->length;
+	    char c;
+
+	    if (!index)
+		return NULL;	/* String not present */
+
+	    while (--index) {
+		if (!*p)
+		    return NULL;
+
+		do {
+		    c = *p;
+		    if (++offset >= dmi->tbllen)
+			return NULL;
+		    p++;
+		} while (c);
+	    }
+
+	    return p;
+	}
+
+	/* Search for a double NUL terminating the string table */
+	while (offset+2 < dmi->tbllen &&
+	       *(const uint16_t *)(dmi->tbladdr + offset) != 0)
+	    offset++;
+
+	offset += 2;
+    }
+
+    return NULL;
+}
+
+struct sysappend_dmi_strings {
+    const char *prefix;
+    enum syslinux_sysappend sa;
+    uint8_t index;
+    uint8_t offset;
+};
+
+static const struct sysappend_dmi_strings dmi_strings[] = {
+    { "SYSVENDOR=",  SYSAPPEND_SYSVENDOR,  1, 0x04 },
+    { "SYSPRODUCT=", SYSAPPEND_SYSPRODUCT, 1, 0x05 },
+    { "SYSVERSION=", SYSAPPEND_SYSVERSION, 1, 0x06 },
+    { "SYSSERIAL=",  SYSAPPEND_SYSSERIAL,  1, 0x07 },
+    { NULL, 0, 0, 0 }
+};
+
+void dmi_init(void)
+{
+    const struct sysappend_dmi_strings *ds;
+
+    dmi_find_header();
+    if (!dmi)
+	return;
+
+    sysappend_set_uuid(dmi_find_data(1, 0x08, 16));
+
+    for (ds = dmi_strings; ds->prefix; ds++) {
+	const char *str = dmi_find_string(ds->index, ds->offset);
+
+	if (sysappend_strings[ds->sa]) {
+	    free((char *)sysappend_strings[ds->sa]);
+	    sysappend_strings[ds->sa] = NULL;
+	}
+	if (str)
+	    asprintf((char **)&sysappend_strings[ds->sa],
+		     "%s%s", ds->prefix, str);
+    }
+}
diff --git a/core/extern.inc b/core/extern.inc
index 433d55e..3858f70 100644
--- a/core/extern.inc
+++ b/core/extern.inc
@@ -30,9 +30,12 @@
 	; sysappend.c
 	extern do_sysappend, print_sysappend
 
+	; dmi.c
+	extern dmi_init
+
 %if IS_PXELINUX
 	; pxe.c
-	extern unload_pxe, reset_pxe
+	extern unload_pxe, reset_pxe, http_bake_cookies
 %endif
 
 %endif ; EXTERN_INC
diff --git a/core/fs/pxe/http.c b/core/fs/pxe/http.c
index ae5e010..d98cc4a 100644
--- a/core/fs/pxe/http.c
+++ b/core/fs/pxe/http.c
@@ -46,8 +46,10 @@ static bool append_ch(char *str, size_t size, size_t *pos, int ch)
     return success;
 }
 
-static size_t cookie_len;
-static char *cookie_buf;
+static size_t cookie_len, header_len;
+static char *cookie_buf, *header_buf;
+
+extern uint32_t SendCookies;
 
 static size_t http_do_bake_cookies(char *q)
 {
@@ -59,9 +61,10 @@ static size_t http_do_bake_cookies(char *q)
     char c;
     size_t qlen = q ? -1UL : 0;
     bool first = true;
+    uint32_t mask = SendCookies;
 
     for (i = 0; i < SYSAPPEND_MAX; i++) {
-	if ((p = sysappend_strings[i])) {
+	if ((mask & 1) && (p = sysappend_strings[i])) {
 	    len = snprintf(q, qlen, "%s_Syslinux_", first ? "Cookie: " : "");
 	    if (q)
 		q += len;
@@ -96,6 +99,7 @@ static size_t http_do_bake_cookies(char *q)
 		*q++ = ';';
 	    n++;
 	}
+	mask >>= 1;
     }
     if (!first) {
 	if (q) {
@@ -117,8 +121,20 @@ void http_bake_cookies(void)
 
     cookie_len = http_do_bake_cookies(NULL);
     cookie_buf = malloc(cookie_len+1);
-    if (!cookie_buf)
+    if (!cookie_buf) {
+	cookie_len = 0;
 	return;
+    }
+
+    if (header_buf)
+	free(header_buf);
+
+    header_len = cookie_len + 6*FILENAME_MAX + 256;
+    header_buf = malloc(header_len);
+    if (!header_buf) {
+	header_len = 0;
+	return;			/* Uh-oh... */
+    }
 
     http_do_bake_cookies(cookie_buf);
 }
@@ -126,8 +142,7 @@ void http_bake_cookies(void)
 void http_open(struct url_info *url, struct inode *inode, const char **redir)
 {
     struct pxe_pvt_inode *socket = PVT(inode);
-    char header_buf[4096];
-    int header_len;
+    int header_bytes;
     const char *next;
     char field_name[20];
     char field_value[1024];
@@ -151,9 +166,8 @@ void http_open(struct url_info *url, struct inode *inode, const char **redir)
     int status;
     int pos;
 
-    /* XXX: make this an external call at the appropriate time instead */
-    if (!cookie_buf)
-	http_bake_cookies();
+    if (!header_buf)
+	return;			/* http is broken... */
 
     socket->fill_buffer = tcp_fill_buffer;
     socket->close = tcp_close_file;
@@ -178,26 +192,25 @@ void http_open(struct url_info *url, struct inode *inode, const char **redir)
     }
 
     strcpy(header_buf, "GET /");
-    header_len = 5;
-    header_len += url_escape_unsafe(header_buf+5, url->path,
+    header_bytes = 5;
+    header_bytes += url_escape_unsafe(header_buf+5, url->path,
 				    sizeof header_buf - 5);
-    if (header_len > sizeof header_buf)
+    if (header_bytes > header_len)
 	goto fail;		/* Buffer overflow */
-    header_len += snprintf(header_buf + header_len,
-			   sizeof header_buf - header_len,
-			   " HTTP/1.0\r\n"
-			   "Host: %s\r\n"
-			   "User-Agent: PXELINUX/%s\r\n"
-			   "Connection: close\r\n"
-			   "%s"
-			   "\r\n",
-			   url->host, VERSION_STR,
-			   cookie_buf ? cookie_buf : "");
-    if (header_len > sizeof header_buf)
+    header_bytes += snprintf(header_buf + header_bytes,
+			     header_len - header_bytes,
+			     " HTTP/1.0\r\n"
+			     "Host: %s\r\n"
+			     "User-Agent: PXELINUX/" VERSION_STR "\r\n"
+			     "Connection: close\r\n"
+			     "%s"
+			     "\r\n",
+			     url->host, cookie_buf ? cookie_buf : "");
+    if (header_bytes > sizeof header_buf)
 	goto fail;		/* Buffer overflow */
 
     err = netconn_write(socket->conn, header_buf,
-			header_len, NETCONN_NOCOPY);
+			header_bytes, NETCONN_NOCOPY);
     if (err) {
 	printf("netconn_write error %d\n", err);
 	goto fail;
diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c
index c1b8476..4bf8d00 100644
--- a/core/fs/pxe/pxe.c
+++ b/core/fs/pxe/pxe.c
@@ -77,50 +77,6 @@ static void pxe_close_file(struct file *file)
     free_socket(inode);
 }
 
-/**
- * Take a nubmer of bytes in memory and convert to lower-case hxeadecimal
- *
- * @param: dst, output buffer
- * @param: src, input buffer
- * @param: count, number of bytes
- *
- */
-static void lchexbytes(char *dst, const void *src, int count)
-{
-    uint8_t half;
-    uint8_t c;
-    const uint8_t *s = src;
-
-    for(; count > 0; count--) {
-        c = *s++;
-        half   = ((c >> 4) & 0x0f) + '0';
-        *dst++ = half > '9' ? (half + 'a' - '9' - 1) : half;
-
-        half   = (c & 0x0f) + '0';
-        *dst++ = half > '9' ? (half + 'a' - '9' - 1) : half;
-    }
-}
-
-/*
- * just like the lchexbytes, except to upper-case
- *
- */
-static void uchexbytes(char *dst, const void *src, int count)
-{
-    uint8_t half;
-    uint8_t c;
-    const uint8_t *s = src;
-
-    for(; count > 0; count--) {
-        c = *s++;
-        half   = ((c >> 4) & 0x0f) + '0';
-        *dst++ = half > '9' ? (half + 'A' - '9' - 1) : half;
-
-        half   = (c & 0x0f) + '0';
-        *dst++ = half > '9' ? (half + 'A' - '9' - 1) : half;
-    }
-}
-
 /*
  * Tests an IP address in _ip_ for validity; return with 0 for bad, 1 for good.
  * We used to refuse class E, but class E addresses are likely to become
@@ -149,27 +105,11 @@ bool ip_ok(uint32_t ip)
  */
 static int gendotquad(char *dst, uint32_t ip)
 {
-    int part;
-    int i = 0, j;
-    char temp[4];
-    char *p = dst;
-
-    for (; i < 4; i++) {
-        j = 0;
-        part = ip & 0xff;
-        do {
-            temp[j++] = (part % 10) + '0';
-        }while(part /= 10);
-        for (; j > 0; j--)
-            *p++ = temp[j-1];
-        *p++ = '.';
-
-        ip >>= 8;
-    }
-    /* drop the last dot '.' and zero-terminate string*/
-    *(--p) = 0;
-
-    return p - dst;
+    return sprintf(dst, "%u.%u.%u.%u",
+		   ((const uint8_t *)&ip)[0],
+		   ((const uint8_t *)&ip)[1],
+		   ((const uint8_t *)&ip)[2],
+		   ((const uint8_t *)&ip)[3]);
 }
 
 /*
@@ -544,8 +484,8 @@ static int pxe_load_config(void)
     config_file = stpcpy(ConfigName, cfgprefix);
 
     /* Try loading by UUID */
-    if (sysappend_strings[SYSAPPEND_UUID]) {
-	strcpy(config_file, sysappend_strings[SYSAPPEND_UUID]+8);
+    if (sysappend_strings[SYSAPPEND_SYSUUID]) {
+	strcpy(config_file, sysappend_strings[SYSAPPEND_SYSUUID]+8);
 	if (try_load(ConfigName))
             return 0;
     }
@@ -556,7 +496,7 @@ static int pxe_load_config(void)
         return 0;
 
     /* Nope, try hexadecimal IP prefixes... */
-    uchexbytes(config_file, (uint8_t *)&IPInfo.myip, 4);
+    sprintf(config_file, "%08X", ntohl(IPInfo.myip));
     last = &config_file[8];
     while (tries) {
         *last = '\0';        /* Zero-terminate string */
@@ -592,36 +532,6 @@ static void make_bootif_string(void)
 
     sysappend_strings[SYSAPPEND_BOOTIF] = bootif_str;
 }
-/*
- * Generate the SYSUUID string, if we have one...
- */
-static void make_sysuuid_string(void)
-{
-    static char sysuuid_str[8+32+5];
-    static const uint8_t uuid_dashes[] = {4, 2, 2, 2, 6, 0};
-    const uint8_t *src = uuid;
-    const uint8_t *uuid_ptr = uuid_dashes;
-    char *dst;
-
-    /* Try loading by UUID */
-    if (have_uuid) {
-	dst = stpcpy(sysuuid_str, "SYSUUID=");
-
-        while (*uuid_ptr) {
-	    int len = *uuid_ptr;
-
-            lchexbytes(dst, src, len);
-            dst += len * 2;
-            src += len;
-            uuid_ptr++;
-            *dst++ = '-';
-        }
-        /* Remove last dash and zero-terminate */
-	*--dst = '\0';
-
-	sysappend_strings[SYSAPPEND_UUID] = sysuuid_str;
-    }
-}
 
 /*
  * Generate an ip=<client-ip>:<boot-server-ip>:<gw-ip>:<netmask>
@@ -937,8 +847,11 @@ static void network_init(void)
     printf("\n");
 
     make_bootif_string();
-    make_sysuuid_string();
+    /* If DMI and DHCP disagree, which one should we set? */
+    if (have_uuid)
+	sysappend_set_uuid(uuid);
     ip_init();
+    http_bake_cookies();
     print_sysappend();
 
     /*
diff --git a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h
index d3e7499..0200c1e 100644
--- a/core/fs/pxe/pxe.h
+++ b/core/fs/pxe/pxe.h
@@ -227,6 +227,7 @@ void gpxe_open(struct inode *inode, const char *url);
 
 /* http.c */
 void http_open(struct url_info *url, struct inode *inode, const char **redir);
+void http_bake_cookies(void);
 
 /* ftp.c */
 void ftp_open(struct url_info *url, struct inode *inode, const char **redir);
diff --git a/core/include/core.h b/core/include/core.h
index 4420fec..965b990 100644
--- a/core/include/core.h
+++ b/core/include/core.h
@@ -48,6 +48,7 @@ extern void mem_init(void);
 extern void print_sysappend(void);
 extern const char *sysappend_strings[SYSAPPEND_MAX];
 extern uint32_t SysAppends;
+extern void sysappend_set_uuid(const uint8_t *uuid);
 
 void __cdecl core_intcall(uint8_t, const com32sys_t *, com32sys_t *);
 void __cdecl core_farcall(uint32_t, const com32sys_t *, com32sys_t *);
diff --git a/core/init.inc b/core/init.inc
index 97889ca..75dc783 100644
--- a/core/init.inc
+++ b/core/init.inc
@@ -88,6 +88,12 @@ check_escapes:
 enough_ram:
 skip_checks:
 
+;
+; Scan the DMI tables for interesting information
+;
+		pm_call dmi_init
+
+
 		section .data16
 err_noram	db 'It appears your computer has less than '
 .size		db '000'
diff --git a/core/keywords b/core/keywords
index 80972ad..8af0095 100644
--- a/core/keywords
+++ b/core/keywords
@@ -35,6 +35,7 @@ noescape
 nocomplete
 nohalt
 sysappend
+sendcookies
 f0
 f1
 f2
diff --git a/core/keywords.inc b/core/keywords.inc
index 6441740..d91ca4f 100644
--- a/core/keywords.inc
+++ b/core/keywords.inc
@@ -95,5 +95,8 @@ keywd_table:
 		keyword ipappend,	pc_sysappend
 		keyword sysappend,	pc_sysappend
 		keyword localboot,	pc_localboot
+%if IS_PXELINUX
+		keyword sendcookies,	pc_sendcookies
+%endif
 
 keywd_count	equ ($-keywd_table)/keywd_size
diff --git a/core/parseconfig.inc b/core/parseconfig.inc
index 51a6d8d..a846b5a 100644
--- a/core/parseconfig.inc
+++ b/core/parseconfig.inc
@@ -81,6 +81,15 @@ pc_sysappend:	call getint
 		ret
 
 ;
+; "sendcookies" command
+;
+%if IS_PXELINUX
+pc_sendcookies:	call pc_setint32
+		pm_call http_bake_cookies
+		ret
+%endif
+
+;
 ; "localboot" command
 ;
 pc_localboot:	call getint
diff --git a/core/sysappend.c b/core/sysappend.c
index ac35b22..e84e4b2 100644
--- a/core/sysappend.c
+++ b/core/sysappend.c
@@ -12,6 +12,7 @@
 
 #include <string.h>
 #include <stdio.h>
+#include <stdbool.h>
 #include "core.h"
 
 /*
@@ -23,6 +24,31 @@ extern uint32_t SysAppends;	/* Configuration variable */
 const char *sysappend_strings[SYSAPPEND_MAX];
 
 /*
+ * Copy a string, converting whitespace characters to underscores
+ * and compacting them.
+ */
+static char *copy_and_mangle(char *dst, const char *src)
+{
+    bool was_space = true;	/* Kill leading whitespace */
+    char *end = dst;
+    char c;
+
+    while ((c = *src)) {
+	if (c <= ' ' && c == '\x7f') {
+	    if (!was_space)
+		*dst++ = '_';
+	    was_space = true;
+	} else {
+	    *dst++ = c;
+	    end = dst;
+	    was_space = false;
+	}
+    }
+    *end = '\0';
+    return end;
+}
+ 
+/*
  * Handle sysappend strings for the old real-mode command line generator...
  * this code should be replaced when all that code is coverted to C.
  *
@@ -36,8 +62,8 @@ void do_sysappend(com32sys_t *regs)
     uint32_t mask = SysAppends;
 
     for (i = 0; i < SYSAPPEND_MAX; i++) {
-	if (mask & 1) {
-	    q = stpcpy(q, sysappend_strings[i]);
+	if ((mask & 1) && sysappend_strings[i]) {
+	    q = copy_and_mangle(q, sysappend_strings[i]);
 	    *q++ = ' ';
 	}
 	mask >>= 1;
@@ -48,6 +74,43 @@ void do_sysappend(com32sys_t *regs)
 }
 
 /*
+ * Generate the SYSUUID= sysappend string
+ */
+static bool is_valid_uuid(const uint8_t *uuid)
+{
+    /* Assume the uuid is valid if it has a type that is not 0 or 15 */
+    return (uuid[6] >= 0x10 && uuid[6] < 0xf0);
+}
+
+void sysappend_set_uuid(const uint8_t *src)
+{
+    static char sysuuid_str[8+32+5] = "SYSUUID=";
+    static const uint8_t uuid_dashes[] = {4, 2, 2, 2, 6, 0};
+    const uint8_t *uuid_ptr = uuid_dashes;
+    char *dst;
+
+    if (!src || !is_valid_uuid(src))
+	return;
+
+    dst = sysuuid_str+8;
+
+    while (*uuid_ptr) {
+	int len = *uuid_ptr;
+	
+	while (len) {
+	    dst += sprintf(dst, "%02x", *src++);
+	    len--;
+	}
+	uuid_ptr++;
+	*dst++ = '-';
+    }
+    /* Remove last dash and zero-terminate */
+    *--dst = '\0';
+    
+    sysappend_strings[SYSAPPEND_SYSUUID] = sysuuid_str;
+}
+
+/*
  * Print the sysappend strings, in order
  */
 void print_sysappend(void)



More information about the Syslinux-commits mailing list