1 <?
// -*- Mode: PHP; -*-
4 * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
5 * Copyright (C) 2009 Entity Cyber, Inc.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 // Include table of user-configurable gPXE options
23 require_once "flag-table.php";
25 // Include user-shadowable globals
26 require_once "globals.php";
28 // Allow user to shadow globals
29 if ( is_file ( 'local-config.php' ) ) {
30 include_once "local-config.php";
34 // General utility functions
38 * Remove undesirable characters from a given string
40 * Certain characters have the potential to be used for
41 * malicious purposes by web-based attackers. This routine
42 * filters out such characters.
44 * @param string $s supplied string
46 * @return string returned string with unwanted characters
49 function cleanstring ( $s )
53 $s = substr ( $s, 0, 80 );
60 while ( $pos < $len ) {
61 $ltr = ord ( ucfirst ( $s[$pos] ) );
62 if ( ( $ltr >= ord ( "A" ) ) && ( $ltr <= ord ( "Z" ) ) ||
63 ( $ltr >= ord ( "0" ) ) && ( $ltr <= ord ( "9" ) ) ||
64 ( $ltr == ord ( "." ) ) && ( strlen ( $result ) > 0 ) ||
65 ( $ltr == ord ( "_" ) ) ||
66 ( $ltr == ord ( "+" ) ) ||
67 ( $ltr == ord ( ":" ) ) ||
68 ( $ltr == ord ( "/" ) ) ||
69 ( $ltr == ord ( "-" ) ) ) {
78 * Return URL of the currently running script, minus the filename
80 * @return string the URL of the currently running script, minus the filename
84 $dir = dirname ( $_SERVER['PHP_SELF'] );
86 if ( $dir == "." ||
$dir == "/" ) {
90 $isHTTPS = ( isset ( $_SERVER["HTTPS"] ) && $_SERVER["HTTPS"] == "on" );
91 $port = ( isset($_SERVER["SERVER_PORT"] ) &&
92 ( ( !$isHTTPS && $_SERVER["SERVER_PORT"] != "80" ) ||
93 ( $isHTTPS && $_SERVER["SERVER_PORT"] != "443" ) ) );
95 $port = ( $port ) ?
':' . $_SERVER["SERVER_PORT"] : '';
97 $dest = ( $isHTTPS ?
'https://' : 'http://' ) .
98 $_SERVER["SERVER_NAME"] . $dir . "/";
104 * Extract NIC families and associated ROM PCI IDs from the src/bin/NIC file.
106 * $src_dir must contain the path of the gPXE src directory for this build
108 * @return array[0] array $new_nics
109 * @return array[1] array $roms
111 function parse_nic_file ()
115 $fd = fopen ( "$src_dir/bin/NIC", "r" );
117 die ( "Missing src/bin/NIC file. 'make bin/NIC'" );
124 while ( !feof ( $fd ) ) {
126 $line = trim ( fgets ( $fd, 200 ) );
128 $first_eight_chars = substr ( $line, 0, 8 );
129 settype ( $first_eight_chars, "string" );
131 if ( strpos ( $first_eight_chars, "family" ) === 0 ) {
133 // get pathname of NIC driver
134 list ( $dummy, $nic ) = split( "[ \t]+", $line );
135 settype ( $nic, "string" );
137 // extract filename name of driver from pathname
138 $nic = substr ( $nic, strrpos ( $nic, "/" ) +
1,
139 strlen ( $nic ) - strrpos ( $nic, "/" ) +
1 );
143 // For each ISA NIC, there can only be one ROM variant
147 // If the first 8 digits of the line are hex digits
148 // add this rom to the current nic family.
150 if ( ( strlen ( $first_eight_chars ) == 8 )
151 && ( ctype_xdigit ( $first_eight_chars ) )
152 && ( $nic != "" ) ) {
154 $roms[$first_eight_chars] = $nic;
159 // put most NICs in nice alpha order for menu
162 // add special cases to the top
164 $new_nics = array ( "all-drivers" => "gpxe",
165 "undionly" => "undionly",
169 foreach ( $nics as $key => $value ) {
170 // skip the undi driver
171 if ( $key != "undi" ) {
172 $new_nics[$key] = $value;
176 return array ( $new_nics, $roms );
180 // HTML form utility functions
184 * Return html code to create hidden form input fields
186 * @param string $flag name of form variable to set
187 * @param string $value value to give form variable
189 * @return string html code for given hidden form input field
191 function hidden ( $flag, $value )
193 $value = htmlentities ( $value );
194 return "<input type=\"hidden\" value=\"$value\" name=\"$flag\"></input>";
198 * Return html code to create checkbox form input fields
200 * @param string $flag name of form variable to set
201 * @param string $value "on" means box should be checked
203 * @return string html code for given hidden form input field
205 function checkbox ( $flag, $value )
207 return "<input type=\"checkbox\" value=\"on\" name=\"$flag\"" .
208 ($value == "on" ?
" checked>" : ">" );
212 * Return html code to create text form input fields
214 * @param string $flag name of form variable to set
215 * @param string $value initial contents of field
216 * @param string $size size in characters of text box
218 * @return string html code for given text input field
220 function textbox ( $flag, $value, $size )
222 $value = htmlentities ( $value );
223 return "<input type=\"text\" size=\"$size\" value=\"$value\" name=\"$flag\">";
227 * Return html code to create textarea form fields
229 * @param string $flag name of form variable to set
230 * @param string $value initial contents of textarea
231 * @param string $rows height of text area in rows
232 * @param string $cols width of text area in columns
234 * @return string html code for given textarea input field
236 function textarea ( $flag, $value, $rows, $cols )
238 $value = htmlentities ( $value );
239 return "<textarea name=\"$flag\" rows=\"$rows\" cols=\"$cols\">"
240 . $value . "</textarea>";
244 * Return html code to create select (menu) form fields
246 * Use array of strings as menu choices
248 * @param string $flag name of form variable to set
249 * @param array $options array of strings representing choices
250 * @param string $value value of choice to select in menu
252 * @return string html code for given select (menu) input field
254 function menubox ( $name, $options, $value )
256 $s="<select name=\"$name\">";
258 foreach ( $options as $ignore => $option ) {
259 if ( !$value ) $value = $option;
260 $s .= "<option" . ( $option == $value ?
" selected>" : ">" ) .
261 htmlentities ( $option ) . "</option>";
263 return $s . "</select>";
267 * Return html code to create select (menu) form fields
269 * Use indices of array of strings as menu choices rather than
270 * the values pointed to by the indicies.
272 * @param string $flag name of form variable to set
273 * @param array $options array of strings representing choices
274 * @param string $value value of choice to select in menu
276 * @return string html code for given select (menu) input field
278 function keys_menubox ( $name, $options, $value )
280 $s="<select name=\"$name\">";
282 foreach ( $options as $option => $ignore ) {
283 if ( !$value ) $value = $option;
284 $s .= "<option" . ( $option == $value ?
" selected>" : ">" ) .
285 htmlentities ( $option ) . "</option>";
287 return $s . "</select>";
291 // Flag (compile option) handling functions
295 * Return default compile options (flags)
297 * Initial compile options are in a global called $flag_table.
298 * Create and return an array containing the ones we want.
300 * @return array default compile options (flags)
302 function default_flags ()
308 foreach ( $flag_table as $key => $props ) {
310 $flag = $props["flag"];
311 $type = $props["type"];
313 // Fields like headers have no "value" property
314 if ( isset ( $props["value"] ) ) {
315 $flags[$flag] = $props["value"];
322 * Return combination of default and user compile options (flags)
324 * Initial compile options are in a global called $flag_table.
325 * Compile options may have been changed via form input. We return
326 * an array with either the default value of each option or a user
327 * supplied value from form input.
329 * @return array combined default and user supplied compile options (flags)
331 function get_flags ()
335 $flags = default_flags ();
337 if ( ! isset ( $_POST["use_flags"] ) )
340 foreach ( $flag_table as $key => $props ) {
342 $flag = $props["flag"];
343 $type = $props["type"];
345 if ( isset ( $_POST["$flag"] ) ) {
346 $flags[$flag] = $_POST["$flag"];
347 if ( $type == "integer-hex" ) {
348 if ( strtolower ( substr ( $flags[$flag], 0, 2 ) ) != "0x" ) {
349 $flags[$flag] = "0x" . $flags[$flag];
352 } else if ( $type == "on/off" ) {
353 // Unchecked checkboxes don't pass any POST value
354 // so we must check for them specially. At this
355 // point we know that there is no $_POST value set
356 // for this option. If it is a checkbox, this means
357 // it is unchecked, so record that in $flags so we
358 // can later generate an #undef for this option.
359 $flags[$flag] = "off";
366 * Output given value in appropriate format for gPXE config file
368 * gPXE config/*.h files use C pre-processor syntax. Output the given
369 * compile option in a format appropriate to its type
371 * @param string $key index into $flag_table for given compile option
372 * @param string $value value we wish to set compile option to
374 * @return string code to set compile option to given value
376 function pprint_flag ( $key, $value )
380 // Determine type of given compile option (flag)
381 $type = $flag_table[$key]["type"];
384 if ( $type == "on/off" && $value == "on" ) {
386 } else if ( $type == "on/off" && $value != "on" ) {
388 } else if ( $type == "string" ) {
389 $s = ( "#define $key \"" . cleanstring ( $value ) . "\"" );
390 } else if ($type == "qstring" ) {
391 $s = ( "#define $key \\\"" . cleanstring ( $value ) . "\\\"" );
393 $s = "#define $key " . cleanstring ( $value );
400 * Output html code to display all compile options as a table
402 * @param array $flags array of compile options
406 function echo_flags ( $flags )
412 foreach ( $flag_table as $key => $props ) {
414 // Hide parameters from users that should not be changed.
415 $hide_from_user = isset ( $props["hide_from_user"] ) ?
$props["hide_from_user"] : "no";
417 $flag = $props["flag"];
418 $type = $props["type"];
420 $value = isset ( $flags[$flag] ) ?
$flags[$flag] : '';
422 if ( $hide_from_user == "yes" ) {
424 // Hidden flags cannot not be set by the user. We use hidden form
425 // fields to keep them at their default values.
426 if ( $type != "header" ) {
427 echo hidden ( $flag, $value );
432 // Flag (gPXE compile option) should be displayed to user
434 if ( $type == "header" ) {
436 $label = $props["label"];
437 echo "<td colspan=2><hr><h3>$label</h3><hr></td>";
439 } else if ($type == "on/off" ) {
441 echo "<td>", checkbox ( $flag, $value ), "</td><td><strong>$flag</strong></td>";
443 } else { // don't display checkbox for non-on/off flags
445 echo "<td> </td><td><strong>$flag: </strong>";
447 if ($type == "choice" ) {
448 $options = $props["options"];
449 echo menubox($flag, $options, $value);
453 echo textbox($flag, $value, ($type == "integer" ||
454 $type == "integer-hex"
461 if ( $type != "header" ) {
462 echo "<tr><td> </td>";
464 if ( is_file ( "doc/$flag.html" ) ) {
465 include_once "doc/$flag.html";
467 echo "\n</td></tr>\n";
475 * Return an array of configuration sections used in all compile options
477 * $flag_table, the global list of compile options contains a 'cfgsec'
478 * property for each flag we are interested in. We return a list of
479 * all the unique cfgsec options we find in $flag_table.
481 * @return array an array of strings representing all unique cfgsec values
482 * found in $flag_table
484 function get_flag_cfgsecs ()
489 foreach ( $flag_table as $key => $props ) {
490 if ( isset ( $props['cfgsec'] ) ) {
491 $cfgsec = $props["cfgsec"];
492 $cfgsecs[$cfgsec] = $cfgsec;
499 // File and directory handling functions
503 * Create a copy of a given source directory to a given destination
505 * Since we are going to modify the source directory, we create a copy
506 * of the directory with a unique name in the given destination directory.
507 * We supply a prefix for the tempnam call to prepend to the random filename
510 * @param string $src source directory
511 * @param string $dst destination directory
512 * @param string $prefix string to append to directory created
514 * @return string absolute path to destination directory
516 function mktempcopy ( $src, $dst, $prefix )
518 if ( $src[0] != "/" ) {
519 $src = dirname ( $_SERVER['SCRIPT_FILENAME'] ) . "/" . $src;
522 // Create a file in the given destination directory with a unique name
523 $dir = tempnam ( $dst, $prefix );
525 // Delete the file just created, since it would interfere with the copy we
526 // are about to do. We only care that the dir name we copy to is unique.
529 exec ( "/bin/cp -a '$src' '$dir' 2>&1", $cpytxt, $status );
531 if ( $status != 0 ) {
532 die ( "src directory copy failed!" );
538 * Write gPXE config files based on value of given flags
540 * gPXE compile options are stored in src/config/*.h .
541 * We write out a config file for each set of options.
543 * @param string $config_dir directory to write .h files to
544 * @param array $flags array of compile options for this build
548 function write_gpxe_config_files ( $config_dir, $flags )
552 $cfgsecs = get_flag_cfgsecs ();
554 foreach ( $cfgsecs as $cfgsec ) {
556 $fname = $config_dir . "/" . $cfgsec . ".h";
558 $fp = fopen ( $fname, "wb" );
560 die ( "Unable to open $fname file for output!" );
563 $ifdef_secname = "CONFIG_" . strtoupper ( $cfgsec ) . "_H";
565 fwrite ( $fp, "#ifndef ${ifdef_secname}\n" );
566 fwrite ( $fp, "#define ${ifdef_secname}\n" );
567 fwrite ( $fp, "#include <config/defaults.h>\n" );
569 foreach ( $flags as $key => $value ) {
570 // When the flag matches this section name, write it out
571 if ( $flag_table[$key]["cfgsec"] == $cfgsec ) {
572 fwrite ( $fp, pprint_flag ( $key, $value ) . "\n" );
575 fwrite ( $fp, "#endif /* ${ifdef_secname} */\n" );
581 * Output a string to a file
583 * Output a given string to a given pathname. The file will be created if
584 * necessary, and the string will replace the file's contents in all cases.
586 * @param string $fname pathname of file to output string to
587 * @param string $ftext text to output to file
591 function write_file_from_string ( $fname, $ftext )
593 $fp = fopen ( $fname, "wb" );
595 die ( "Unable to open $fname file for output!" );
597 fwrite ( $fp, $ftext );
602 * Delete a file or recursively delete a directory tree
604 * @param string $file_or_dir_name name of file or directory to delete
605 * @return bool Returns TRUE on success, FALSE on failure
607 function rm_file_or_dir ( $file_or_dir_name )
609 if ( ! file_exists ( $file_or_dir_name ) ) {
613 if ( is_file ( $file_or_dir_name ) ||
is_link ( $file_or_dir_name ) ) {
614 return unlink ( $file_or_dir_name );
617 $dir = dir ( $file_or_dir_name );
618 while ( ( $dir_entry = $dir->read () ) !== false ) {
620 if ( $dir_entry == '.' ||
$dir_entry == '..') {
623 rm_file_or_dir ( $file_or_dir_name . '/' . $dir_entry );
627 return rmdir ( $file_or_dir_name );
631 // Debugging functions
635 * Emit html code to display given array of compile options (flags)
637 * @param array $flags array of compile options for this build
641 function show_flags ( $flags )
643 echo ( "\$flags contains " . count ( $flags ) . " elements:" . "<br>" );
645 foreach ( $flags as $key => $flag ) {
646 echo ( "\$flags[" . $key . "]=" . "\"$flag\"" . "<br>" );
651 * Emit HTML code to display default array of compile options (flags)
653 * $flag_table contains default compile options and properties. This
654 * routine outputs HTML code to display all properties of $flag_table.
658 function dump_flag_table ()
662 echo ( "\$flag_table contains " . count ( $flag_table ) . " elements:" . "<br>" );
664 foreach ( $flag_table as $key => $props ) {
665 print ( "flag_table[" . $key . "] = " . "<br>" );
667 foreach ( $props as $key2 => $props2 ) {
668 print ( " " . $key2 . " = " . $props2 . "<br>" );
673 // Parse src/bin/NIC file
674 list ( $nics, $roms ) = parse_nic_file ();