| <?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: |
| |
| ?> |