From ca67b09c015d4af3ae3cce12aa72e60941dbb8b5 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 18:29:52 +0200 Subject: Adding debian version 2.06-13+deb12u1. Signed-off-by: Daniel Baumann --- debian/grub-extras/disabled/gpxe/src/core/base64.c | 68 + .../grub-extras/disabled/gpxe/src/core/basename.c | 64 + debian/grub-extras/disabled/gpxe/src/core/bitmap.c | 101 ++ debian/grub-extras/disabled/gpxe/src/core/cwuri.c | 46 + .../grub-extras/disabled/gpxe/src/core/interface.c | 63 + debian/grub-extras/disabled/gpxe/src/core/iobuf.c | 96 ++ debian/grub-extras/disabled/gpxe/src/core/job.c | 97 ++ .../grub-extras/disabled/gpxe/src/core/linebuf.c | 111 ++ debian/grub-extras/disabled/gpxe/src/core/misc.c | 80 ++ debian/grub-extras/disabled/gpxe/src/core/nvo.c | 263 ++++ debian/grub-extras/disabled/gpxe/src/core/open.c | 197 +++ .../grub-extras/disabled/gpxe/src/core/process.c | 106 ++ debian/grub-extras/disabled/gpxe/src/core/random.c | 41 + debian/grub-extras/disabled/gpxe/src/core/refcnt.c | 78 ++ debian/grub-extras/disabled/gpxe/src/core/resolv.c | 415 ++++++ .../grub-extras/disabled/gpxe/src/core/settings.c | 1447 ++++++++++++++++++++ debian/grub-extras/disabled/gpxe/src/core/uri.c | 463 +++++++ debian/grub-extras/disabled/gpxe/src/core/uuid.c | 51 + debian/grub-extras/disabled/gpxe/src/core/xfer.c | 417 ++++++ 19 files changed, 4204 insertions(+) create mode 100644 debian/grub-extras/disabled/gpxe/src/core/base64.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/basename.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/bitmap.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/cwuri.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/interface.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/iobuf.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/job.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/linebuf.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/misc.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/nvo.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/open.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/process.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/random.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/refcnt.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/resolv.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/settings.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/uri.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/uuid.c create mode 100644 debian/grub-extras/disabled/gpxe/src/core/xfer.c (limited to 'debian/grub-extras/disabled/gpxe/src/core') diff --git a/debian/grub-extras/disabled/gpxe/src/core/base64.c b/debian/grub-extras/disabled/gpxe/src/core/base64.c new file mode 100644 index 0000000..5619ef7 --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/base64.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009 Michael Brown . + * + * 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 +#include +#include +#include + +/** @file + * + * Base64 encoding + * + */ + +static const char base64[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/** + * Base64-encode a string + * + * @v raw Raw string + * @v encoded Buffer for encoded string + * + * The buffer must be the correct length for the encoded string. Use + * something like + * + * char buf[ base64_encoded_len ( strlen ( raw ) ) + 1 ]; + * + * (the +1 is for the terminating NUL) to provide a buffer of the + * correct size. + */ +void base64_encode ( const char *raw, char *encoded ) { + const uint8_t *raw_bytes = ( ( const uint8_t * ) raw ); + uint8_t *encoded_bytes = ( ( uint8_t * ) encoded ); + size_t raw_bit_len = ( 8 * strlen ( raw ) ); + unsigned int bit; + unsigned int tmp; + + for ( bit = 0 ; bit < raw_bit_len ; bit += 6 ) { + tmp = ( ( raw_bytes[ bit / 8 ] << ( bit % 8 ) ) | + ( raw_bytes[ bit / 8 + 1 ] >> ( 8 - ( bit % 8 ) ) ) ); + tmp = ( ( tmp >> 2 ) & 0x3f ); + *(encoded_bytes++) = base64[tmp]; + } + for ( ; ( bit % 8 ) != 0 ; bit += 6 ) + *(encoded_bytes++) = '='; + *(encoded_bytes++) = '\0'; + + DBG ( "Base64-encoded \"%s\" as \"%s\"\n", raw, encoded ); + assert ( strlen ( encoded ) == base64_encoded_len ( strlen ( raw ) ) ); +} diff --git a/debian/grub-extras/disabled/gpxe/src/core/basename.c b/debian/grub-extras/disabled/gpxe/src/core/basename.c new file mode 100644 index 0000000..a481c54 --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/basename.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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 ); + +/** + * @file + * + * Get base name of path + * + */ + +#include +#include + +/** + * Return base name from path + * + * @v path Full path + * @ret basename Base name + */ +char * basename ( char *path ) { + char *basename; + + basename = strrchr ( path, '/' ); + return ( basename ? ( basename + 1 ) : path ); +} + +/** + * Return directory name from path + * + * @v path Full path + * @ret dirname Directory name + * + * Note that this function may modify its argument. + */ +char * dirname ( char *path ) { + char *separator; + + separator = strrchr ( path, '/' ); + if ( separator == path ) { + return "/"; + } else if ( separator ) { + *separator = 0; + return path; + } else { + return "."; + } +} diff --git a/debian/grub-extras/disabled/gpxe/src/core/bitmap.c b/debian/grub-extras/disabled/gpxe/src/core/bitmap.c new file mode 100644 index 0000000..bbe9cba --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/bitmap.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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 +#include + +/** @file + * + * Bitmaps for multicast downloads + * + */ + +/** + * Resize bitmap + * + * @v bitmap Bitmap + * @v new_length New length of bitmap, in bits + * @ret rc Return status code + */ +int bitmap_resize ( struct bitmap *bitmap, unsigned int new_length ) { + unsigned int old_num_blocks; + unsigned int new_num_blocks; + size_t new_size; + bitmap_block_t *new_blocks; + + old_num_blocks = BITMAP_INDEX ( bitmap->length + BITMAP_BLKSIZE - 1 ); + new_num_blocks = BITMAP_INDEX ( new_length + BITMAP_BLKSIZE - 1 ); + + if ( old_num_blocks != new_num_blocks ) { + new_size = ( new_num_blocks * sizeof ( bitmap->blocks[0] ) ); + new_blocks = realloc ( bitmap->blocks, new_size ); + if ( ! new_blocks ) { + DBGC ( bitmap, "Bitmap %p could not resize to %d " + "bits\n", bitmap, new_length ); + return -ENOMEM; + } + bitmap->blocks = new_blocks; + } + bitmap->length = new_length; + + while ( old_num_blocks < new_num_blocks ) { + bitmap->blocks[old_num_blocks++] = 0; + } + + DBGC ( bitmap, "Bitmap %p resized to %d bits\n", bitmap, new_length ); + return 0; +} + +/** + * Test bit in bitmap + * + * @v bitmap Bitmap + * @v bit Bit index + * @ret is_set Bit is set + */ +int bitmap_test ( struct bitmap *bitmap, unsigned int bit ) { + unsigned int index = BITMAP_INDEX ( bit ); + bitmap_block_t mask = BITMAP_MASK ( bit ); + + if ( bit >= bitmap->length ) + return 0; + return ( bitmap->blocks[index] & mask ); +} + +/** + * Set bit in bitmap + * + * @v bitmap Bitmap + * @v bit Bit index + */ +void bitmap_set ( struct bitmap *bitmap, unsigned int bit ) { + unsigned int index = BITMAP_INDEX ( bit ); + bitmap_block_t mask = BITMAP_MASK ( bit ); + + DBGC ( bitmap, "Bitmap %p setting bit %d\n", bitmap, bit ); + + /* Update bitmap */ + bitmap->blocks[index] |= mask; + + /* Update first gap counter */ + while ( bitmap_test ( bitmap, bitmap->first_gap ) ) { + bitmap->first_gap++; + } +} diff --git a/debian/grub-extras/disabled/gpxe/src/core/cwuri.c b/debian/grub-extras/disabled/gpxe/src/core/cwuri.c new file mode 100644 index 0000000..65e01b2 --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/cwuri.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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 +#include + +/** @file + * + * Current working URI + * + * Somewhat analogous to the current working directory in a POSIX + * system. + */ + +/** Current working URI */ +struct uri *cwuri = NULL; + +/** + * Change working URI + * + * @v uri New working URI, or NULL + */ +void churi ( struct uri *uri ) { + struct uri *new_uri; + + new_uri = resolve_uri ( cwuri, uri ); + uri_put ( cwuri ); + cwuri = new_uri; +} diff --git a/debian/grub-extras/disabled/gpxe/src/core/interface.c b/debian/grub-extras/disabled/gpxe/src/core/interface.c new file mode 100644 index 0000000..6451bfe --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/interface.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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 +#include + +/** @file + * + * Object communication interfaces + * + */ + +/** + * Plug an interface into a new destination interface + * + * @v intf Interface + * @v dest New destination interface + * + * The reference to the existing destination interface is dropped, a + * reference to the new destination interface is obtained, and the + * interface is updated to point to the new destination interface. + * + * Note that there is no "unplug" call; instead you must plug the + * interface into a null interface. + */ +void plug ( struct interface *intf, struct interface *dest ) { + DBGC ( intf, "INTF %p moving from INTF %p to INTF %p\n", + intf, intf->dest, dest ); + intf_put ( intf->dest ); + intf->dest = intf_get ( dest ); +} + +/** + * Plug two interfaces together + * + * @v a Interface A + * @v b Interface B + * + * Plugs interface A into interface B, and interface B into interface + * A. (The basic plug() function is unidirectional; this function is + * merely a shorthand for two calls to plug(), hence the name.) + */ +void plug_plug ( struct interface *a, struct interface *b ) { + plug ( a, b ); + plug ( b, a ); +} diff --git a/debian/grub-extras/disabled/gpxe/src/core/iobuf.c b/debian/grub-extras/disabled/gpxe/src/core/iobuf.c new file mode 100644 index 0000000..1ce7890 --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/iobuf.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2006 Michael Brown . + * + * 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 +#include +#include +#include + +/** @file + * + * I/O buffers + * + */ + +/** + * Allocate I/O buffer + * + * @v len Required length of buffer + * @ret iobuf I/O buffer, or NULL if none available + * + * The I/O buffer will be physically aligned to a multiple of + * @c IOBUF_SIZE. + */ +struct io_buffer * alloc_iob ( size_t len ) { + struct io_buffer *iobuf = NULL; + void *data; + + /* Pad to minimum length */ + if ( len < IOB_ZLEN ) + len = IOB_ZLEN; + + /* Align buffer length */ + len = ( len + __alignof__( *iobuf ) - 1 ) & + ~( __alignof__( *iobuf ) - 1 ); + + /* Allocate memory for buffer plus descriptor */ + data = malloc_dma ( len + sizeof ( *iobuf ), IOB_ALIGN ); + if ( ! data ) + return NULL; + + iobuf = ( struct io_buffer * ) ( data + len ); + iobuf->head = iobuf->data = iobuf->tail = data; + iobuf->end = iobuf; + return iobuf; +} + +/** + * Free I/O buffer + * + * @v iobuf I/O buffer + */ +void free_iob ( struct io_buffer *iobuf ) { + if ( iobuf ) { + assert ( iobuf->head <= iobuf->data ); + assert ( iobuf->data <= iobuf->tail ); + assert ( iobuf->tail <= iobuf->end ); + free_dma ( iobuf->head, + ( iobuf->end - iobuf->head ) + sizeof ( *iobuf ) ); + } +} + +/** + * Ensure I/O buffer has sufficient headroom + * + * @v iobuf I/O buffer + * @v len Required headroom + * + * This function currently only checks for the required headroom; it + * does not reallocate the I/O buffer if required. If we ever have a + * code path that requires this functionality, it's a fairly trivial + * change to make. + */ +int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len ) { + + if ( iob_headroom ( iobuf ) >= len ) + return 0; + return -ENOBUFS; +} + diff --git a/debian/grub-extras/disabled/gpxe/src/core/job.c b/debian/grub-extras/disabled/gpxe/src/core/job.c new file mode 100644 index 0000000..438064e --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/job.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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 +#include +#include + +/** @file + * + * Job control interfaces + * + */ + +void job_done ( struct job_interface *job, int rc ) { + struct job_interface *dest = job_get_dest ( job ); + + job_unplug ( job ); + dest->op->done ( dest, rc ); + job_put ( dest ); +} + +void job_kill ( struct job_interface *job ) { + struct job_interface *dest = job_get_dest ( job ); + + job_unplug ( job ); + dest->op->kill ( dest ); + job_put ( dest ); +} + +void job_progress ( struct job_interface *job, + struct job_progress *progress ) { + struct job_interface *dest = job_get_dest ( job ); + + dest->op->progress ( dest, progress ); + job_put ( dest ); +} + +/**************************************************************************** + * + * Helper methods + * + * These functions are designed to be used as methods in the + * job_interface_operations table. + * + */ + +void ignore_job_done ( struct job_interface *job __unused, int rc __unused ) { + /* Nothing to do */ +} + +void ignore_job_kill ( struct job_interface *job __unused ) { + /* Nothing to do */ +} + +void ignore_job_progress ( struct job_interface *job __unused, + struct job_progress *progress ) { + memset ( progress, 0, sizeof ( *progress ) ); +} + +/** Null job control interface operations */ +struct job_interface_operations null_job_ops = { + .done = ignore_job_done, + .kill = ignore_job_kill, + .progress = ignore_job_progress, +}; + +/** + * Null job control interface + * + * This is the interface to which job control interfaces are connected + * when unplugged. It will never generate messages, and will silently + * absorb all received messages. + */ +struct job_interface null_job = { + .intf = { + .dest = &null_job.intf, + .refcnt = NULL, + }, + .op = &null_job_ops, +}; diff --git a/debian/grub-extras/disabled/gpxe/src/core/linebuf.c b/debian/grub-extras/disabled/gpxe/src/core/linebuf.c new file mode 100644 index 0000000..221f4e1 --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/linebuf.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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 ); + +/** + * @file + * + * Line buffering + * + */ + +#include +#include +#include +#include +#include + +/** + * Retrieve buffered-up line + * + * @v linebuf Line buffer + * @ret line Buffered line, or NULL if no line ready to read + */ +char * buffered_line ( struct line_buffer *linebuf ) { + return ( linebuf->ready ? linebuf->data : NULL ); +} + +/** + * Discard line buffer contents + * + * @v linebuf Line buffer + */ +void empty_line_buffer ( struct line_buffer *linebuf ) { + free ( linebuf->data ); + linebuf->data = NULL; + linebuf->len = 0; + linebuf->ready = 0; +} + +/** + * Buffer up received data by lines + * + * @v linebuf Line buffer + * @v data New data to add + * @v len Length of new data to add + * @ret len Consumed length, or negative error number + * + * After calling line_buffer(), use buffered_line() to determine + * whether or not a complete line is available. Carriage returns and + * newlines will have been stripped, and the line will be + * NUL-terminated. This buffered line is valid only until the next + * call to line_buffer() (or to empty_line_buffer()). + * + * Note that line buffers use dynamically allocated storage; you + * should call empty_line_buffer() before freeing a @c struct @c + * line_buffer. + */ +ssize_t line_buffer ( struct line_buffer *linebuf, + const char *data, size_t len ) { + const char *eol; + size_t consume; + size_t new_len; + char *new_data; + + /* Free any completed line from previous iteration */ + if ( linebuf->ready ) + empty_line_buffer ( linebuf ); + + /* Search for line terminator */ + if ( ( eol = memchr ( data, '\n', len ) ) ) { + consume = ( eol - data + 1 ); + } else { + consume = len; + } + + /* Reallocate data buffer and copy in new data */ + new_len = ( linebuf->len + consume ); + new_data = realloc ( linebuf->data, ( new_len + 1 ) ); + if ( ! new_data ) + return -ENOMEM; + memcpy ( ( new_data + linebuf->len ), data, consume ); + new_data[new_len] = '\0'; + linebuf->data = new_data; + linebuf->len = new_len; + + /* If we have reached end of line, trim the line and mark as ready */ + if ( eol ) { + linebuf->data[--linebuf->len] = '\0'; /* trim NL */ + if ( linebuf->data[linebuf->len - 1] == '\r' ) + linebuf->data[--linebuf->len] = '\0'; /* trim CR */ + linebuf->ready = 1; + } + + return consume; +} diff --git a/debian/grub-extras/disabled/gpxe/src/core/misc.c b/debian/grub-extras/disabled/gpxe/src/core/misc.c new file mode 100644 index 0000000..c19591b --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/misc.c @@ -0,0 +1,80 @@ +/************************************************************************** +MISC Support Routines +**************************************************************************/ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include + +/************************************************************************** +INET_ATON - Convert an ascii x.x.x.x to binary form +**************************************************************************/ +int inet_aton ( const char *cp, struct in_addr *inp ) { + const char *p = cp; + const char *digits_start; + unsigned long ip = 0; + unsigned long val; + int j; + for(j = 0; j <= 3; j++) { + digits_start = p; + val = strtoul(p, ( char ** ) &p, 10); + if ((p == digits_start) || (val > 255)) return 0; + if ( ( j < 3 ) && ( *(p++) != '.' ) ) return 0; + ip = (ip << 8) | val; + } + if ( *p == '\0' ) { + inp->s_addr = htonl(ip); + return 1; + } + return 0; +} + +unsigned long strtoul ( const char *p, char **endp, int base ) { + unsigned long ret = 0; + unsigned int charval; + + while ( isspace ( *p ) ) + p++; + + if ( base == 0 ) { + base = 10; + if ( *p == '0' ) { + p++; + base = 8; + if ( ( *p | 0x20 ) == 'x' ) { + p++; + base = 16; + } + } + } + + while ( 1 ) { + charval = *p; + if ( charval >= 'a' ) { + charval = ( charval - 'a' + 10 ); + } else if ( charval >= 'A' ) { + charval = ( charval - 'A' + 10 ); + } else if ( charval <= '9' ) { + charval = ( charval - '0' ); + } + if ( charval >= ( unsigned int ) base ) + break; + ret = ( ( ret * base ) + charval ); + p++; + } + + if ( endp ) + *endp = ( char * ) p; + + return ( ret ); +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/debian/grub-extras/disabled/gpxe/src/core/nvo.c b/debian/grub-extras/disabled/gpxe/src/core/nvo.c new file mode 100644 index 0000000..3dbf51d --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/nvo.c @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2006 Michael Brown . + * + * 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 +#include +#include +#include +#include +#include +#include + +/** @file + * + * Non-volatile stored options + * + */ + +/** + * Calculate checksum over non-volatile stored options + * + * @v nvo Non-volatile options block + * @ret sum Checksum + */ +static unsigned int nvo_checksum ( struct nvo_block *nvo ) { + uint8_t *data = nvo->data; + uint8_t sum = 0; + unsigned int i; + + for ( i = 0 ; i < nvo->total_len ; i++ ) { + sum += *(data++); + } + return sum; +} + +/** + * Load non-volatile stored options from non-volatile storage device + * + * @v nvo Non-volatile options block + * @ret rc Return status code + */ +static int nvo_load ( struct nvo_block *nvo ) { + void *data = nvo->data; + struct nvo_fragment *frag; + int rc; + + /* Read data a fragment at a time */ + for ( frag = nvo->fragments ; frag->len ; frag++ ) { + if ( ( rc = nvs_read ( nvo->nvs, frag->address, data, + frag->len ) ) != 0 ) { + DBGC ( nvo, "NVO %p could not read %zd bytes at " + "%#04x\n", nvo, frag->len, frag->address ); + return rc; + } + data += frag->len; + } + + DBGC ( nvo, "NVO %p loaded from non-volatile storage\n", nvo ); + return 0; +} + +/** + * Save non-volatile stored options back to non-volatile storage device + * + * @v nvo Non-volatile options block + * @ret rc Return status code + */ +static int nvo_save ( struct nvo_block *nvo ) { + void *data = nvo->data; + uint8_t *checksum = data; + struct nvo_fragment *frag; + int rc; + + /* Recalculate checksum */ + *checksum -= nvo_checksum ( nvo ); + + /* Write data a fragment at a time */ + for ( frag = nvo->fragments ; frag->len ; frag++ ) { + if ( ( rc = nvs_write ( nvo->nvs, frag->address, data, + frag->len ) ) != 0 ) { + DBGC ( nvo, "NVO %p could not write %zd bytes at " + "%#04x\n", nvo, frag->len, frag->address ); + return rc; + } + data += frag->len; + } + + DBGC ( nvo, "NVO %p saved to non-volatile storage\n", nvo ); + return 0; +} + +/** + * Parse stored options + * + * @v nvo Non-volatile options block + * + * Verifies that the options data is valid, and configures the DHCP + * options block. If the data is not valid, it is replaced with an + * empty options block. + */ +static void nvo_init_dhcpopts ( struct nvo_block *nvo ) { + uint8_t *options_data; + size_t options_len; + + /* Steal one byte for the checksum */ + options_data = ( nvo->data + 1 ); + options_len = ( nvo->total_len - 1 ); + + /* If checksum fails, or options data starts with a zero, + * assume the whole block is invalid. This should capture the + * case of random initial contents. + */ + if ( ( nvo_checksum ( nvo ) != 0 ) || ( options_data[0] == 0 ) ) { + DBGC ( nvo, "NVO %p has checksum %02x and initial byte %02x; " + "assuming empty\n", nvo, nvo_checksum ( nvo ), + options_data[0] ); + memset ( nvo->data, 0, nvo->total_len ); + } + + dhcpopt_init ( &nvo->dhcpopts, options_data, options_len ); +} + +/** + * Store value of NVO setting + * + * @v settings Settings block + * @v setting Setting to store + * @v data Setting data, or NULL to clear setting + * @v len Length of setting data + * @ret rc Return status code + */ +static int nvo_store ( struct settings *settings, struct setting *setting, + const void *data, size_t len ) { + struct nvo_block *nvo = + container_of ( settings, struct nvo_block, settings ); + int rc; + + /* Update stored options */ + if ( ( rc = dhcpopt_store ( &nvo->dhcpopts, setting->tag, + data, len ) ) != 0 ) { + DBGC ( nvo, "NVO %p could not store %zd bytes: %s\n", + nvo, len, strerror ( rc ) ); + return rc; + } + + /* Save updated options to NVS */ + if ( ( rc = nvo_save ( nvo ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Fetch value of NVO setting + * + * @v settings Settings block + * @v setting Setting to fetch + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + * + * The actual length of the setting will be returned even if + * the buffer was too small. + */ +static int nvo_fetch ( struct settings *settings, struct setting *setting, + void *data, size_t len ) { + struct nvo_block *nvo = + container_of ( settings, struct nvo_block, settings ); + + return dhcpopt_fetch ( &nvo->dhcpopts, setting->tag, data, len ); +} + +/** NVO settings operations */ +static struct settings_operations nvo_settings_operations = { + .store = nvo_store, + .fetch = nvo_fetch, +}; + +/** + * Initialise non-volatile stored options + * + * @v nvo Non-volatile options block + * @v nvs Underlying non-volatile storage device + * @v fragments List of option-containing fragments + * @v refcnt Containing object reference counter, or NULL + */ +void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs, + struct nvo_fragment *fragments, struct refcnt *refcnt ) { + nvo->nvs = nvs; + nvo->fragments = fragments; + settings_init ( &nvo->settings, &nvo_settings_operations, refcnt, + "nvo", 0 ); +} + +/** + * Register non-volatile stored options + * + * @v nvo Non-volatile options block + * @v parent Parent settings block, or NULL + * @ret rc Return status code + */ +int register_nvo ( struct nvo_block *nvo, struct settings *parent ) { + struct nvo_fragment *fragment = nvo->fragments; + int rc; + + /* Calculate total length of all fragments */ + for ( fragment = nvo->fragments ; fragment->len ; fragment++ ) + nvo->total_len += fragment->len; + + /* Allocate memory for options and read in from NVS */ + nvo->data = malloc ( nvo->total_len ); + if ( ! nvo->data ) { + DBGC ( nvo, "NVO %p could not allocate %zd bytes\n", + nvo, nvo->total_len ); + rc = -ENOMEM; + goto err_malloc; + } + if ( ( rc = nvo_load ( nvo ) ) != 0 ) + goto err_load; + + /* Verify and register options */ + nvo_init_dhcpopts ( nvo ); + if ( ( rc = register_settings ( &nvo->settings, parent ) ) != 0 ) + goto err_register; + + DBGC ( nvo, "NVO %p registered\n", nvo ); + return 0; + + err_register: + err_load: + free ( nvo->data ); + nvo->data = NULL; + err_malloc: + return rc; +} + +/** + * Unregister non-volatile stored options + * + * @v nvo Non-volatile options block + */ +void unregister_nvo ( struct nvo_block *nvo ) { + unregister_settings ( &nvo->settings ); + free ( nvo->data ); + nvo->data = NULL; + DBGC ( nvo, "NVO %p unregistered\n", nvo ); +} diff --git a/debian/grub-extras/disabled/gpxe/src/core/open.c b/debian/grub-extras/disabled/gpxe/src/core/open.c new file mode 100644 index 0000000..70b427b --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/open.c @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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 +#include +#include +#include +#include +#include +#include + +/** @file + * + * Data transfer interface opening + * + */ + +/** + * Open URI + * + * @v xfer Data transfer interface + * @v uri URI + * @ret rc Return status code + * + * The URI will be regarded as being relative to the current working + * URI (see churi()). + */ +int xfer_open_uri ( struct xfer_interface *xfer, struct uri *uri ) { + struct uri_opener *opener; + struct uri *resolved_uri; + int rc = -ENOTSUP; + + /* Resolve URI */ + resolved_uri = resolve_uri ( cwuri, uri ); + if ( ! resolved_uri ) + return -ENOMEM; + + /* Find opener which supports this URI scheme */ + for_each_table_entry ( opener, URI_OPENERS ) { + if ( strcmp ( resolved_uri->scheme, opener->scheme ) == 0 ) { + DBGC ( xfer, "XFER %p opening %s URI\n", + xfer, opener->scheme ); + rc = opener->open ( xfer, resolved_uri ); + goto done; + } + } + DBGC ( xfer, "XFER %p attempted to open unsupported URI scheme " + "\"%s\"\n", xfer, resolved_uri->scheme ); + + done: + uri_put ( resolved_uri ); + return rc; +} + +/** + * Open URI string + * + * @v xfer Data transfer interface + * @v uri_string URI string (e.g. "http://etherboot.org/kernel") + * @ret rc Return status code + * + * The URI will be regarded as being relative to the current working + * URI (see churi()). + */ +int xfer_open_uri_string ( struct xfer_interface *xfer, + const char *uri_string ) { + struct uri *uri; + int rc; + + DBGC ( xfer, "XFER %p opening URI %s\n", xfer, uri_string ); + + uri = parse_uri ( uri_string ); + if ( ! uri ) + return -ENOMEM; + + rc = xfer_open_uri ( xfer, uri ); + + uri_put ( uri ); + return rc; +} + +/** + * Open socket + * + * @v xfer Data transfer interface + * @v semantics Communication semantics (e.g. SOCK_STREAM) + * @v peer Peer socket address + * @v local Local socket address, or NULL + * @ret rc Return status code + */ +int xfer_open_socket ( struct xfer_interface *xfer, int semantics, + struct sockaddr *peer, struct sockaddr *local ) { + struct socket_opener *opener; + + DBGC ( xfer, "XFER %p opening (%s,%s) socket\n", xfer, + socket_semantics_name ( semantics ), + socket_family_name ( peer->sa_family ) ); + + for_each_table_entry ( opener, SOCKET_OPENERS ) { + if ( ( opener->semantics == semantics ) && + ( opener->family == peer->sa_family ) ) { + return opener->open ( xfer, peer, local ); + } + } + + DBGC ( xfer, "XFER %p attempted to open unsupported socket type " + "(%s,%s)\n", xfer, socket_semantics_name ( semantics ), + socket_family_name ( peer->sa_family ) ); + return -ENOTSUP; +} + +/** + * Open location + * + * @v xfer Data transfer interface + * @v type Location type + * @v args Remaining arguments depend upon location type + * @ret rc Return status code + */ +int xfer_vopen ( struct xfer_interface *xfer, int type, va_list args ) { + switch ( type ) { + case LOCATION_URI_STRING: { + const char *uri_string = va_arg ( args, const char * ); + + return xfer_open_uri_string ( xfer, uri_string ); } + case LOCATION_URI: { + struct uri *uri = va_arg ( args, struct uri * ); + + return xfer_open_uri ( xfer, uri ); } + case LOCATION_SOCKET: { + int semantics = va_arg ( args, int ); + struct sockaddr *peer = va_arg ( args, struct sockaddr * ); + struct sockaddr *local = va_arg ( args, struct sockaddr * ); + + return xfer_open_socket ( xfer, semantics, peer, local ); } + default: + DBGC ( xfer, "XFER %p attempted to open unsupported location " + "type %d\n", xfer, type ); + return -ENOTSUP; + } +} + +/** + * Open location + * + * @v xfer Data transfer interface + * @v type Location type + * @v ... Remaining arguments depend upon location type + * @ret rc Return status code + */ +int xfer_open ( struct xfer_interface *xfer, int type, ... ) { + va_list args; + int rc; + + va_start ( args, type ); + rc = xfer_vopen ( xfer, type, args ); + va_end ( args ); + return rc; +} + +/** + * Reopen location + * + * @v xfer Data transfer interface + * @v type Location type + * @v args Remaining arguments depend upon location type + * @ret rc Return status code + * + * This will close the existing connection and open a new connection + * using xfer_vopen(). It is intended to be used as a .vredirect + * method handler. + */ +int xfer_vreopen ( struct xfer_interface *xfer, int type, va_list args ) { + + /* Close existing connection */ + xfer_close ( xfer, 0 ); + + /* Open new location */ + return xfer_vopen ( xfer, type, args ); +} diff --git a/debian/grub-extras/disabled/gpxe/src/core/process.c b/debian/grub-extras/disabled/gpxe/src/core/process.c new file mode 100644 index 0000000..9c13e02 --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/process.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2006 Michael Brown . + * + * 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 +#include +#include + +/** @file + * + * Processes + * + * We implement a trivial form of cooperative multitasking, in which + * all processes share a single stack and address space. + */ + +/** Process run queue */ +static LIST_HEAD ( run_queue ); + +/** + * Add process to process list + * + * @v process Process + * + * It is safe to call process_add() multiple times; further calls will + * have no effect. + */ +void process_add ( struct process *process ) { + if ( list_empty ( &process->list ) ) { + DBGC ( process, "PROCESS %p starting\n", process ); + ref_get ( process->refcnt ); + list_add_tail ( &process->list, &run_queue ); + } else { + DBGC ( process, "PROCESS %p already started\n", process ); + } +} + +/** + * Remove process from process list + * + * @v process Process + * + * It is safe to call process_del() multiple times; further calls will + * have no effect. + */ +void process_del ( struct process *process ) { + if ( ! list_empty ( &process->list ) ) { + DBGC ( process, "PROCESS %p stopping\n", process ); + list_del ( &process->list ); + INIT_LIST_HEAD ( &process->list ); + ref_put ( process->refcnt ); + } else { + DBGC ( process, "PROCESS %p already stopped\n", process ); + } +} + +/** + * Single-step a single process + * + * This executes a single step of the first process in the run queue, + * and moves the process to the end of the run queue. + */ +void step ( void ) { + struct process *process; + + list_for_each_entry ( process, &run_queue, list ) { + list_del ( &process->list ); + list_add_tail ( &process->list, &run_queue ); + DBGC2 ( process, "PROCESS %p executing\n", process ); + process->step ( process ); + DBGC2 ( process, "PROCESS %p finished executing\n", process ); + break; + } +} + +/** + * Initialise processes + * + */ +static void init_processes ( void ) { + struct process *process; + + for_each_table_entry ( process, PERMANENT_PROCESSES ) + process_add ( process ); +} + +/** Process initialiser */ +struct init_fn process_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = init_processes, +}; diff --git a/debian/grub-extras/disabled/gpxe/src/core/random.c b/debian/grub-extras/disabled/gpxe/src/core/random.c new file mode 100644 index 0000000..6e7374e --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/random.c @@ -0,0 +1,41 @@ +/** @file + * + * Random number generation + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +static int32_t rnd_seed = 0; + +/** + * Seed the pseudo-random number generator + * + * @v seed Seed value + */ +void srandom ( unsigned int seed ) { + rnd_seed = seed; +} + +/** + * Generate a pseudo-random number between 0 and 2147483647L or 2147483562? + * + * @ret rand Pseudo-random number + */ +long int random ( void ) { + int32_t q; + + if ( ! rnd_seed ) /* Initialize linear congruential generator */ + srandom ( currticks() ); + + /* simplified version of the LCG given in Bruce Schneier's + "Applied Cryptography" */ + q = ( rnd_seed / 53668 ); + rnd_seed = ( 40014 * ( rnd_seed - 53668 * q ) - 12211 * q ); + if ( rnd_seed < 0 ) + rnd_seed += 2147483563L; + return rnd_seed; +} diff --git a/debian/grub-extras/disabled/gpxe/src/core/refcnt.c b/debian/grub-extras/disabled/gpxe/src/core/refcnt.c new file mode 100644 index 0000000..f2286ca --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/refcnt.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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 +#include + +/** @file + * + * Reference counting + * + */ + +/** + * Increment reference count + * + * @v refcnt Reference counter, or NULL + * @ret refcnt Reference counter + * + * If @c refcnt is NULL, no action is taken. + */ +struct refcnt * ref_get ( struct refcnt *refcnt ) { + + if ( refcnt ) { + refcnt->refcnt++; + DBGC2 ( refcnt, "REFCNT %p incremented to %d\n", + refcnt, refcnt->refcnt ); + } + return refcnt; +} + +/** + * Decrement reference count + * + * @v refcnt Reference counter, or NULL + * + * If the reference count decreases below zero, the object's free() + * method will be called. + * + * If @c refcnt is NULL, no action is taken. + */ +void ref_put ( struct refcnt *refcnt ) { + + if ( ! refcnt ) + return; + + refcnt->refcnt--; + DBGC2 ( refcnt, "REFCNT %p decremented to %d\n", + refcnt, refcnt->refcnt ); + + if ( refcnt->refcnt >= 0 ) + return; + + if ( refcnt->free ) { + DBGC ( refcnt, "REFCNT %p being freed via method %p\n", + refcnt, refcnt->free ); + refcnt->free ( refcnt ); + } else { + DBGC ( refcnt, "REFCNT %p being freed\n", refcnt ); + free ( refcnt ); + } +} diff --git a/debian/grub-extras/disabled/gpxe/src/core/resolv.c b/debian/grub-extras/disabled/gpxe/src/core/resolv.c new file mode 100644 index 0000000..6f01f93 --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/resolv.c @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Name resolution + * + */ + +/*************************************************************************** + * + * Name resolution interfaces + * + *************************************************************************** + */ + +/** + * Name resolution completed + * + * @v resolv Name resolution interface + * @v sa Completed socket address (if successful) + * @v rc Final status code + */ +void resolv_done ( struct resolv_interface *resolv, struct sockaddr *sa, + int rc ) { + struct resolv_interface *dest = resolv_get_dest ( resolv ); + + resolv_unplug ( resolv ); + dest->op->done ( dest, sa, rc ); + resolv_put ( dest ); +} + +/** + * Ignore name resolution done() event + * + * @v resolv Name resolution interface + * @v sa Completed socket address (if successful) + * @v rc Final status code + */ +void ignore_resolv_done ( struct resolv_interface *resolv __unused, + struct sockaddr *sa __unused, int rc __unused ) { + /* Do nothing */ +} + +/** Null name resolution interface operations */ +struct resolv_interface_operations null_resolv_ops = { + .done = ignore_resolv_done, +}; + +/** Null name resolution interface */ +struct resolv_interface null_resolv = { + .intf = { + .dest = &null_resolv.intf, + .refcnt = NULL, + }, + .op = &null_resolv_ops, +}; + +/*************************************************************************** + * + * Numeric name resolver + * + *************************************************************************** + */ + +/** A numeric name resolver */ +struct numeric_resolv { + /** Reference counter */ + struct refcnt refcnt; + /** Name resolution interface */ + struct resolv_interface resolv; + /** Process */ + struct process process; + /** Completed socket address */ + struct sockaddr sa; + /** Overall status code */ + int rc; +}; + +static void numeric_step ( struct process *process ) { + struct numeric_resolv *numeric = + container_of ( process, struct numeric_resolv, process ); + + resolv_done ( &numeric->resolv, &numeric->sa, numeric->rc ); + process_del ( process ); +} + +static int numeric_resolv ( struct resolv_interface *resolv, + const char *name, struct sockaddr *sa ) { + struct numeric_resolv *numeric; + struct sockaddr_in *sin; + + /* Allocate and initialise structure */ + numeric = zalloc ( sizeof ( *numeric ) ); + if ( ! numeric ) + return -ENOMEM; + resolv_init ( &numeric->resolv, &null_resolv_ops, &numeric->refcnt ); + process_init ( &numeric->process, numeric_step, &numeric->refcnt ); + memcpy ( &numeric->sa, sa, sizeof ( numeric->sa ) ); + + DBGC ( numeric, "NUMERIC %p attempting to resolve \"%s\"\n", + numeric, name ); + + /* Attempt to resolve name */ + sin = ( ( struct sockaddr_in * ) &numeric->sa ); + sin->sin_family = AF_INET; + if ( inet_aton ( name, &sin->sin_addr ) == 0 ) + numeric->rc = -EINVAL; + + /* Attach to parent interface, mortalise self, and return */ + resolv_plug_plug ( &numeric->resolv, resolv ); + ref_put ( &numeric->refcnt ); + return 0; +} + +struct resolver numeric_resolver __resolver ( RESOLV_NUMERIC ) = { + .name = "NUMERIC", + .resolv = numeric_resolv, +}; + +/*************************************************************************** + * + * Name resolution multiplexer + * + *************************************************************************** + */ + +/** A name resolution multiplexer */ +struct resolv_mux { + /** Reference counter */ + struct refcnt refcnt; + /** Parent name resolution interface */ + struct resolv_interface parent; + + /** Child name resolution interface */ + struct resolv_interface child; + /** Current child resolver */ + struct resolver *resolver; + + /** Socket address to complete */ + struct sockaddr sa; + /** Name to be resolved + * + * Must be at end of structure + */ + char name[0]; +}; + +/** + * Try current child name resolver + * + * @v mux Name resolution multiplexer + * @ret rc Return status code + */ +static int resolv_mux_try ( struct resolv_mux *mux ) { + struct resolver *resolver = mux->resolver; + int rc; + + DBGC ( mux, "RESOLV %p trying method %s\n", mux, resolver->name ); + + if ( ( rc = resolver->resolv ( &mux->child, mux->name, + &mux->sa ) ) != 0 ) { + DBGC ( mux, "RESOLV %p could not use method %s: %s\n", + mux, resolver->name, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Handle done() event from child name resolver + * + * @v resolv Child name resolution interface + * @v sa Completed socket address (if successful) + * @v rc Final status code + */ +static void resolv_mux_done ( struct resolv_interface *resolv, + struct sockaddr *sa, int rc ) { + struct resolv_mux *mux = + container_of ( resolv, struct resolv_mux, child ); + + /* Unplug child */ + resolv_unplug ( &mux->child ); + + /* If this resolution succeeded, stop now */ + if ( rc == 0 ) { + DBGC ( mux, "RESOLV %p succeeded using method %s\n", + mux, mux->resolver->name ); + goto finished; + } + + /* Attempt next child resolver, if possible */ + mux->resolver++; + if ( mux->resolver >= table_end ( RESOLVERS ) ) { + DBGC ( mux, "RESOLV %p failed to resolve name\n", mux ); + goto finished; + } + if ( ( rc = resolv_mux_try ( mux ) ) != 0 ) + goto finished; + + /* Next resolver is now running */ + return; + + finished: + resolv_done ( &mux->parent, sa, rc ); +} + +/** Name resolution multiplexer operations */ +static struct resolv_interface_operations resolv_mux_child_ops = { + .done = resolv_mux_done, +}; + +/** + * Start name resolution + * + * @v resolv Name resolution interface + * @v name Name to resolve + * @v sa Socket address to complete + * @ret rc Return status code + */ +int resolv ( struct resolv_interface *resolv, const char *name, + struct sockaddr *sa ) { + struct resolv_mux *mux; + size_t name_len = ( strlen ( name ) + 1 ); + int rc; + + /* Allocate and initialise structure */ + mux = zalloc ( sizeof ( *mux ) + name_len ); + if ( ! mux ) + return -ENOMEM; + resolv_init ( &mux->parent, &null_resolv_ops, &mux->refcnt ); + resolv_init ( &mux->child, &resolv_mux_child_ops, &mux->refcnt ); + mux->resolver = table_start ( RESOLVERS ); + memcpy ( &mux->sa, sa, sizeof ( mux->sa ) ); + memcpy ( mux->name, name, name_len ); + + DBGC ( mux, "RESOLV %p attempting to resolve \"%s\"\n", mux, name ); + + /* Start first resolver in chain. There will always be at + * least one resolver (the numeric resolver), so no need to + * check for the zero-resolvers-available case. + */ + if ( ( rc = resolv_mux_try ( mux ) ) != 0 ) + goto err; + + /* Attach parent interface, mortalise self, and return */ + resolv_plug_plug ( &mux->parent, resolv ); + ref_put ( &mux->refcnt ); + return 0; + + err: + ref_put ( &mux->refcnt ); + return rc; +} + +/*************************************************************************** + * + * Named socket opening + * + *************************************************************************** + */ + +/** A named socket */ +struct named_socket { + /** Reference counter */ + struct refcnt refcnt; + /** Data transfer interface */ + struct xfer_interface xfer; + /** Name resolution interface */ + struct resolv_interface resolv; + /** Communication semantics (e.g. SOCK_STREAM) */ + int semantics; + /** Stored local socket address, if applicable */ + struct sockaddr local; + /** Stored local socket address exists */ + int have_local; +}; + +/** + * Finish using named socket + * + * @v named Named socket + * @v rc Reason for finish + */ +static void named_done ( struct named_socket *named, int rc ) { + + /* Close all interfaces */ + resolv_nullify ( &named->resolv ); + xfer_nullify ( &named->xfer ); + xfer_close ( &named->xfer, rc ); +} + +/** + * Handle close() event + * + * @v xfer Data transfer interface + * @v rc Reason for close + */ +static void named_xfer_close ( struct xfer_interface *xfer, int rc ) { + struct named_socket *named = + container_of ( xfer, struct named_socket, xfer ); + + named_done ( named, rc ); +} + +/** Named socket opener data transfer interface operations */ +static struct xfer_interface_operations named_xfer_ops = { + .close = named_xfer_close, + .vredirect = ignore_xfer_vredirect, + .window = no_xfer_window, + .alloc_iob = default_xfer_alloc_iob, + .deliver_iob = xfer_deliver_as_raw, + .deliver_raw = ignore_xfer_deliver_raw, +}; + +/** + * Handle done() event + * + * @v resolv Name resolution interface + * @v sa Completed socket address (if successful) + * @v rc Final status code + */ +static void named_resolv_done ( struct resolv_interface *resolv, + struct sockaddr *sa, int rc ) { + struct named_socket *named = + container_of ( resolv, struct named_socket, resolv ); + + /* Redirect if name resolution was successful */ + if ( rc == 0 ) { + rc = xfer_redirect ( &named->xfer, LOCATION_SOCKET, + named->semantics, sa, + ( named->have_local ? + &named->local : NULL ) ); + } + + /* Terminate resolution */ + named_done ( named, rc ); +} + +/** Named socket opener name resolution interface operations */ +static struct resolv_interface_operations named_resolv_ops = { + .done = named_resolv_done, +}; + +/** + * Open named socket + * + * @v semantics Communication semantics (e.g. SOCK_STREAM) + * @v peer Peer socket address to complete + * @v name Name to resolve + * @v local Local socket address, or NULL + * @ret rc Return status code + */ +int xfer_open_named_socket ( struct xfer_interface *xfer, int semantics, + struct sockaddr *peer, const char *name, + struct sockaddr *local ) { + struct named_socket *named; + int rc; + + /* Allocate and initialise structure */ + named = zalloc ( sizeof ( *named ) ); + if ( ! named ) + return -ENOMEM; + xfer_init ( &named->xfer, &named_xfer_ops, &named->refcnt ); + resolv_init ( &named->resolv, &named_resolv_ops, &named->refcnt ); + named->semantics = semantics; + if ( local ) { + memcpy ( &named->local, local, sizeof ( named->local ) ); + named->have_local = 1; + } + + DBGC ( named, "RESOLV %p opening named socket \"%s\"\n", + named, name ); + + /* Start name resolution */ + if ( ( rc = resolv ( &named->resolv, name, peer ) ) != 0 ) + goto err; + + /* Attach parent interface, mortalise self, and return */ + xfer_plug_plug ( &named->xfer, xfer ); + ref_put ( &named->refcnt ); + return 0; + + err: + ref_put ( &named->refcnt ); + return rc; +} diff --git a/debian/grub-extras/disabled/gpxe/src/core/settings.c b/debian/grub-extras/disabled/gpxe/src/core/settings.c new file mode 100644 index 0000000..87d84a0 --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/settings.c @@ -0,0 +1,1447 @@ +/* + * Copyright (C) 2008 Michael Brown . + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Configuration settings + * + */ + +/****************************************************************************** + * + * Generic settings blocks + * + ****************************************************************************** + */ + +/** + * A generic setting + * + */ +struct generic_setting { + /** List of generic settings */ + struct list_head list; + /** Setting */ + struct setting setting; + /** Size of setting name */ + size_t name_len; + /** Size of setting data */ + size_t data_len; +}; + +/** + * Get generic setting name + * + * @v generic Generic setting + * @ret name Generic setting name + */ +static inline void * generic_setting_name ( struct generic_setting *generic ) { + return ( ( ( void * ) generic ) + sizeof ( *generic ) ); +} + +/** + * Get generic setting data + * + * @v generic Generic setting + * @ret data Generic setting data + */ +static inline void * generic_setting_data ( struct generic_setting *generic ) { + return ( ( ( void * ) generic ) + sizeof ( *generic ) + + generic->name_len ); +} + +/** + * Find generic setting + * + * @v generics Generic settings block + * @v setting Setting to find + * @ret generic Generic setting, or NULL + */ +static struct generic_setting * +find_generic_setting ( struct generic_settings *generics, + struct setting *setting ) { + struct generic_setting *generic; + + list_for_each_entry ( generic, &generics->list, list ) { + if ( setting_cmp ( &generic->setting, setting ) == 0 ) + return generic; + } + return NULL; +} + +/** + * Store value of generic setting + * + * @v settings Settings block + * @v setting Setting to store + * @v data Setting data, or NULL to clear setting + * @v len Length of setting data + * @ret rc Return status code + */ +int generic_settings_store ( struct settings *settings, + struct setting *setting, + const void *data, size_t len ) { + struct generic_settings *generics = + container_of ( settings, struct generic_settings, settings ); + struct generic_setting *old; + struct generic_setting *new = NULL; + size_t name_len; + + /* Identify existing generic setting, if any */ + old = find_generic_setting ( generics, setting ); + + /* Create new generic setting, if required */ + if ( len ) { + /* Allocate new generic setting */ + name_len = ( strlen ( setting->name ) + 1 ); + new = zalloc ( sizeof ( *new ) + name_len + len ); + if ( ! new ) + return -ENOMEM; + + /* Populate new generic setting */ + new->name_len = name_len; + new->data_len = len; + memcpy ( &new->setting, setting, sizeof ( new->setting ) ); + new->setting.name = generic_setting_name ( new ); + memcpy ( generic_setting_name ( new ), + setting->name, name_len ); + memcpy ( generic_setting_data ( new ), data, len ); + } + + /* Delete existing generic setting, if any */ + if ( old ) { + list_del ( &old->list ); + free ( old ); + } + + /* Add new setting to list, if any */ + if ( new ) + list_add ( &new->list, &generics->list ); + + return 0; +} + +/** + * Fetch value of generic setting + * + * @v settings Settings block + * @v setting Setting to fetch + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +int generic_settings_fetch ( struct settings *settings, + struct setting *setting, + void *data, size_t len ) { + struct generic_settings *generics = + container_of ( settings, struct generic_settings, settings ); + struct generic_setting *generic; + + /* Find generic setting */ + generic = find_generic_setting ( generics, setting ); + if ( ! generic ) + return -ENOENT; + + /* Copy out generic setting data */ + if ( len > generic->data_len ) + len = generic->data_len; + memcpy ( data, generic_setting_data ( generic ), len ); + return generic->data_len; +} + +/** + * Clear generic settings block + * + * @v settings Settings block + */ +void generic_settings_clear ( struct settings *settings ) { + struct generic_settings *generics = + container_of ( settings, struct generic_settings, settings ); + struct generic_setting *generic; + struct generic_setting *tmp; + + list_for_each_entry_safe ( generic, tmp, &generics->list, list ) { + list_del ( &generic->list ); + free ( generic ); + } + assert ( list_empty ( &generics->list ) ); +} + +/** Generic settings operations */ +struct settings_operations generic_settings_operations = { + .store = generic_settings_store, + .fetch = generic_settings_fetch, + .clear = generic_settings_clear, +}; + +/****************************************************************************** + * + * Registered settings blocks + * + ****************************************************************************** + */ + +/** Root generic settings block */ +struct generic_settings generic_settings_root = { + .settings = { + .refcnt = NULL, + .name = "", + .siblings = + LIST_HEAD_INIT ( generic_settings_root.settings.siblings ), + .children = + LIST_HEAD_INIT ( generic_settings_root.settings.children ), + .op = &generic_settings_operations, + }, + .list = LIST_HEAD_INIT ( generic_settings_root.list ), +}; + +/** Root settings block */ +#define settings_root generic_settings_root.settings + +/** + * Find child named settings block + * + * @v parent Parent settings block + * @v name Name within this parent + * @ret settings Settings block, or NULL + */ +static struct settings * find_child_settings ( struct settings *parent, + const char *name ) { + struct settings *settings; + + /* Treat empty name as meaning "this block" */ + if ( ! *name ) + return parent; + + /* Look for child with matching name */ + list_for_each_entry ( settings, &parent->children, siblings ) { + if ( strcmp ( settings->name, name ) == 0 ) + return settings; + } + + return NULL; +} + +/** + * Find or create child named settings block + * + * @v parent Parent settings block + * @v name Name within this parent + * @ret settings Settings block, or NULL + */ +static struct settings * autovivify_child_settings ( struct settings *parent, + const char *name ) { + struct { + struct generic_settings generic; + char name[ strlen ( name ) + 1 /* NUL */ ]; + } *new_child; + struct settings *settings; + + /* Return existing settings, if existent */ + if ( ( settings = find_child_settings ( parent, name ) ) != NULL ) + return settings; + + /* Create new generic settings block */ + new_child = zalloc ( sizeof ( *new_child ) ); + if ( ! new_child ) { + DBGC ( parent, "Settings %p could not create child %s\n", + parent, name ); + return NULL; + } + memcpy ( new_child->name, name, sizeof ( new_child->name ) ); + generic_settings_init ( &new_child->generic, NULL, new_child->name ); + settings = &new_child->generic.settings; + register_settings ( settings, parent ); + return settings; +} + +/** + * Return settings block name (for debug only) + * + * @v settings Settings block + * @ret name Settings block name + */ +static const char * settings_name ( struct settings *settings ) { + static char buf[64]; + char tmp[ sizeof ( buf ) ]; + int count; + + for ( count = 0 ; settings ; settings = settings->parent ) { + memcpy ( tmp, buf, sizeof ( tmp ) ); + snprintf ( buf, sizeof ( buf ), "%s%c%s", settings->name, + ( count++ ? '.' : '\0' ), tmp ); + } + return ( buf + 1 ); +} + +/** + * Parse settings block name + * + * @v name Name + * @v get_child Function to find or create child settings block + * @ret settings Settings block, or NULL + */ +static struct settings * +parse_settings_name ( const char *name, + struct settings * ( * get_child ) ( struct settings *, + const char * ) ) { + struct settings *settings = &settings_root; + char name_copy[ strlen ( name ) + 1 ]; + char *subname; + char *remainder; + + /* Create modifiable copy of name */ + memcpy ( name_copy, name, sizeof ( name_copy ) ); + remainder = name_copy; + + /* Parse each name component in turn */ + while ( remainder ) { + subname = remainder; + remainder = strchr ( subname, '.' ); + if ( remainder ) + *(remainder++) = '\0'; + settings = get_child ( settings, subname ); + if ( ! settings ) + break; + } + + return settings; +} + +/** + * Find named settings block + * + * @v name Name + * @ret settings Settings block, or NULL + */ +struct settings * find_settings ( const char *name ) { + + return parse_settings_name ( name, find_child_settings ); +} + +/** + * Apply all settings + * + * @ret rc Return status code + */ +static int apply_settings ( void ) { + struct settings_applicator *applicator; + int rc; + + /* Call all settings applicators */ + for_each_table_entry ( applicator, SETTINGS_APPLICATORS ) { + if ( ( rc = applicator->apply() ) != 0 ) { + DBG ( "Could not apply settings using applicator " + "%p: %s\n", applicator, strerror ( rc ) ); + return rc; + } + } + + return 0; +} + +/** + * Reprioritise settings + * + * @v settings Settings block + * + * Reorders the settings block amongst its siblings according to its + * priority. + */ +static void reprioritise_settings ( struct settings *settings ) { + struct settings *parent = settings->parent; + long priority; + struct settings *tmp; + long tmp_priority; + + /* Stop when we reach the top of the tree */ + if ( ! parent ) + return; + + /* Read priority, if present */ + priority = fetch_intz_setting ( settings, &priority_setting ); + + /* Remove from siblings list */ + list_del ( &settings->siblings ); + + /* Reinsert after any existing blocks which have a higher priority */ + list_for_each_entry ( tmp, &parent->children, siblings ) { + tmp_priority = fetch_intz_setting ( tmp, &priority_setting ); + if ( priority > tmp_priority ) + break; + } + list_add_tail ( &settings->siblings, &tmp->siblings ); + + /* Recurse up the tree */ + reprioritise_settings ( parent ); +} + +/** + * Register settings block + * + * @v settings Settings block + * @v parent Parent settings block, or NULL + * @ret rc Return status code + */ +int register_settings ( struct settings *settings, struct settings *parent ) { + struct settings *old_settings; + + /* NULL parent => add to settings root */ + assert ( settings != NULL ); + if ( parent == NULL ) + parent = &settings_root; + + /* Remove any existing settings with the same name */ + if ( ( old_settings = find_child_settings ( parent, settings->name ) )) + unregister_settings ( old_settings ); + + /* Add to list of settings */ + ref_get ( settings->refcnt ); + ref_get ( parent->refcnt ); + settings->parent = parent; + list_add_tail ( &settings->siblings, &parent->children ); + DBGC ( settings, "Settings %p (\"%s\") registered\n", + settings, settings_name ( settings ) ); + + /* Fix up settings priority */ + reprioritise_settings ( settings ); + + /* Apply potentially-updated settings */ + apply_settings(); + + return 0; +} + +/** + * Unregister settings block + * + * @v settings Settings block + */ +void unregister_settings ( struct settings *settings ) { + + DBGC ( settings, "Settings %p (\"%s\") unregistered\n", + settings, settings_name ( settings ) ); + + /* Remove from list of settings */ + ref_put ( settings->refcnt ); + ref_put ( settings->parent->refcnt ); + settings->parent = NULL; + list_del ( &settings->siblings ); + + /* Apply potentially-updated settings */ + apply_settings(); +} + +/****************************************************************************** + * + * Core settings routines + * + ****************************************************************************** + */ + +/** + * Store value of setting + * + * @v settings Settings block, or NULL + * @v setting Setting to store + * @v data Setting data, or NULL to clear setting + * @v len Length of setting data + * @ret rc Return status code + */ +int store_setting ( struct settings *settings, struct setting *setting, + const void *data, size_t len ) { + int rc; + + /* NULL settings implies storing into the global settings root */ + if ( ! settings ) + settings = &settings_root; + + /* Sanity check */ + if ( ! settings->op->store ) + return -ENOTSUP; + + /* Store setting */ + if ( ( rc = settings->op->store ( settings, setting, + data, len ) ) != 0 ) + return rc; + + /* Reprioritise settings if necessary */ + if ( setting_cmp ( setting, &priority_setting ) == 0 ) + reprioritise_settings ( settings ); + + /* If these settings are registered, apply potentially-updated + * settings + */ + for ( ; settings ; settings = settings->parent ) { + if ( settings == &settings_root ) { + if ( ( rc = apply_settings() ) != 0 ) + return rc; + break; + } + } + + return 0; +} + +/** + * Fetch value of setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + * + * The actual length of the setting will be returned even if + * the buffer was too small. + */ +int fetch_setting ( struct settings *settings, struct setting *setting, + void *data, size_t len ) { + struct settings *child; + int ret; + + /* Avoid returning uninitialised data on error */ + memset ( data, 0, len ); + + /* NULL settings implies starting at the global settings root */ + if ( ! settings ) + settings = &settings_root; + + /* Sanity check */ + if ( ! settings->op->fetch ) + return -ENOTSUP; + + /* Try this block first */ + if ( ( ret = settings->op->fetch ( settings, setting, + data, len ) ) >= 0 ) + return ret; + + /* Recurse into each child block in turn */ + list_for_each_entry ( child, &settings->children, siblings ) { + if ( ( ret = fetch_setting ( child, setting, + data, len ) ) >= 0 ) + return ret; + } + + return -ENOENT; +} + +/** + * Fetch length of setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @ret len Length of setting data, or negative error + * + * This function can also be used as an existence check for the + * setting. + */ +int fetch_setting_len ( struct settings *settings, struct setting *setting ) { + return fetch_setting ( settings, setting, NULL, 0 ); +} + +/** + * Fetch value of string setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v data Buffer to fill with setting string data + * @v len Length of buffer + * @ret len Length of string setting, or negative error + * + * The resulting string is guaranteed to be correctly NUL-terminated. + * The returned length will be the length of the underlying setting + * data. + */ +int fetch_string_setting ( struct settings *settings, struct setting *setting, + char *data, size_t len ) { + memset ( data, 0, len ); + return fetch_setting ( settings, setting, data, + ( ( len > 0 ) ? ( len - 1 ) : 0 ) ); +} + +/** + * Fetch value of string setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v data Buffer to allocate and fill with setting string data + * @ret len Length of string setting, or negative error + * + * The resulting string is guaranteed to be correctly NUL-terminated. + * The returned length will be the length of the underlying setting + * data. The caller is responsible for eventually freeing the + * allocated buffer. + */ +int fetch_string_setting_copy ( struct settings *settings, + struct setting *setting, + char **data ) { + int len; + int check_len = 0; + + len = fetch_setting_len ( settings, setting ); + if ( len < 0 ) + return len; + + *data = malloc ( len + 1 ); + if ( ! *data ) + return -ENOMEM; + + check_len = fetch_string_setting ( settings, setting, *data, + ( len + 1 ) ); + assert ( check_len == len ); + return len; +} + +/** + * Fetch value of IPv4 address setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v inp IPv4 address to fill in + * @ret len Length of setting, or negative error + */ +int fetch_ipv4_setting ( struct settings *settings, struct setting *setting, + struct in_addr *inp ) { + int len; + + len = fetch_setting ( settings, setting, inp, sizeof ( *inp ) ); + if ( len < 0 ) + return len; + if ( len < ( int ) sizeof ( *inp ) ) + return -ERANGE; + return len; +} + +/** + * Fetch value of signed integer setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v value Integer value to fill in + * @ret len Length of setting, or negative error + */ +int fetch_int_setting ( struct settings *settings, struct setting *setting, + long *value ) { + union { + uint8_t u8[ sizeof ( long ) ]; + int8_t s8[ sizeof ( long ) ]; + } buf; + int len; + int i; + + /* Avoid returning uninitialised data on error */ + *value = 0; + + /* Fetch raw (network-ordered, variable-length) setting */ + len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) ); + if ( len < 0 ) + return len; + if ( len > ( int ) sizeof ( buf ) ) + return -ERANGE; + + /* Convert to host-ordered signed long */ + *value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L ); + for ( i = 0 ; i < len ; i++ ) { + *value = ( ( *value << 8 ) | buf.u8[i] ); + } + + return len; +} + +/** + * Fetch value of unsigned integer setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v value Integer value to fill in + * @ret len Length of setting, or negative error + */ +int fetch_uint_setting ( struct settings *settings, struct setting *setting, + unsigned long *value ) { + long svalue; + int len; + + /* Avoid returning uninitialised data on error */ + *value = 0; + + /* Fetch as a signed long */ + len = fetch_int_setting ( settings, setting, &svalue ); + if ( len < 0 ) + return len; + + /* Mask off sign-extended bits */ + assert ( len <= ( int ) sizeof ( long ) ); + *value = ( svalue & ( -1UL >> ( 8 * ( sizeof ( long ) - len ) ) ) ); + + return len; +} + +/** + * Fetch value of signed integer setting, or zero + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @ret value Setting value, or zero + */ +long fetch_intz_setting ( struct settings *settings, struct setting *setting ){ + long value; + + fetch_int_setting ( settings, setting, &value ); + return value; +} + +/** + * Fetch value of unsigned integer setting, or zero + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @ret value Setting value, or zero + */ +unsigned long fetch_uintz_setting ( struct settings *settings, + struct setting *setting ) { + unsigned long value; + + fetch_uint_setting ( settings, setting, &value ); + return value; +} + +/** + * Fetch value of UUID setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v uuid UUID to fill in + * @ret len Length of setting, or negative error + */ +int fetch_uuid_setting ( struct settings *settings, struct setting *setting, + union uuid *uuid ) { + int len; + + len = fetch_setting ( settings, setting, uuid, sizeof ( *uuid ) ); + if ( len < 0 ) + return len; + if ( len != sizeof ( *uuid ) ) + return -ERANGE; + return len; +} + +/** + * Clear settings block + * + * @v settings Settings block + */ +void clear_settings ( struct settings *settings ) { + if ( settings->op->clear ) + settings->op->clear ( settings ); +} + +/** + * Compare two settings + * + * @v a Setting to compare + * @v b Setting to compare + * @ret 0 Settings are the same + * @ret non-zero Settings are not the same + */ +int setting_cmp ( struct setting *a, struct setting *b ) { + + /* If the settings have tags, compare them */ + if ( a->tag && ( a->tag == b->tag ) ) + return 0; + + /* Otherwise, if the settings have names, compare them */ + if ( a->name && b->name && a->name[0] ) + return strcmp ( a->name, b->name ); + + /* Otherwise, return a non-match */ + return ( ! 0 ); +} + +/****************************************************************************** + * + * Formatted setting routines + * + ****************************************************************************** + */ + +/** + * Store value of typed setting + * + * @v settings Settings block + * @v setting Setting to store + * @v type Settings type + * @v value Formatted setting data, or NULL + * @ret rc Return status code + */ +int storef_setting ( struct settings *settings, struct setting *setting, + const char *value ) { + + /* NULL value implies deletion. Avoid imposing the burden of + * checking for NULL values on each typed setting's storef() + * method. + */ + if ( ! value ) + return delete_setting ( settings, setting ); + + return setting->type->storef ( settings, setting, value ); +} + +/** + * Find named setting + * + * @v name Name + * @ret setting Named setting, or NULL + */ +static struct setting * find_setting ( const char *name ) { + struct setting *setting; + + for_each_table_entry ( setting, SETTINGS ) { + if ( strcmp ( name, setting->name ) == 0 ) + return setting; + } + return NULL; +} + +/** + * Parse setting name as tag number + * + * @v name Name + * @ret tag Tag number, or 0 if not a valid number + */ +static unsigned int parse_setting_tag ( const char *name ) { + char *tmp = ( ( char * ) name ); + unsigned int tag = 0; + + while ( 1 ) { + tag = ( ( tag << 8 ) | strtoul ( tmp, &tmp, 0 ) ); + if ( *tmp == 0 ) + return tag; + if ( *tmp != '.' ) + return 0; + tmp++; + } +} + +/** + * Find setting type + * + * @v name Name + * @ret type Setting type, or NULL + */ +static struct setting_type * find_setting_type ( const char *name ) { + struct setting_type *type; + + for_each_table_entry ( type, SETTING_TYPES ) { + if ( strcmp ( name, type->name ) == 0 ) + return type; + } + return NULL; +} + +/** + * Parse setting name + * + * @v name Name of setting + * @v get_child Function to find or create child settings block + * @v settings Settings block to fill in + * @v setting Setting to fill in + * @v tmp_name Buffer for copy of setting name + * @ret rc Return status code + * + * Interprets a name of the form + * "[settings_name/]tag_name[:type_name]" and fills in the appropriate + * fields. + * + * The @c tmp_name buffer must be large enough to hold a copy of the + * setting name. + */ +static int +parse_setting_name ( const char *name, + struct settings * ( * get_child ) ( struct settings *, + const char * ), + struct settings **settings, struct setting *setting, + char *tmp_name ) { + char *settings_name; + char *setting_name; + char *type_name; + struct setting *named_setting; + + /* Set defaults */ + *settings = &settings_root; + memset ( setting, 0, sizeof ( *setting ) ); + setting->name = ""; + setting->type = &setting_type_string; + + /* Split name into "[settings_name/]setting_name[:type_name]" */ + strcpy ( tmp_name, name ); + if ( ( setting_name = strchr ( tmp_name, '/' ) ) != NULL ) { + *(setting_name++) = 0; + settings_name = tmp_name; + } else { + setting_name = tmp_name; + settings_name = NULL; + } + if ( ( type_name = strchr ( setting_name, ':' ) ) != NULL ) + *(type_name++) = 0; + + /* Identify settings block, if specified */ + if ( settings_name ) { + *settings = parse_settings_name ( settings_name, get_child ); + if ( *settings == NULL ) { + DBG ( "Unrecognised settings block \"%s\" in \"%s\"\n", + settings_name, name ); + return -ENODEV; + } + } + + /* Identify setting */ + if ( ( named_setting = find_setting ( setting_name ) ) != NULL ) { + /* Matches a defined named setting; use that setting */ + memcpy ( setting, named_setting, sizeof ( *setting ) ); + } else if ( ( setting->tag = parse_setting_tag ( setting_name ) ) !=0){ + /* Is a valid numeric tag; use the tag */ + setting->tag |= (*settings)->tag_magic; + } else { + /* Use the arbitrary name */ + setting->name = setting_name; + } + + /* Identify setting type, if specified */ + if ( type_name ) { + setting->type = find_setting_type ( type_name ); + if ( setting->type == NULL ) { + DBG ( "Invalid setting type \"%s\" in \"%s\"\n", + type_name, name ); + return -ENOTSUP; + } + } + + return 0; +} + +/** + * Parse and store value of named setting + * + * @v name Name of setting + * @v value Formatted setting data, or NULL + * @ret rc Return status code + */ +int storef_named_setting ( const char *name, const char *value ) { + struct settings *settings; + struct setting setting; + char tmp_name[ strlen ( name ) + 1 ]; + int rc; + + if ( ( rc = parse_setting_name ( name, autovivify_child_settings, + &settings, &setting, tmp_name )) != 0) + return rc; + return storef_setting ( settings, &setting, value ); +} + +/** + * Fetch and format value of named setting + * + * @v name Name of setting + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +int fetchf_named_setting ( const char *name, char *buf, size_t len ) { + struct settings *settings; + struct setting setting; + char tmp_name[ strlen ( name ) + 1 ]; + int rc; + + if ( ( rc = parse_setting_name ( name, find_child_settings, + &settings, &setting, tmp_name )) != 0) + return rc; + return fetchf_setting ( settings, &setting, buf, len ); +} + +/****************************************************************************** + * + * Setting types + * + ****************************************************************************** + */ + +/** + * Parse and store value of string setting + * + * @v settings Settings block + * @v setting Setting to store + * @v value Formatted setting data + * @ret rc Return status code + */ +static int storef_string ( struct settings *settings, struct setting *setting, + const char *value ) { + return store_setting ( settings, setting, value, strlen ( value ) ); +} + +/** + * Fetch and format value of string setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +static int fetchf_string ( struct settings *settings, struct setting *setting, + char *buf, size_t len ) { + return fetch_string_setting ( settings, setting, buf, len ); +} + +/** A string setting type */ +struct setting_type setting_type_string __setting_type = { + .name = "string", + .storef = storef_string, + .fetchf = fetchf_string, +}; + +/** + * Parse and store value of URI-encoded string setting + * + * @v settings Settings block + * @v setting Setting to store + * @v value Formatted setting data + * @ret rc Return status code + */ +static int storef_uristring ( struct settings *settings, + struct setting *setting, + const char *value ) { + char buf[ strlen ( value ) + 1 ]; /* Decoding never expands string */ + size_t len; + + len = uri_decode ( value, buf, sizeof ( buf ) ); + return store_setting ( settings, setting, buf, len ); +} + +/** + * Fetch and format value of URI-encoded string setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +static int fetchf_uristring ( struct settings *settings, + struct setting *setting, + char *buf, size_t len ) { + ssize_t raw_len; + + /* We need to always retrieve the full raw string to know the + * length of the encoded string. + */ + raw_len = fetch_setting ( settings, setting, NULL, 0 ); + if ( raw_len < 0 ) + return raw_len; + + { + char raw_buf[ raw_len + 1 ]; + + fetch_string_setting ( settings, setting, raw_buf, + sizeof ( raw_buf ) ); + return uri_encode ( raw_buf, buf, len ); + } +} + +/** A URI-encoded string setting type */ +struct setting_type setting_type_uristring __setting_type = { + .name = "uristring", + .storef = storef_uristring, + .fetchf = fetchf_uristring, +}; + +/** + * Parse and store value of IPv4 address setting + * + * @v settings Settings block + * @v setting Setting to store + * @v value Formatted setting data + * @ret rc Return status code + */ +static int storef_ipv4 ( struct settings *settings, struct setting *setting, + const char *value ) { + struct in_addr ipv4; + + if ( inet_aton ( value, &ipv4 ) == 0 ) + return -EINVAL; + return store_setting ( settings, setting, &ipv4, sizeof ( ipv4 ) ); +} + +/** + * Fetch and format value of IPv4 address setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +static int fetchf_ipv4 ( struct settings *settings, struct setting *setting, + char *buf, size_t len ) { + struct in_addr ipv4; + int raw_len; + + if ( ( raw_len = fetch_ipv4_setting ( settings, setting, &ipv4 ) ) < 0) + return raw_len; + return snprintf ( buf, len, "%s", inet_ntoa ( ipv4 ) ); +} + +/** An IPv4 address setting type */ +struct setting_type setting_type_ipv4 __setting_type = { + .name = "ipv4", + .storef = storef_ipv4, + .fetchf = fetchf_ipv4, +}; + +/** + * Parse and store value of integer setting + * + * @v settings Settings block + * @v setting Setting to store + * @v value Formatted setting data + * @v size Integer size, in bytes + * @ret rc Return status code + */ +static int storef_int ( struct settings *settings, struct setting *setting, + const char *value, unsigned int size ) { + union { + uint32_t num; + uint8_t bytes[4]; + } u; + char *endp; + + u.num = htonl ( strtoul ( value, &endp, 0 ) ); + if ( *endp ) + return -EINVAL; + return store_setting ( settings, setting, + &u.bytes[ sizeof ( u ) - size ], size ); +} + +/** + * Parse and store value of 8-bit integer setting + * + * @v settings Settings block + * @v setting Setting to store + * @v value Formatted setting data + * @v size Integer size, in bytes + * @ret rc Return status code + */ +static int storef_int8 ( struct settings *settings, struct setting *setting, + const char *value ) { + return storef_int ( settings, setting, value, 1 ); +} + +/** + * Parse and store value of 16-bit integer setting + * + * @v settings Settings block + * @v setting Setting to store + * @v value Formatted setting data + * @v size Integer size, in bytes + * @ret rc Return status code + */ +static int storef_int16 ( struct settings *settings, struct setting *setting, + const char *value ) { + return storef_int ( settings, setting, value, 2 ); +} + +/** + * Parse and store value of 32-bit integer setting + * + * @v settings Settings block + * @v setting Setting to store + * @v value Formatted setting data + * @v size Integer size, in bytes + * @ret rc Return status code + */ +static int storef_int32 ( struct settings *settings, struct setting *setting, + const char *value ) { + return storef_int ( settings, setting, value, 4 ); +} + +/** + * Fetch and format value of signed integer setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +static int fetchf_int ( struct settings *settings, struct setting *setting, + char *buf, size_t len ) { + long value; + int rc; + + if ( ( rc = fetch_int_setting ( settings, setting, &value ) ) < 0 ) + return rc; + return snprintf ( buf, len, "%ld", value ); +} + +/** + * Fetch and format value of unsigned integer setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +static int fetchf_uint ( struct settings *settings, struct setting *setting, + char *buf, size_t len ) { + unsigned long value; + int rc; + + if ( ( rc = fetch_uint_setting ( settings, setting, &value ) ) < 0 ) + return rc; + return snprintf ( buf, len, "%#lx", value ); +} + +/** A signed 8-bit integer setting type */ +struct setting_type setting_type_int8 __setting_type = { + .name = "int8", + .storef = storef_int8, + .fetchf = fetchf_int, +}; + +/** A signed 16-bit integer setting type */ +struct setting_type setting_type_int16 __setting_type = { + .name = "int16", + .storef = storef_int16, + .fetchf = fetchf_int, +}; + +/** A signed 32-bit integer setting type */ +struct setting_type setting_type_int32 __setting_type = { + .name = "int32", + .storef = storef_int32, + .fetchf = fetchf_int, +}; + +/** An unsigned 8-bit integer setting type */ +struct setting_type setting_type_uint8 __setting_type = { + .name = "uint8", + .storef = storef_int8, + .fetchf = fetchf_uint, +}; + +/** An unsigned 16-bit integer setting type */ +struct setting_type setting_type_uint16 __setting_type = { + .name = "uint16", + .storef = storef_int16, + .fetchf = fetchf_uint, +}; + +/** An unsigned 32-bit integer setting type */ +struct setting_type setting_type_uint32 __setting_type = { + .name = "uint32", + .storef = storef_int32, + .fetchf = fetchf_uint, +}; + +/** + * Parse and store value of hex string setting + * + * @v settings Settings block + * @v setting Setting to store + * @v value Formatted setting data + * @ret rc Return status code + */ +static int storef_hex ( struct settings *settings, struct setting *setting, + const char *value ) { + char *ptr = ( char * ) value; + uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */ + unsigned int len = 0; + + while ( 1 ) { + bytes[len++] = strtoul ( ptr, &ptr, 16 ); + switch ( *ptr ) { + case '\0' : + return store_setting ( settings, setting, bytes, len ); + case ':' : + ptr++; + break; + default : + return -EINVAL; + } + } +} + +/** + * Fetch and format value of hex string setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +static int fetchf_hex ( struct settings *settings, struct setting *setting, + char *buf, size_t len ) { + int raw_len; + int check_len; + int used = 0; + int i; + + raw_len = fetch_setting_len ( settings, setting ); + if ( raw_len < 0 ) + return raw_len; + + { + uint8_t raw[raw_len]; + + check_len = fetch_setting ( settings, setting, raw, + sizeof ( raw ) ); + if ( check_len < 0 ) + return check_len; + assert ( check_len == raw_len ); + + if ( len ) + buf[0] = 0; /* Ensure that a terminating NUL exists */ + for ( i = 0 ; i < raw_len ; i++ ) { + used += ssnprintf ( ( buf + used ), ( len - used ), + "%s%02x", ( used ? ":" : "" ), + raw[i] ); + } + return used; + } +} + +/** A hex-string setting */ +struct setting_type setting_type_hex __setting_type = { + .name = "hex", + .storef = storef_hex, + .fetchf = fetchf_hex, +}; + +/** + * Parse and store value of UUID setting + * + * @v settings Settings block + * @v setting Setting to store + * @v value Formatted setting data + * @ret rc Return status code + */ +static int storef_uuid ( struct settings *settings __unused, + struct setting *setting __unused, + const char *value __unused ) { + return -ENOTSUP; +} + +/** + * Fetch and format value of UUID setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +static int fetchf_uuid ( struct settings *settings, struct setting *setting, + char *buf, size_t len ) { + union uuid uuid; + int raw_len; + + if ( ( raw_len = fetch_uuid_setting ( settings, setting, &uuid ) ) < 0) + return raw_len; + return snprintf ( buf, len, "%s", uuid_ntoa ( &uuid ) ); +} + +/** UUID setting type */ +struct setting_type setting_type_uuid __setting_type = { + .name = "uuid", + .storef = storef_uuid, + .fetchf = fetchf_uuid, +}; + +/****************************************************************************** + * + * Settings + * + ****************************************************************************** + */ + +/** Hostname setting */ +struct setting hostname_setting __setting = { + .name = "hostname", + .description = "Host name", + .tag = DHCP_HOST_NAME, + .type = &setting_type_string, +}; + +/** Filename setting */ +struct setting filename_setting __setting = { + .name = "filename", + .description = "Boot filename", + .tag = DHCP_BOOTFILE_NAME, + .type = &setting_type_string, +}; + +/** Root path setting */ +struct setting root_path_setting __setting = { + .name = "root-path", + .description = "NFS/iSCSI root path", + .tag = DHCP_ROOT_PATH, + .type = &setting_type_string, +}; + +/** Username setting */ +struct setting username_setting __setting = { + .name = "username", + .description = "User name", + .tag = DHCP_EB_USERNAME, + .type = &setting_type_string, +}; + +/** Password setting */ +struct setting password_setting __setting = { + .name = "password", + .description = "Password", + .tag = DHCP_EB_PASSWORD, + .type = &setting_type_string, +}; + +/** Priority setting */ +struct setting priority_setting __setting = { + .name = "priority", + .description = "Priority of these settings", + .tag = DHCP_EB_PRIORITY, + .type = &setting_type_int8, +}; diff --git a/debian/grub-extras/disabled/gpxe/src/core/uri.c b/debian/grub-extras/disabled/gpxe/src/core/uri.c new file mode 100644 index 0000000..f87ec1b --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/uri.c @@ -0,0 +1,463 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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 ); + +/** @file + * + * Uniform Resource Identifiers + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/** + * Dump URI for debugging + * + * @v uri URI + */ +static void dump_uri ( struct uri *uri ) { + if ( ! uri ) + return; + if ( uri->scheme ) + DBG ( " scheme \"%s\"", uri->scheme ); + if ( uri->opaque ) + DBG ( " opaque \"%s\"", uri->opaque ); + if ( uri->user ) + DBG ( " user \"%s\"", uri->user ); + if ( uri->password ) + DBG ( " password \"%s\"", uri->password ); + if ( uri->host ) + DBG ( " host \"%s\"", uri->host ); + if ( uri->port ) + DBG ( " port \"%s\"", uri->port ); + if ( uri->path ) + DBG ( " path \"%s\"", uri->path ); + if ( uri->query ) + DBG ( " query \"%s\"", uri->query ); + if ( uri->fragment ) + DBG ( " fragment \"%s\"", uri->fragment ); +} + +/** + * Parse URI + * + * @v uri_string URI as a string + * @ret uri URI + * + * Splits a URI into its component parts. The return URI structure is + * dynamically allocated and must eventually be freed by calling + * uri_put(). + */ +struct uri * parse_uri ( const char *uri_string ) { + struct uri *uri; + char *raw; + char *tmp; + char *path = NULL; + char *authority = NULL; + size_t raw_len; + + /* Allocate space for URI struct and a copy of the string */ + raw_len = ( strlen ( uri_string ) + 1 /* NUL */ ); + uri = zalloc ( sizeof ( *uri ) + raw_len ); + if ( ! uri ) + return NULL; + raw = ( ( ( char * ) uri ) + sizeof ( *uri ) ); + + /* Zero URI struct and copy in the raw string */ + memcpy ( raw, uri_string, raw_len ); + + /* Start by chopping off the fragment, if it exists */ + if ( ( tmp = strchr ( raw, '#' ) ) ) { + *(tmp++) = '\0'; + uri->fragment = tmp; + } + + /* Identify absolute/relative URI. We ignore schemes that are + * apparently only a single character long, since otherwise we + * misinterpret a DOS-style path name ("C:\path\to\file") as a + * URI with scheme="C",opaque="\path\to\file". + */ + if ( ( tmp = strchr ( raw, ':' ) ) && ( tmp > ( raw + 1 ) ) ) { + /* Absolute URI: identify hierarchical/opaque */ + uri->scheme = raw; + *(tmp++) = '\0'; + if ( *tmp == '/' ) { + /* Absolute URI with hierarchical part */ + path = tmp; + } else { + /* Absolute URI with opaque part */ + uri->opaque = tmp; + } + } else { + /* Relative URI */ + path = raw; + } + + /* If we don't have a path (i.e. we have an absolute URI with + * an opaque portion, we're already finished processing + */ + if ( ! path ) + goto done; + + /* Chop off the query, if it exists */ + if ( ( tmp = strchr ( path, '?' ) ) ) { + *(tmp++) = '\0'; + uri->query = tmp; + } + + /* Identify net/absolute/relative path */ + if ( strncmp ( path, "//", 2 ) == 0 ) { + /* Net path. If this is terminated by the first '/' + * of an absolute path, then we have no space for a + * terminator after the authority field, so shuffle + * the authority down by one byte, overwriting one of + * the two slashes. + */ + authority = ( path + 2 ); + if ( ( tmp = strchr ( authority, '/' ) ) ) { + /* Shuffle down */ + uri->path = tmp; + memmove ( ( authority - 1 ), authority, + ( tmp - authority ) ); + authority--; + *(--tmp) = '\0'; + } + } else { + /* Absolute/relative path */ + uri->path = path; + } + + /* Split authority into user[:password] and host[:port] portions */ + if ( ( tmp = strchr ( authority, '@' ) ) ) { + /* Has user[:password] */ + *(tmp++) = '\0'; + uri->host = tmp; + uri->user = authority; + if ( ( tmp = strchr ( authority, ':' ) ) ) { + /* Has password */ + *(tmp++) = '\0'; + uri->password = tmp; + } + } else { + /* No user:password */ + uri->host = authority; + } + + /* Split host into host[:port] */ + if ( ( tmp = strchr ( uri->host, ':' ) ) ) { + *(tmp++) = '\0'; + uri->port = tmp; + } + + done: + DBG ( "URI \"%s\" split into", uri_string ); + dump_uri ( uri ); + DBG ( "\n" ); + + return uri; +} + +/** + * Get port from URI + * + * @v uri URI, or NULL + * @v default_port Default port to use if none specified in URI + * @ret port Port + */ +unsigned int uri_port ( struct uri *uri, unsigned int default_port ) { + if ( ( ! uri ) || ( ! uri->port ) ) + return default_port; + return ( strtoul ( uri->port, NULL, 0 ) ); +} + +/** + * Unparse URI + * + * @v buf Buffer to fill with URI string + * @v size Size of buffer + * @v uri URI to write into buffer, or NULL + * @ret len Length of URI string + */ +int unparse_uri ( char *buf, size_t size, struct uri *uri ) { + int used = 0; + + DBG ( "URI unparsing" ); + dump_uri ( uri ); + DBG ( "\n" ); + + /* Special-case NULL URI */ + if ( ! uri ) { + if ( size ) + buf[0] = '\0'; + return 0; + } + + /* Special-case opaque URIs */ + if ( uri->opaque ) { + return ssnprintf ( ( buf + used ), ( size - used ), + "%s:%s", uri->scheme, uri->opaque ); + } + + /* scheme:// */ + if ( uri->scheme ) { + used += ssnprintf ( ( buf + used ), ( size - used ), + "%s://", uri->scheme ); + } + + /* [user[:password]@]host[:port] */ + if ( uri->host ) { + if ( uri->user ) { + used += ssnprintf ( ( buf + used ), ( size - used ), + "%s", uri->user ); + if ( uri->password ) { + used += ssnprintf ( ( buf + used ), + ( size - used ), + ":%s", uri->password ); + } + used += ssnprintf ( ( buf + used ), ( size - used ), + "@" ); + } + used += ssnprintf ( ( buf + used ), ( size - used ), "%s", + uri->host ); + if ( uri->port ) { + used += ssnprintf ( ( buf + used ), ( size - used ), + ":%s", uri->port ); + } + } + + /* /path */ + if ( uri->path ) { + used += ssnprintf ( ( buf + used ), ( size - used ), + "%s", uri->path ); + } + + /* ?query */ + if ( uri->query ) { + used += ssnprintf ( ( buf + used ), ( size - used ), + "?%s", uri->query ); + } + + /* #fragment */ + if ( uri->fragment ) { + used += ssnprintf ( ( buf + used ), ( size - used ), + "#%s", uri->fragment ); + } + + return used; +} + +/** + * Duplicate URI + * + * @v uri URI + * @ret uri Duplicate URI + * + * Creates a modifiable copy of a URI. + */ +struct uri * uri_dup ( struct uri *uri ) { + size_t len = ( unparse_uri ( NULL, 0, uri ) + 1 ); + char buf[len]; + + unparse_uri ( buf, len, uri ); + return parse_uri ( buf ); +} + +/** + * Resolve base+relative path + * + * @v base_uri Base path + * @v relative_uri Relative path + * @ret resolved_uri Resolved path + * + * Takes a base path (e.g. "/var/lib/tftpboot/vmlinuz" and a relative + * path (e.g. "initrd.gz") and produces a new path + * (e.g. "/var/lib/tftpboot/initrd.gz"). Note that any non-directory + * portion of the base path will automatically be stripped; this + * matches the semantics used when resolving the path component of + * URIs. + */ +char * resolve_path ( const char *base_path, + const char *relative_path ) { + size_t base_len = ( strlen ( base_path ) + 1 ); + char base_path_copy[base_len]; + char *base_tmp = base_path_copy; + + /* If relative path is absolute, just re-use it */ + if ( relative_path[0] == '/' ) + return strdup ( relative_path ); + + /* Create modifiable copy of path for dirname() */ + memcpy ( base_tmp, base_path, base_len ); + base_tmp = dirname ( base_tmp ); + + /* Process "./" and "../" elements */ + while ( *relative_path == '.' ) { + relative_path++; + if ( *relative_path == 0 ) { + /* Do nothing */ + } else if ( *relative_path == '/' ) { + relative_path++; + } else if ( *relative_path == '.' ) { + relative_path++; + if ( *relative_path == 0 ) { + base_tmp = dirname ( base_tmp ); + } else if ( *relative_path == '/' ) { + base_tmp = dirname ( base_tmp ); + relative_path++; + } else { + relative_path -= 2; + break; + } + } else { + relative_path--; + break; + } + } + + /* Create and return new path */ + return grub_xasprintf ( "%s%s%s", base_tmp, + ( ( base_tmp[ strlen ( base_tmp ) - 1 ] == '/' ) ? + "" : "/" ), relative_path ); +} + +/** + * Resolve base+relative URI + * + * @v base_uri Base URI, or NULL + * @v relative_uri Relative URI + * @ret resolved_uri Resolved URI + * + * Takes a base URI (e.g. "http://etherboot.org/kernels/vmlinuz" and a + * relative URI (e.g. "../initrds/initrd.gz") and produces a new URI + * (e.g. "http://etherboot.org/initrds/initrd.gz"). + */ +struct uri * resolve_uri ( struct uri *base_uri, + struct uri *relative_uri ) { + struct uri tmp_uri; + char *tmp_path = NULL; + struct uri *new_uri; + + /* If relative URI is absolute, just re-use it */ + if ( uri_is_absolute ( relative_uri ) || ( ! base_uri ) ) + return uri_get ( relative_uri ); + + /* Mangle URI */ + memcpy ( &tmp_uri, base_uri, sizeof ( tmp_uri ) ); + if ( relative_uri->path ) { + tmp_path = resolve_path ( ( base_uri->path ? + base_uri->path : "/" ), + relative_uri->path ); + tmp_uri.path = tmp_path; + tmp_uri.query = relative_uri->query; + tmp_uri.fragment = relative_uri->fragment; + } else if ( relative_uri->query ) { + tmp_uri.query = relative_uri->query; + tmp_uri.fragment = relative_uri->fragment; + } else if ( relative_uri->fragment ) { + tmp_uri.fragment = relative_uri->fragment; + } + + /* Create demangled URI */ + new_uri = uri_dup ( &tmp_uri ); + free ( tmp_path ); + return new_uri; +} + +/** + * Test for unreserved URI characters + * + * @v c Character to test + * @ret is_unreserved Character is an unreserved character + */ +static int is_unreserved_uri_char ( int c ) { + /* According to RFC3986, the unreserved character set is + * + * A-Z a-z 0-9 - _ . ~ + */ + return ( isupper ( c ) || islower ( c ) || isdigit ( c ) || + ( c == '-' ) || ( c == '_' ) || + ( c == '.' ) || ( c == '~' ) ); +} + +/** + * URI-encode string + * + * @v raw_string String to be URI-encoded + * @v buf Buffer to contain encoded string + * @v len Length of buffer + * @ret len Length of encoded string (excluding NUL) + */ +size_t uri_encode ( const char *raw_string, char *buf, size_t len ) { + ssize_t remaining = len; + size_t used; + unsigned char c; + + if ( len ) + buf[0] = '\0'; + + while ( ( c = *(raw_string++) ) ) { + if ( is_unreserved_uri_char ( c ) ) { + used = ssnprintf ( buf, remaining, "%c", c ); + } else { + used = ssnprintf ( buf, remaining, "%%%02X", c ); + } + buf += used; + remaining -= used; + } + + return ( len - remaining ); +} + +/** + * Decode URI-encoded string + * + * @v encoded_string URI-encoded string + * @v buf Buffer to contain decoded string + * @v len Length of buffer + * @ret len Length of decoded string (excluding NUL) + */ +size_t uri_decode ( const char *encoded_string, char *buf, size_t len ) { + ssize_t remaining = len; + char hexbuf[3]; + char *hexbuf_end; + unsigned char c; + + if ( len ) + buf[0] = '\0'; + + while ( *encoded_string ) { + if ( *encoded_string == '%' ) { + encoded_string++; + snprintf ( hexbuf, sizeof ( hexbuf ), "%s", + encoded_string ); + c = strtoul ( hexbuf, &hexbuf_end, 16 ); + encoded_string += ( hexbuf_end - hexbuf ); + } else { + c = *(encoded_string++); + } + ssnprintf ( buf++, remaining--, "%c", c ); + } + return ( len - remaining ); +} diff --git a/debian/grub-extras/disabled/gpxe/src/core/uuid.c b/debian/grub-extras/disabled/gpxe/src/core/uuid.c new file mode 100644 index 0000000..55fad36 --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/uuid.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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 +#include +#include +#include + +/** @file + * + * Universally unique IDs + * + */ + +/** + * Convert UUID to printable string + * + * @v uuid UUID + * @ret string UUID in canonical form + */ +char * uuid_ntoa ( union uuid *uuid ) { + static char buf[37]; /* "00000000-0000-0000-0000-000000000000" */ + + snprintf ( buf, sizeof (buf), + "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", + be32_to_cpu ( uuid->canonical.a ), + be16_to_cpu ( uuid->canonical.b ), + be16_to_cpu ( uuid->canonical.c ), + be16_to_cpu ( uuid->canonical.d ), + uuid->canonical.e[0], uuid->canonical.e[1], + uuid->canonical.e[2], uuid->canonical.e[3], + uuid->canonical.e[4], uuid->canonical.e[5] ); + return buf; +} diff --git a/debian/grub-extras/disabled/gpxe/src/core/xfer.c b/debian/grub-extras/disabled/gpxe/src/core/xfer.c new file mode 100644 index 0000000..1ec6f9d --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/core/xfer.c @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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 +#include +#include +#include + +/** @file + * + * Data transfer interfaces + * + */ + +/** + * Dummy transfer metadata + * + * This gets passed to xfer_interface::deliver_iob() and equivalents + * when no metadata is available. + */ +static struct xfer_metadata dummy_metadata; + +/** + * Close data transfer interface + * + * @v xfer Data transfer interface + * @v rc Reason for close + */ +void xfer_close ( struct xfer_interface *xfer, int rc ) { + struct xfer_interface *dest = xfer_get_dest ( xfer ); + struct xfer_interface_operations *op = xfer->op; + + DBGC ( xfer, "XFER %p->%p close\n", xfer, dest ); + + xfer_unplug ( xfer ); + xfer_nullify ( xfer ); + dest->op->close ( dest, rc ); + xfer->op = op; + xfer_put ( dest ); +} + +/** + * Send redirection event + * + * @v xfer Data transfer interface + * @v type New location type + * @v args Remaining arguments depend upon location type + * @ret rc Return status code + */ +int xfer_vredirect ( struct xfer_interface *xfer, int type, va_list args ) { + struct xfer_interface *dest = xfer_get_dest ( xfer ); + int rc; + + DBGC ( xfer, "XFER %p->%p redirect\n", xfer, dest ); + + rc = dest->op->vredirect ( dest, type, args ); + + if ( rc != 0 ) { + DBGC ( xfer, "XFER %p<-%p redirect: %s\n", xfer, dest, + strerror ( rc ) ); + } + xfer_put ( dest ); + return rc; +} + +/** + * Send redirection event + * + * @v xfer Data transfer interface + * @v type New location type + * @v ... Remaining arguments depend upon location type + * @ret rc Return status code + */ +int xfer_redirect ( struct xfer_interface *xfer, int type, ... ) { + va_list args; + int rc; + + va_start ( args, type ); + rc = xfer_vredirect ( xfer, type, args ); + va_end ( args ); + return rc; +} + +/** + * Check flow control window + * + * @v xfer Data transfer interface + * @ret len Length of window + */ +size_t xfer_window ( struct xfer_interface *xfer ) { + struct xfer_interface *dest = xfer_get_dest ( xfer ); + size_t len; + + len = dest->op->window ( dest ); + + xfer_put ( dest ); + return len; +} + +/** + * Allocate I/O buffer + * + * @v xfer Data transfer interface + * @v len I/O buffer payload length + * @ret iobuf I/O buffer + */ +struct io_buffer * xfer_alloc_iob ( struct xfer_interface *xfer, size_t len ) { + struct xfer_interface *dest = xfer_get_dest ( xfer ); + struct io_buffer *iobuf; + + DBGC ( xfer, "XFER %p->%p alloc_iob %zd\n", xfer, dest, len ); + + iobuf = dest->op->alloc_iob ( dest, len ); + + if ( ! iobuf ) { + DBGC ( xfer, "XFER %p<-%p alloc_iob failed\n", xfer, dest ); + } + xfer_put ( dest ); + return iobuf; +} + +/** + * Deliver datagram as I/O buffer with metadata + * + * @v xfer Data transfer interface + * @v iobuf Datagram I/O buffer + * @v meta Data transfer metadata + * @ret rc Return status code + */ +int xfer_deliver_iob_meta ( struct xfer_interface *xfer, + struct io_buffer *iobuf, + struct xfer_metadata *meta ) { + struct xfer_interface *dest = xfer_get_dest ( xfer ); + int rc; + + DBGC ( xfer, "XFER %p->%p deliver_iob %zd\n", xfer, dest, + iob_len ( iobuf ) ); + + rc = dest->op->deliver_iob ( dest, iobuf, meta ); + + if ( rc != 0 ) { + DBGC ( xfer, "XFER %p<-%p deliver_iob: %s\n", xfer, dest, + strerror ( rc ) ); + } + xfer_put ( dest ); + return rc; +} + +/** + * Deliver datagram as I/O buffer with metadata + * + * @v xfer Data transfer interface + * @v iobuf Datagram I/O buffer + * @ret rc Return status code + */ +int xfer_deliver_iob ( struct xfer_interface *xfer, + struct io_buffer *iobuf ) { + return xfer_deliver_iob_meta ( xfer, iobuf, &dummy_metadata ); +} + +/** + * Deliver datagram as raw data + * + * @v xfer Data transfer interface + * @v iobuf Datagram I/O buffer + * @ret rc Return status code + */ +int xfer_deliver_raw ( struct xfer_interface *xfer, + const void *data, size_t len ) { + struct xfer_interface *dest = xfer_get_dest ( xfer ); + int rc; + + DBGC ( xfer, "XFER %p->%p deliver_raw %p+%zd\n", xfer, dest, + data, len ); + + rc = dest->op->deliver_raw ( dest, data, len ); + + if ( rc != 0 ) { + DBGC ( xfer, "XFER %p<-%p deliver_raw: %s\n", xfer, dest, + strerror ( rc ) ); + } + xfer_put ( dest ); + return rc; +} + +/** + * Deliver formatted string + * + * @v xfer Data transfer interface + * @v format Format string + * @v args Arguments corresponding to the format string + * @ret rc Return status code + */ +int xfer_vprintf ( struct xfer_interface *xfer, const char *format, + va_list args ) { + size_t len; + va_list args_tmp; + + va_copy ( args_tmp, args ); + len = vsnprintf ( NULL, 0, format, args ); + { + char buf[len + 1]; + vsnprintf ( buf, sizeof ( buf ), format, args_tmp ); + va_end ( args_tmp ); + return xfer_deliver_raw ( xfer, buf, len ); + } +} + +/** + * Deliver formatted string + * + * @v xfer Data transfer interface + * @v format Format string + * @v ... Arguments corresponding to the format string + * @ret rc Return status code + */ +int xfer_printf ( struct xfer_interface *xfer, const char *format, ... ) { + va_list args; + int rc; + + va_start ( args, format ); + rc = xfer_vprintf ( xfer, format, args ); + va_end ( args ); + return rc; +} + +/** + * Seek to position + * + * @v xfer Data transfer interface + * @v offset Offset to new position + * @v whence Basis for new position + * @ret rc Return status code + */ +int xfer_seek ( struct xfer_interface *xfer, off_t offset, int whence ) { + struct io_buffer *iobuf; + struct xfer_metadata meta = { + .offset = offset, + .whence = whence, + }; + + DBGC ( xfer, "XFER %p seek %s+%ld\n", xfer, + whence_text ( whence ), offset ); + + /* Allocate and send a zero-length data buffer */ + iobuf = xfer_alloc_iob ( xfer, 0 ); + if ( ! iobuf ) + return -ENOMEM; + return xfer_deliver_iob_meta ( xfer, iobuf, &meta ); +} + +/**************************************************************************** + * + * Helper methods + * + * These functions are designed to be used as methods in the + * xfer_interface_operations table. + * + */ + +/** + * Ignore close() event + * + * @v xfer Data transfer interface + * @v rc Reason for close + */ +void ignore_xfer_close ( struct xfer_interface *xfer __unused, + int rc __unused ) { + /* Nothing to do */ +} + +/** + * Ignore vredirect() event + * + * @v xfer Data transfer interface + * @v type New location type + * @v args Remaining arguments depend upon location type + * @ret rc Return status code + */ +int ignore_xfer_vredirect ( struct xfer_interface *xfer __unused, + int type __unused, va_list args __unused ) { + return 0; +} + +/** + * Unlimited flow control window + * + * @v xfer Data transfer interface + * @ret len Length of window + * + * This handler indicates that the interface is always ready to accept + * data. + */ +size_t unlimited_xfer_window ( struct xfer_interface *xfer __unused ) { + return ~( ( size_t ) 0 ); +} + +/** + * No flow control window + * + * @v xfer Data transfer interface + * @ret len Length of window + * + * This handler indicates that the interface is never ready to accept + * data. + */ +size_t no_xfer_window ( struct xfer_interface *xfer __unused ) { + return 0; +} + +/** + * Allocate I/O buffer + * + * @v xfer Data transfer interface + * @v len I/O buffer payload length + * @ret iobuf I/O buffer + */ +struct io_buffer * +default_xfer_alloc_iob ( struct xfer_interface *xfer __unused, size_t len ) { + return alloc_iob ( len ); +} + +/** + * Deliver datagram as raw data + * + * @v xfer Data transfer interface + * @v iobuf Datagram I/O buffer + * @v meta Data transfer metadata + * @ret rc Return status code + * + * This function is intended to be used as the deliver() method for + * data transfer interfaces that prefer to handle raw data. + */ +int xfer_deliver_as_raw ( struct xfer_interface *xfer, + struct io_buffer *iobuf, + struct xfer_metadata *meta __unused ) { + int rc; + + rc = xfer->op->deliver_raw ( xfer, iobuf->data, iob_len ( iobuf ) ); + free_iob ( iobuf ); + return rc; +} + +/** + * Deliver datagram as I/O buffer + * + * @v xfer Data transfer interface + * @v data Data buffer + * @v len Length of data buffer + * @ret rc Return status code + * + * This function is intended to be used as the deliver_raw() method + * for data transfer interfaces that prefer to handle I/O buffers. + */ +int xfer_deliver_as_iob ( struct xfer_interface *xfer, + const void *data, size_t len ) { + struct io_buffer *iobuf; + + iobuf = xfer->op->alloc_iob ( xfer, len ); + if ( ! iobuf ) + return -ENOMEM; + + memcpy ( iob_put ( iobuf, len ), data, len ); + return xfer->op->deliver_iob ( xfer, iobuf, &dummy_metadata ); +} + +/** + * Ignore datagram as raw data event + * + * @v xfer Data transfer interface + * @v data Data buffer + * @v len Length of data buffer + * @ret rc Return status code + */ +int ignore_xfer_deliver_raw ( struct xfer_interface *xfer, + const void *data __unused, size_t len ) { + DBGC ( xfer, "XFER %p %zd bytes delivered %s\n", xfer, len, + ( ( xfer == &null_xfer ) ? + "before connection" : "after termination" ) ); + return 0; +} + +/** Null data transfer interface operations */ +struct xfer_interface_operations null_xfer_ops = { + .close = ignore_xfer_close, + .vredirect = ignore_xfer_vredirect, + .window = unlimited_xfer_window, + .alloc_iob = default_xfer_alloc_iob, + .deliver_iob = xfer_deliver_as_raw, + .deliver_raw = ignore_xfer_deliver_raw, +}; + +/** + * Null data transfer interface + * + * This is the interface to which data transfer interfaces are + * connected when unplugged. It will never generate messages, and + * will silently absorb all received messages. + */ +struct xfer_interface null_xfer = XFER_INIT ( &null_xfer_ops ); -- cgit v1.2.3