| <?php // -*- Mode: PHP; -*- | |
| /** | |
| * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>. | |
| * Copyright (C) 2009 Entity Cyber, Inc. | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU General Public License as | |
| * published by the Free Software Foundation; either version 2 of the | |
| * License, or any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, but | |
| * WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU General Public License | |
| * along with this program; if not, write to the Free Software | |
| * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| */ | |
| // Include table of user-configurable iPXE options | |
| require_once "flag-table.php"; | |
| // Include user-shadowable globals | |
| require_once "globals.php"; | |
| // Allow user to shadow globals | |
| if ( is_file ( 'local-config.php' ) ) { | |
| include_once "local-config.php"; | |
| } | |
| //// | |
| // General utility functions | |
| //// | |
| /** | |
| * Remove undesirable characters from a given string | |
| * | |
| * Certain characters have the potential to be used for | |
| * malicious purposes by web-based attackers. This routine | |
| * filters out such characters. | |
| * | |
| * @param string $s supplied string | |
| * | |
| * @return string returned string with unwanted characters | |
| * removed | |
| */ | |
| function cleanstring ( $s ) | |
| { | |
| $len = strlen ( $s ); | |
| if ( $len > 80 ) { | |
| $s = substr ( $s, 0, 80 ); | |
| } | |
| $s = trim ( $s ); | |
| $pos = 0; | |
| $result = ""; | |
| while ( $pos < $len ) { | |
| $ltr = ord ( ucfirst ( $s[$pos] ) ); | |
| if ( ( $ltr >= ord ( "A" ) ) && ( $ltr <= ord ( "Z" ) ) || | |
| ( $ltr >= ord ( "0" ) ) && ( $ltr <= ord ( "9" ) ) || | |
| ( $ltr == ord ( "." ) ) && ( strlen ( $result ) > 0 ) || | |
| ( $ltr == ord ( "_" ) ) || | |
| ( $ltr == ord ( "+" ) ) || | |
| ( $ltr == ord ( ":" ) ) || | |
| ( $ltr == ord ( "/" ) ) || | |
| ( $ltr == ord ( "-" ) ) ) { | |
| $result .= $s[$pos]; | |
| } | |
| $pos++; | |
| } | |
| return $result; | |
| } | |
| /** | |
| * Return URL of the currently running script, minus the filename | |
| * | |
| * @return string the URL of the currently running script, minus the filename | |
| */ | |
| function curDirURL () | |
| { | |
| $dir = dirname ( $_SERVER['PHP_SELF'] ); | |
| if ( $dir == "." || $dir == "/" ) { | |
| $dir = ""; | |
| } | |
| $isHTTPS = ( isset ( $_SERVER["HTTPS"] ) && $_SERVER["HTTPS"] == "on" ); | |
| $port = ( isset($_SERVER["SERVER_PORT"] ) && | |
| ( ( !$isHTTPS && $_SERVER["SERVER_PORT"] != "80" ) || | |
| ( $isHTTPS && $_SERVER["SERVER_PORT"] != "443" ) ) ); | |
| $port = ( $port ) ? ':' . $_SERVER["SERVER_PORT"] : ''; | |
| $dest = ( $isHTTPS ? 'https://' : 'http://' ) . | |
| $_SERVER["SERVER_NAME"] . $dir . "/"; | |
| return $dest; | |
| } | |
| /** | |
| * Extract NIC families and associated ROM PCI IDs from the src/bin/NIC file. | |
| * | |
| * $src_dir must contain the path of the iPXE src directory for this build | |
| * | |
| * @return array[0] array $new_nics | |
| * @return array[1] array $roms | |
| */ | |
| function parse_nic_file () | |
| { | |
| global $src_dir; | |
| $fd = fopen ( "$src_dir/bin/NIC", "r" ); | |
| if ( ! $fd ) { | |
| die ( "Missing src/bin/NIC file. 'make bin/NIC'" ); | |
| } | |
| $nics = array (); | |
| $roms = array (); | |
| $nic = ""; | |
| while ( !feof ( $fd ) ) { | |
| $line = trim ( fgets ( $fd, 200 ) ); | |
| $first_eight_chars = substr ( $line, 0, 8 ); | |
| settype ( $first_eight_chars, "string" ); | |
| if ( strpos ( $first_eight_chars, "family" ) === 0 ) { | |
| // get pathname of NIC driver | |
| #list ( $dummy, $nic ) = split( "[ \t]+", $line ); | |
| list ( $dummy, $nic ) = explode("\t", $line); | |
| settype ( $nic, "string" ); | |
| // extract filename name of driver from pathname | |
| $nic = substr ( $nic, strrpos ( $nic, "/" ) + 1, | |
| strlen ( $nic ) - strrpos ( $nic, "/" ) + 1 ); | |
| $nics[$nic] = $nic; | |
| // For each ISA NIC, there can only be one ROM variant | |
| $roms[$nic] = $nic; | |
| } | |
| // If the first 8 digits of the line are hex digits | |
| // add this rom to the current nic family. | |
| if ( ( strlen ( $first_eight_chars ) == 8 ) | |
| && ( ctype_xdigit ( $first_eight_chars ) ) | |
| && ( $nic != "" ) ) { | |
| $roms[$first_eight_chars] = $nic; | |
| } | |
| } | |
| fclose ( $fd ); | |
| // put most NICs in nice alpha order for menu | |
| ksort ( $nics ); | |
| // add special cases to the top | |
| $new_nics = array ( "all-drivers" => "ipxe", | |
| "undionly" => "undionly", | |
| "undi" => "undi", | |
| ); | |
| foreach ( $nics as $key => $value ) { | |
| // skip the undi driver | |
| if ( $key != "undi" ) { | |
| $new_nics[$key] = $value; | |
| } | |
| } | |
| return array ( $new_nics, $roms ); | |
| } | |
| //// | |
| // HTML form utility functions | |
| //// | |
| /** | |
| * Return html code to create hidden form input fields | |
| * | |
| * @param string $flag name of form variable to set | |
| * @param string $value value to give form variable | |
| * | |
| * @return string html code for given hidden form input field | |
| */ | |
| function hidden ( $flag, $value ) | |
| { | |
| $value = htmlentities ( $value ); | |
| return "<input type=\"hidden\" value=\"$value\" name=\"$flag\"></input>"; | |
| } | |
| /** | |
| * Return html code to create checkbox form input fields | |
| * | |
| * @param string $flag name of form variable to set | |
| * @param string $value "on" means box should be checked | |
| * | |
| * @return string html code for given hidden form input field | |
| */ | |
| function checkbox ( $flag, $value ) | |
| { | |
| return "<input type=\"checkbox\" value=\"on\" name=\"$flag\"" . | |
| ($value == "on" ? " checked>" : ">" ); | |
| } | |
| /** | |
| * Return html code to create text form input fields | |
| * | |
| * @param string $flag name of form variable to set | |
| * @param string $value initial contents of field | |
| * @param string $size size in characters of text box | |
| * | |
| * @return string html code for given text input field | |
| */ | |
| function textbox ( $flag, $value, $size ) | |
| { | |
| $value = htmlentities ( $value ); | |
| return "<input type=\"text\" size=\"$size\" value=\"$value\" name=\"$flag\">"; | |
| } | |
| /** | |
| * Return html code to create textarea form fields | |
| * | |
| * @param string $flag name of form variable to set | |
| * @param string $value initial contents of textarea | |
| * @param string $rows height of text area in rows | |
| * @param string $cols width of text area in columns | |
| * | |
| * @return string html code for given textarea input field | |
| */ | |
| function textarea ( $flag, $value, $rows, $cols ) | |
| { | |
| $value = htmlentities ( $value ); | |
| return "<textarea name=\"$flag\" rows=\"$rows\" cols=\"$cols\">" | |
| . $value . "</textarea>"; | |
| } | |
| /** | |
| * Return html code to create select (menu) form fields | |
| * | |
| * Use array of strings as menu choices | |
| * | |
| * @param string $flag name of form variable to set | |
| * @param array $options array of strings representing choices | |
| * @param string $value value of choice to select in menu | |
| * | |
| * @return string html code for given select (menu) input field | |
| */ | |
| function menubox ( $name, $options, $value ) | |
| { | |
| $s="<select name=\"$name\">"; | |
| foreach ( $options as $ignore => $option ) { | |
| if ( !$value ) $value = $option; | |
| $s .= "<option" . ( $option == $value ? " selected>" : ">" ) . | |
| htmlentities ( $option ) . "</option>"; | |
| } | |
| return $s . "</select>"; | |
| } | |
| /** | |
| * Return html code to create select (menu) form fields | |
| * | |
| * Use indices of array of strings as menu choices rather than | |
| * the values pointed to by the indicies. | |
| * | |
| * @param string $flag name of form variable to set | |
| * @param array $options array of strings representing choices | |
| * @param string $value value of choice to select in menu | |
| * | |
| * @return string html code for given select (menu) input field | |
| */ | |
| function keys_menubox ( $name, $options, $value ) | |
| { | |
| $s="<select name=\"$name\">"; | |
| foreach ( $options as $option => $ignore ) { | |
| if ( !$value ) $value = $option; | |
| $s .= "<option" . ( $option == $value ? " selected>" : ">" ) . | |
| htmlentities ( $option ) . "</option>"; | |
| } | |
| return $s . "</select>"; | |
| } | |
| //// | |
| // Flag (compile option) handling functions | |
| //// | |
| /** | |
| * Return default compile options (flags) | |
| * | |
| * Initial compile options are in a global called $flag_table. | |
| * Create and return an array containing the ones we want. | |
| * | |
| * @return array default compile options (flags) | |
| */ | |
| function default_flags () | |
| { | |
| global $flag_table; | |
| $flags = array (); | |
| foreach ( $flag_table as $key => $props ) { | |
| $flag = $props["flag"]; | |
| $type = $props["type"]; | |
| // Fields like headers have no "value" property | |
| if ( isset ( $props["value"] ) ) { | |
| $flags[$flag] = $props["value"]; | |
| } | |
| } | |
| return $flags; | |
| } | |
| /** | |
| * Return combination of default and user compile options (flags) | |
| * | |
| * Initial compile options are in a global called $flag_table. | |
| * Compile options may have been changed via form input. We return | |
| * an array with either the default value of each option or a user | |
| * supplied value from form input. | |
| * | |
| * @return array combined default and user supplied compile options (flags) | |
| */ | |
| function get_flags () | |
| { | |
| global $flag_table; | |
| $flags = default_flags (); | |
| if ( ! isset ( $_POST["use_flags"] ) ) | |
| return $flags; | |
| foreach ( $flag_table as $key => $props ) { | |
| $flag = $props["flag"]; | |
| $type = $props["type"]; | |
| if ( isset ( $_POST["$flag"] ) ) { | |
| $flags[$flag] = $_POST["$flag"]; | |
| if ( $type == "integer-hex" ) { | |
| if ( strtolower ( substr ( $flags[$flag], 0, 2 ) ) != "0x" ) { | |
| $flags[$flag] = "0x" . $flags[$flag]; | |
| } | |
| } | |
| } else if ( $type == "on/off" ) { | |
| // Unchecked checkboxes don't pass any POST value | |
| // so we must check for them specially. At this | |
| // point we know that there is no $_POST value set | |
| // for this option. If it is a checkbox, this means | |
| // it is unchecked, so record that in $flags so we | |
| // can later generate an #undef for this option. | |
| $flags[$flag] = "off"; | |
| } | |
| } | |
| return $flags; | |
| } | |
| /** | |
| * Output given value in appropriate format for iPXE config file | |
| * | |
| * iPXE config/*.h files use C pre-processor syntax. Output the given | |
| * compile option in a format appropriate to its type | |
| * | |
| * @param string $key index into $flag_table for given compile option | |
| * @param string $value value we wish to set compile option to | |
| * | |
| * @return string code to set compile option to given value | |
| */ | |
| function pprint_flag ( $key, $value ) | |
| { | |
| global $flag_table; | |
| // Determine type of given compile option (flag) | |
| $type = $flag_table[$key]["type"]; | |
| $s = ""; | |
| if ( $type == "on/off" && $value == "on" ) { | |
| $s = "#define $key"; | |
| } else if ( $type == "on/off" && $value != "on" ) { | |
| $s = "#undef $key"; | |
| } else if ( $type == "string" ) { | |
| $s = ( "#define $key \"" . cleanstring ( $value ) . "\"" ); | |
| } else if ($type == "qstring" ) { | |
| $s = ( "#define $key \\\"" . cleanstring ( $value ) . "\\\"" ); | |
| } else { | |
| $s = "#define $key " . cleanstring ( $value ); | |
| } | |
| return $s; | |
| } | |
| /** | |
| * Output html code to display all compile options as a table | |
| * | |
| * @param array $flags array of compile options | |
| * | |
| * @return void | |
| */ | |
| function echo_flags ( $flags ) | |
| { | |
| global $flag_table; | |
| echo "<table>\n"; | |
| foreach ( $flag_table as $key => $props ) { | |
| // Hide parameters from users that should not be changed. | |
| $hide_from_user = isset ( $props["hide_from_user"] ) ? $props["hide_from_user"] : "no"; | |
| $flag = $props["flag"]; | |
| $type = $props["type"]; | |
| $value = isset ( $flags[$flag] ) ? $flags[$flag] : ''; | |
| if ( $hide_from_user == "yes" ) { | |
| // Hidden flags cannot not be set by the user. We use hidden form | |
| // fields to keep them at their default values. | |
| if ( $type != "header" ) { | |
| echo hidden ( $flag, $value ); | |
| } | |
| } else { | |
| // Flag (iPXE compile option) should be displayed to user | |
| if ( $type == "header" ) { | |
| $label = $props["label"]; | |
| echo "<td colspan=2><hr><h3>$label</h3><hr></td>"; | |
| } else if ($type == "on/off" ) { | |
| echo "<td>", checkbox ( $flag, $value ), "</td><td><strong>$flag</strong></td>"; | |
| } else { // don't display checkbox for non-on/off flags | |
| echo "<td> </td><td><strong>$flag: </strong>"; | |
| if ($type == "choice" ) { | |
| $options = $props["options"]; | |
| echo menubox($flag, $options, $value); | |
| } else { | |
| echo textbox($flag, $value, ($type == "integer" || | |
| $type == "integer-hex" | |
| ? 7 : 25)); | |
| } | |
| echo "</td>"; | |
| } | |
| echo "</tr>\n"; | |
| if ( $type != "header" ) { | |
| echo "<tr><td> </td>"; | |
| echo "<td>\n"; | |
| if ( is_file ( "doc/$flag.html" ) ) { | |
| include_once "doc/$flag.html"; | |
| } | |
| echo "\n</td></tr>\n"; | |
| } | |
| } | |
| } | |
| echo "</table>"; | |
| } | |
| /** | |
| * Return an array of configuration sections used in all compile options | |
| * | |
| * $flag_table, the global list of compile options contains a 'cfgsec' | |
| * property for each flag we are interested in. We return a list of | |
| * all the unique cfgsec options we find in $flag_table. | |
| * | |
| * @return array an array of strings representing all unique cfgsec values | |
| * found in $flag_table | |
| */ | |
| function get_flag_cfgsecs () | |
| { | |
| global $flag_table; | |
| $cfgsecs = array (); | |
| foreach ( $flag_table as $key => $props ) { | |
| if ( isset ( $props['cfgsec'] ) ) { | |
| $cfgsec = $props["cfgsec"]; | |
| $cfgsecs[$cfgsec] = $cfgsec; | |
| } | |
| } | |
| return $cfgsecs; | |
| } | |
| //// | |
| // File and directory handling functions | |
| //// | |
| /** | |
| * Create a copy of a given source directory to a given destination | |
| * | |
| * Since we are going to modify the source directory, we create a copy | |
| * of the directory with a unique name in the given destination directory. | |
| * We supply a prefix for the tempnam call to prepend to the random filename | |
| * it generates. | |
| * | |
| * @param string $src source directory | |
| * @param string $dst destination directory | |
| * @param string $prefix string to append to directory created | |
| * | |
| * @return string absolute path to destination directory | |
| */ | |
| function mktempcopy ( $src, $dst, $prefix ) | |
| { | |
| if ( $src[0] != "/" ) { | |
| $src = dirname ( $_SERVER['SCRIPT_FILENAME'] ) . "/" . $src; | |
| } | |
| // Create a file in the given destination directory with a unique name | |
| $dir = tempnam ( $dst, $prefix ); | |
| // Delete the file just created, since it would interfere with the copy we | |
| // are about to do. We only care that the dir name we copy to is unique. | |
| unlink ( $dir ); | |
| exec ( "/bin/cp -a '$src' '$dir' 2>&1", $cpytxt, $status ); | |
| if ( $status != 0 ) { | |
| die ( "src directory copy failed!" ); | |
| } | |
| return $dir; | |
| } | |
| /** | |
| * Write iPXE config files based on value of given flags | |
| * | |
| * iPXE compile options are stored in src/config/*.h . | |
| * We write out a config file for each set of options. | |
| * | |
| * @param string $config_dir directory to write .h files to | |
| * @param array $flags array of compile options for this build | |
| * | |
| * @return void | |
| */ | |
| function write_ipxe_config_files ( $config_dir, $flags ) | |
| { | |
| global $flag_table; | |
| $cfgsecs = get_flag_cfgsecs (); | |
| foreach ( $cfgsecs as $cfgsec ) { | |
| $fname = $config_dir . "/" . $cfgsec . ".h"; | |
| $fp = fopen ( $fname, "wb" ); | |
| if ( $fp <= 0 ) { | |
| die ( "Unable to open $fname file for output!" ); | |
| } | |
| $ifdef_secname = "CONFIG_" . strtoupper ( $cfgsec ) . "_H"; | |
| fwrite ( $fp, "#ifndef ${ifdef_secname}\n" ); | |
| fwrite ( $fp, "#define ${ifdef_secname}\n" ); | |
| fwrite ( $fp, "#include <config/defaults.h>\n" ); | |
| foreach ( $flags as $key => $value ) { | |
| // When the flag matches this section name, write it out | |
| if ( $flag_table[$key]["cfgsec"] == $cfgsec ) { | |
| fwrite ( $fp, pprint_flag ( $key, $value ) . "\n" ); | |
| } | |
| } | |
| fwrite ( $fp, "#endif /* ${ifdef_secname} */\n" ); | |
| fclose ( $fp ); | |
| } | |
| } | |
| /** | |
| * Output a string to a file | |
| * | |
| * Output a given string to a given pathname. The file will be created if | |
| * necessary, and the string will replace the file's contents in all cases. | |
| * | |
| * @param string $fname pathname of file to output string to | |
| * @param string $ftext text to output to file | |
| * | |
| * @return void | |
| */ | |
| function write_file_from_string ( $fname, $ftext ) | |
| { | |
| $fp = fopen ( $fname, "wb" ); | |
| if ( ! $fp ) { | |
| die ( "Unable to open $fname file for output!" ); | |
| } | |
| fwrite ( $fp, $ftext ); | |
| fclose ( $fp ); | |
| } | |
| /** | |
| * Delete a file or recursively delete a directory tree | |
| * | |
| * @param string $file_or_dir_name name of file or directory to delete | |
| * @return bool Returns TRUE on success, FALSE on failure | |
| */ | |
| function rm_file_or_dir ( $file_or_dir_name ) | |
| { | |
| if ( ! file_exists ( $file_or_dir_name ) ) { | |
| return false; | |
| } | |
| if ( is_file ( $file_or_dir_name ) || is_link ( $file_or_dir_name ) ) { | |
| return unlink ( $file_or_dir_name ); | |
| } | |
| $dir = dir ( $file_or_dir_name ); | |
| while ( ( $dir_entry = $dir->read () ) !== false ) { | |
| if ( $dir_entry == '.' || $dir_entry == '..') { | |
| continue; | |
| } | |
| rm_file_or_dir ( $file_or_dir_name . '/' . $dir_entry ); | |
| } | |
| $dir->close(); | |
| return rmdir ( $file_or_dir_name ); | |
| } | |
| //// | |
| // Debugging functions | |
| //// | |
| /** | |
| * Emit html code to display given array of compile options (flags) | |
| * | |
| * @param array $flags array of compile options for this build | |
| * | |
| * @return void | |
| */ | |
| function show_flags ( $flags ) | |
| { | |
| echo ( "\$flags contains " . count ( $flags ) . " elements:" . "<br>" ); | |
| foreach ( $flags as $key => $flag ) { | |
| echo ( "\$flags[" . $key . "]=" . "\"$flag\"" . "<br>" ); | |
| } | |
| } | |
| /** | |
| * Emit HTML code to display default array of compile options (flags) | |
| * | |
| * $flag_table contains default compile options and properties. This | |
| * routine outputs HTML code to display all properties of $flag_table. | |
| * | |
| * @return void | |
| */ | |
| function dump_flag_table () | |
| { | |
| global $flag_table; | |
| echo ( "\$flag_table contains " . count ( $flag_table ) . " elements:" . "<br>" ); | |
| foreach ( $flag_table as $key => $props ) { | |
| print ( "flag_table[" . $key . "] = " . "<br>" ); | |
| foreach ( $props as $key2 => $props2 ) { | |
| print ( " " . $key2 . " = " . $props2 . "<br>" ); | |
| } | |
| } | |
| } | |
| // Parse src/bin/NIC file | |
| list ( $nics, $roms ) = parse_nic_file (); | |
| // For emacs: | |
| // Local variables: | |
| // c-basic-offset: 4 | |
| // c-indent-level: 4 | |
| // tab-width: 4 | |
| // End: | |
| ?> |