|
|
1.1 root 1: <? // -*- Mode: PHP; -*-
2:
3: /**
4: * Copyright (C) 2009 Marty Connor <[email protected]>.
5: * Copyright (C) 2009 Entity Cyber, Inc.
6: *
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.
11: *
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.
16: *
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.
20: */
21:
22: // Include table of user-configurable iPXE options
23: require_once "flag-table.php";
24:
25: // Include user-shadowable globals
26: require_once "globals.php";
27:
28: // Allow user to shadow globals
29: if ( is_file ( 'local-config.php' ) ) {
30: include_once "local-config.php";
31: }
32:
33: ////
34: // General utility functions
35: ////
36:
37: /**
38: * Remove undesirable characters from a given string
39: *
40: * Certain characters have the potential to be used for
41: * malicious purposes by web-based attackers. This routine
42: * filters out such characters.
43: *
44: * @param string $s supplied string
45: *
46: * @return string returned string with unwanted characters
47: * removed
48: */
49: function cleanstring ( $s )
50: {
51: $len = strlen ( $s );
52: if ( $len > 80 ) {
53: $s = substr ( $s, 0, 80 );
54: }
55:
56: $s = trim ( $s );
57: $pos = 0;
58: $result = "";
59:
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 ( "-" ) ) ) {
70: $result .= $s[$pos];
71: }
72: $pos++;
73: }
74: return $result;
75: }
76:
77: /**
78: * Return URL of the currently running script, minus the filename
79: *
80: * @return string the URL of the currently running script, minus the filename
81: */
82: function curDirURL ()
83: {
84: $dir = dirname ( $_SERVER['PHP_SELF'] );
85:
86: if ( $dir == "." || $dir == "/" ) {
87: $dir = "";
88: }
89:
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" ) ) );
94:
95: $port = ( $port ) ? ':' . $_SERVER["SERVER_PORT"] : '';
96:
97: $dest = ( $isHTTPS ? 'https://' : 'http://' ) .
98: $_SERVER["SERVER_NAME"] . $dir . "/";
99:
100: return $dest;
101: }
102:
103: /**
104: * Extract NIC families and associated ROM PCI IDs from the src/bin/NIC file.
105: *
106: * $src_dir must contain the path of the iPXE src directory for this build
107: *
108: * @return array[0] array $new_nics
109: * @return array[1] array $roms
110: */
111: function parse_nic_file ()
112: {
113: global $src_dir;
114:
115: $fd = fopen ( "$src_dir/bin/NIC", "r" );
116: if ( ! $fd ) {
117: die ( "Missing src/bin/NIC file. 'make bin/NIC'" );
118: }
119:
120: $nics = array ();
121: $roms = array ();
122: $nic = "";
123:
124: while ( !feof ( $fd ) ) {
125:
126: $line = trim ( fgets ( $fd, 200 ) );
127:
128: $first_eight_chars = substr ( $line, 0, 8 );
129: settype ( $first_eight_chars, "string" );
130:
131: if ( strpos ( $first_eight_chars, "family" ) === 0 ) {
132:
133: // get pathname of NIC driver
134: list ( $dummy, $nic ) = split( "[ \t]+", $line );
135: settype ( $nic, "string" );
136:
137: // extract filename name of driver from pathname
138: $nic = substr ( $nic, strrpos ( $nic, "/" ) + 1,
139: strlen ( $nic ) - strrpos ( $nic, "/" ) + 1 );
140:
141: $nics[$nic] = $nic;
142:
143: // For each ISA NIC, there can only be one ROM variant
144: $roms[$nic] = $nic;
145: }
146:
147: // If the first 8 digits of the line are hex digits
148: // add this rom to the current nic family.
149:
150: if ( ( strlen ( $first_eight_chars ) == 8 )
151: && ( ctype_xdigit ( $first_eight_chars ) )
152: && ( $nic != "" ) ) {
153:
154: $roms[$first_eight_chars] = $nic;
155: }
156: }
157: fclose ( $fd );
158:
159: // put most NICs in nice alpha order for menu
160: ksort ( $nics );
161:
162: // add special cases to the top
163:
164: $new_nics = array ( "all-drivers" => "ipxe",
165: "undionly" => "undionly",
166: "undi" => "undi",
167: );
168:
169: foreach ( $nics as $key => $value ) {
170: // skip the undi driver
171: if ( $key != "undi" ) {
172: $new_nics[$key] = $value;
173: }
174: }
175:
176: return array ( $new_nics, $roms );
177: }
178:
179: ////
180: // HTML form utility functions
181: ////
182:
183: /**
184: * Return html code to create hidden form input fields
185: *
186: * @param string $flag name of form variable to set
187: * @param string $value value to give form variable
188: *
189: * @return string html code for given hidden form input field
190: */
191: function hidden ( $flag, $value )
192: {
193: $value = htmlentities ( $value );
194: return "<input type=\"hidden\" value=\"$value\" name=\"$flag\"></input>";
195: }
196:
197: /**
198: * Return html code to create checkbox form input fields
199: *
200: * @param string $flag name of form variable to set
201: * @param string $value "on" means box should be checked
202: *
203: * @return string html code for given hidden form input field
204: */
205: function checkbox ( $flag, $value )
206: {
207: return "<input type=\"checkbox\" value=\"on\" name=\"$flag\"" .
208: ($value == "on" ? " checked>" : ">" );
209: }
210:
211: /**
212: * Return html code to create text form input fields
213: *
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
217: *
218: * @return string html code for given text input field
219: */
220: function textbox ( $flag, $value, $size )
221: {
222: $value = htmlentities ( $value );
223: return "<input type=\"text\" size=\"$size\" value=\"$value\" name=\"$flag\">";
224: }
225:
226: /**
227: * Return html code to create textarea form fields
228: *
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
233: *
234: * @return string html code for given textarea input field
235: */
236: function textarea ( $flag, $value, $rows, $cols )
237: {
238: $value = htmlentities ( $value );
239: return "<textarea name=\"$flag\" rows=\"$rows\" cols=\"$cols\">"
240: . $value . "</textarea>";
241: }
242:
243: /**
244: * Return html code to create select (menu) form fields
245: *
246: * Use array of strings as menu choices
247: *
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
251: *
252: * @return string html code for given select (menu) input field
253: */
254: function menubox ( $name, $options, $value )
255: {
256: $s="<select name=\"$name\">";
257:
258: foreach ( $options as $ignore => $option ) {
259: if ( !$value ) $value = $option;
260: $s .= "<option" . ( $option == $value ? " selected>" : ">" ) .
261: htmlentities ( $option ) . "</option>";
262: }
263: return $s . "</select>";
264: }
265:
266: /**
267: * Return html code to create select (menu) form fields
268: *
269: * Use indices of array of strings as menu choices rather than
270: * the values pointed to by the indicies.
271: *
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
275: *
276: * @return string html code for given select (menu) input field
277: */
278: function keys_menubox ( $name, $options, $value )
279: {
280: $s="<select name=\"$name\">";
281:
282: foreach ( $options as $option => $ignore ) {
283: if ( !$value ) $value = $option;
284: $s .= "<option" . ( $option == $value ? " selected>" : ">" ) .
285: htmlentities ( $option ) . "</option>";
286: }
287: return $s . "</select>";
288: }
289:
290: ////
291: // Flag (compile option) handling functions
292: ////
293:
294: /**
295: * Return default compile options (flags)
296: *
297: * Initial compile options are in a global called $flag_table.
298: * Create and return an array containing the ones we want.
299: *
300: * @return array default compile options (flags)
301: */
302: function default_flags ()
303: {
304: global $flag_table;
305:
306: $flags = array ();
307:
308: foreach ( $flag_table as $key => $props ) {
309:
310: $flag = $props["flag"];
311: $type = $props["type"];
312:
313: // Fields like headers have no "value" property
314: if ( isset ( $props["value"] ) ) {
315: $flags[$flag] = $props["value"];
316: }
317: }
318: return $flags;
319: }
320:
321: /**
322: * Return combination of default and user compile options (flags)
323: *
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.
328: *
329: * @return array combined default and user supplied compile options (flags)
330: */
331: function get_flags ()
332: {
333: global $flag_table;
334:
335: $flags = default_flags ();
336:
337: if ( ! isset ( $_POST["use_flags"] ) )
338: return $flags;
339:
340: foreach ( $flag_table as $key => $props ) {
341:
342: $flag = $props["flag"];
343: $type = $props["type"];
344:
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];
350: }
351: }
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";
360: }
361: }
362: return $flags;
363: }
364:
365: /**
366: * Output given value in appropriate format for iPXE config file
367: *
368: * iPXE config/*.h files use C pre-processor syntax. Output the given
369: * compile option in a format appropriate to its type
370: *
371: * @param string $key index into $flag_table for given compile option
372: * @param string $value value we wish to set compile option to
373: *
374: * @return string code to set compile option to given value
375: */
376: function pprint_flag ( $key, $value )
377: {
378: global $flag_table;
379:
380: // Determine type of given compile option (flag)
381: $type = $flag_table[$key]["type"];
382: $s = "";
383:
384: if ( $type == "on/off" && $value == "on" ) {
385: $s = "#define $key";
386: } else if ( $type == "on/off" && $value != "on" ) {
387: $s = "#undef $key";
388: } else if ( $type == "string" ) {
389: $s = ( "#define $key \"" . cleanstring ( $value ) . "\"" );
390: } else if ($type == "qstring" ) {
391: $s = ( "#define $key \\\"" . cleanstring ( $value ) . "\\\"" );
392: } else {
393: $s = "#define $key " . cleanstring ( $value );
394: }
395:
396: return $s;
397: }
398:
399: /**
400: * Output html code to display all compile options as a table
401: *
402: * @param array $flags array of compile options
403: *
404: * @return void
405: */
406: function echo_flags ( $flags )
407: {
408: global $flag_table;
409:
410: echo "<table>\n";
411:
412: foreach ( $flag_table as $key => $props ) {
413:
414: // Hide parameters from users that should not be changed.
415: $hide_from_user = isset ( $props["hide_from_user"] ) ? $props["hide_from_user"] : "no";
416:
417: $flag = $props["flag"];
418: $type = $props["type"];
419:
420: $value = isset ( $flags[$flag] ) ? $flags[$flag] : '';
421:
422: if ( $hide_from_user == "yes" ) {
423:
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 );
428: }
429:
430: } else {
431:
432: // Flag (iPXE compile option) should be displayed to user
433:
434: if ( $type == "header" ) {
435:
436: $label = $props["label"];
437: echo "<td colspan=2><hr><h3>$label</h3><hr></td>";
438:
439: } else if ($type == "on/off" ) {
440:
441: echo "<td>", checkbox ( $flag, $value ), "</td><td><strong>$flag</strong></td>";
442:
443: } else { // don't display checkbox for non-on/off flags
444:
445: echo "<td> </td><td><strong>$flag: </strong>";
446:
447: if ($type == "choice" ) {
448: $options = $props["options"];
449: echo menubox($flag, $options, $value);
450:
451: } else {
452:
453: echo textbox($flag, $value, ($type == "integer" ||
454: $type == "integer-hex"
455: ? 7 : 25));
456: }
457: echo "</td>";
458: }
459: echo "</tr>\n";
460:
461: if ( $type != "header" ) {
462: echo "<tr><td> </td>";
463: echo "<td>\n";
464: if ( is_file ( "doc/$flag.html" ) ) {
465: include_once "doc/$flag.html";
466: }
467: echo "\n</td></tr>\n";
468: }
469: }
470: }
471: echo "</table>";
472: }
473:
474: /**
475: * Return an array of configuration sections used in all compile options
476: *
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.
480: *
481: * @return array an array of strings representing all unique cfgsec values
482: * found in $flag_table
483: */
484: function get_flag_cfgsecs ()
485: {
486: global $flag_table;
487: $cfgsecs = array ();
488:
489: foreach ( $flag_table as $key => $props ) {
490: if ( isset ( $props['cfgsec'] ) ) {
491: $cfgsec = $props["cfgsec"];
492: $cfgsecs[$cfgsec] = $cfgsec;
493: }
494: }
495: return $cfgsecs;
496: }
497:
498: ////
499: // File and directory handling functions
500: ////
501:
502: /**
503: * Create a copy of a given source directory to a given destination
504: *
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
508: * it generates.
509: *
510: * @param string $src source directory
511: * @param string $dst destination directory
512: * @param string $prefix string to append to directory created
513: *
514: * @return string absolute path to destination directory
515: */
516: function mktempcopy ( $src, $dst, $prefix )
517: {
518: if ( $src[0] != "/" ) {
519: $src = dirname ( $_SERVER['SCRIPT_FILENAME'] ) . "/" . $src;
520: }
521:
522: // Create a file in the given destination directory with a unique name
523: $dir = tempnam ( $dst, $prefix );
524:
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.
527: unlink ( $dir );
528:
529: exec ( "/bin/cp -a '$src' '$dir' 2>&1", $cpytxt, $status );
530:
531: if ( $status != 0 ) {
532: die ( "src directory copy failed!" );
533: }
534: return $dir;
535: }
536:
537: /**
538: * Write iPXE config files based on value of given flags
539: *
540: * iPXE compile options are stored in src/config/*.h .
541: * We write out a config file for each set of options.
542: *
543: * @param string $config_dir directory to write .h files to
544: * @param array $flags array of compile options for this build
545: *
546: * @return void
547: */
548: function write_ipxe_config_files ( $config_dir, $flags )
549: {
550: global $flag_table;
551:
552: $cfgsecs = get_flag_cfgsecs ();
553:
554: foreach ( $cfgsecs as $cfgsec ) {
555:
556: $fname = $config_dir . "/" . $cfgsec . ".h";
557:
558: $fp = fopen ( $fname, "wb" );
559: if ( $fp <= 0 ) {
560: die ( "Unable to open $fname file for output!" );
561: }
562:
563: $ifdef_secname = "CONFIG_" . strtoupper ( $cfgsec ) . "_H";
564:
565: fwrite ( $fp, "#ifndef ${ifdef_secname}\n" );
566: fwrite ( $fp, "#define ${ifdef_secname}\n" );
567: fwrite ( $fp, "#include <config/defaults.h>\n" );
568:
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" );
573: }
574: }
575: fwrite ( $fp, "#endif /* ${ifdef_secname} */\n" );
576: fclose ( $fp );
577: }
578: }
579:
580: /**
581: * Output a string to a file
582: *
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.
585: *
586: * @param string $fname pathname of file to output string to
587: * @param string $ftext text to output to file
588: *
589: * @return void
590: */
591: function write_file_from_string ( $fname, $ftext )
592: {
593: $fp = fopen ( $fname, "wb" );
594: if ( ! $fp ) {
595: die ( "Unable to open $fname file for output!" );
596: }
597: fwrite ( $fp, $ftext );
598: fclose ( $fp );
599: }
600:
601: /**
602: * Delete a file or recursively delete a directory tree
603: *
604: * @param string $file_or_dir_name name of file or directory to delete
605: * @return bool Returns TRUE on success, FALSE on failure
606: */
607: function rm_file_or_dir ( $file_or_dir_name )
608: {
609: if ( ! file_exists ( $file_or_dir_name ) ) {
610: return false;
611: }
612:
613: if ( is_file ( $file_or_dir_name ) || is_link ( $file_or_dir_name ) ) {
614: return unlink ( $file_or_dir_name );
615: }
616:
617: $dir = dir ( $file_or_dir_name );
618: while ( ( $dir_entry = $dir->read () ) !== false ) {
619:
620: if ( $dir_entry == '.' || $dir_entry == '..') {
621: continue;
622: }
623: rm_file_or_dir ( $file_or_dir_name . '/' . $dir_entry );
624: }
625: $dir->close();
626:
627: return rmdir ( $file_or_dir_name );
628: }
629:
630: ////
631: // Debugging functions
632: ////
633:
634: /**
635: * Emit html code to display given array of compile options (flags)
636: *
637: * @param array $flags array of compile options for this build
638: *
639: * @return void
640: */
641: function show_flags ( $flags )
642: {
643: echo ( "\$flags contains " . count ( $flags ) . " elements:" . "<br>" );
644:
645: foreach ( $flags as $key => $flag ) {
646: echo ( "\$flags[" . $key . "]=" . "\"$flag\"" . "<br>" );
647: }
648: }
649:
650: /**
651: * Emit HTML code to display default array of compile options (flags)
652: *
653: * $flag_table contains default compile options and properties. This
654: * routine outputs HTML code to display all properties of $flag_table.
655: *
656: * @return void
657: */
658: function dump_flag_table ()
659: {
660: global $flag_table;
661:
662: echo ( "\$flag_table contains " . count ( $flag_table ) . " elements:" . "<br>" );
663:
664: foreach ( $flag_table as $key => $props ) {
665: print ( "flag_table[" . $key . "] = " . "<br>" );
666:
667: foreach ( $props as $key2 => $props2 ) {
668: print ( " " . $key2 . " = " . $props2 . "<br>" );
669: }
670: }
671: }
672:
673: // Parse src/bin/NIC file
674: list ( $nics, $roms ) = parse_nic_file ();
675:
676: // For emacs:
677: // Local variables:
678: // c-basic-offset: 4
679: // c-indent-level: 4
680: // tab-width: 4
681: // End:
682:
683: ?>
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.