[rhine] Fix usage of mii_read()
[ipxe.git] / contrib / rom-o-matic / utils.php
1 <?php // -*- Mode: PHP; -*-
2
3 /**
4 * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
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 list ( $dummy, $nic ) = explode("\t", $line);
136 settype ( $nic, "string" );
137
138 // extract filename name of driver from pathname
139 $nic = substr ( $nic, strrpos ( $nic, "/" ) + 1,
140 strlen ( $nic ) - strrpos ( $nic, "/" ) + 1 );
141
142 $nics[$nic] = $nic;
143
144 // For each ISA NIC, there can only be one ROM variant
145 $roms[$nic] = $nic;
146 }
147
148 // If the first 8 digits of the line are hex digits
149 // add this rom to the current nic family.
150
151 if ( ( strlen ( $first_eight_chars ) == 8 )
152 && ( ctype_xdigit ( $first_eight_chars ) )
153 && ( $nic != "" ) ) {
154
155 $roms[$first_eight_chars] = $nic;
156 }
157 }
158 fclose ( $fd );
159
160 // put most NICs in nice alpha order for menu
161 ksort ( $nics );
162
163 // add special cases to the top
164
165 $new_nics = array ( "all-drivers" => "ipxe",
166 "undionly" => "undionly",
167 "undi" => "undi",
168 );
169
170 foreach ( $nics as $key => $value ) {
171 // skip the undi driver
172 if ( $key != "undi" ) {
173 $new_nics[$key] = $value;
174 }
175 }
176
177 return array ( $new_nics, $roms );
178 }
179
180 ////
181 // HTML form utility functions
182 ////
183
184 /**
185 * Return html code to create hidden form input fields
186 *
187 * @param string $flag name of form variable to set
188 * @param string $value value to give form variable
189 *
190 * @return string html code for given hidden form input field
191 */
192 function hidden ( $flag, $value )
193 {
194 $value = htmlentities ( $value );
195 return "<input type=\"hidden\" value=\"$value\" name=\"$flag\"></input>";
196 }
197
198 /**
199 * Return html code to create checkbox form input fields
200 *
201 * @param string $flag name of form variable to set
202 * @param string $value "on" means box should be checked
203 *
204 * @return string html code for given hidden form input field
205 */
206 function checkbox ( $flag, $value )
207 {
208 return "<input type=\"checkbox\" value=\"on\" name=\"$flag\"" .
209 ($value == "on" ? " checked>" : ">" );
210 }
211
212 /**
213 * Return html code to create text form input fields
214 *
215 * @param string $flag name of form variable to set
216 * @param string $value initial contents of field
217 * @param string $size size in characters of text box
218 *
219 * @return string html code for given text input field
220 */
221 function textbox ( $flag, $value, $size )
222 {
223 $value = htmlentities ( $value );
224 return "<input type=\"text\" size=\"$size\" value=\"$value\" name=\"$flag\">";
225 }
226
227 /**
228 * Return html code to create textarea form fields
229 *
230 * @param string $flag name of form variable to set
231 * @param string $value initial contents of textarea
232 * @param string $rows height of text area in rows
233 * @param string $cols width of text area in columns
234 *
235 * @return string html code for given textarea input field
236 */
237 function textarea ( $flag, $value, $rows, $cols )
238 {
239 $value = htmlentities ( $value );
240 return "<textarea name=\"$flag\" rows=\"$rows\" cols=\"$cols\">"
241 . $value . "</textarea>";
242 }
243
244 /**
245 * Return html code to create select (menu) form fields
246 *
247 * Use array of strings as menu choices
248 *
249 * @param string $flag name of form variable to set
250 * @param array $options array of strings representing choices
251 * @param string $value value of choice to select in menu
252 *
253 * @return string html code for given select (menu) input field
254 */
255 function menubox ( $name, $options, $value )
256 {
257 $s="<select name=\"$name\">";
258
259 foreach ( $options as $ignore => $option ) {
260 if ( !$value ) $value = $option;
261 $s .= "<option" . ( $option == $value ? " selected>" : ">" ) .
262 htmlentities ( $option ) . "</option>";
263 }
264 return $s . "</select>";
265 }
266
267 /**
268 * Return html code to create select (menu) form fields
269 *
270 * Use indices of array of strings as menu choices rather than
271 * the values pointed to by the indicies.
272 *
273 * @param string $flag name of form variable to set
274 * @param array $options array of strings representing choices
275 * @param string $value value of choice to select in menu
276 *
277 * @return string html code for given select (menu) input field
278 */
279 function keys_menubox ( $name, $options, $value )
280 {
281 $s="<select name=\"$name\">";
282
283 foreach ( $options as $option => $ignore ) {
284 if ( !$value ) $value = $option;
285 $s .= "<option" . ( $option == $value ? " selected>" : ">" ) .
286 htmlentities ( $option ) . "</option>";
287 }
288 return $s . "</select>";
289 }
290
291 ////
292 // Flag (compile option) handling functions
293 ////
294
295 /**
296 * Return default compile options (flags)
297 *
298 * Initial compile options are in a global called $flag_table.
299 * Create and return an array containing the ones we want.
300 *
301 * @return array default compile options (flags)
302 */
303 function default_flags ()
304 {
305 global $flag_table;
306
307 $flags = array ();
308
309 foreach ( $flag_table as $key => $props ) {
310
311 $flag = $props["flag"];
312 $type = $props["type"];
313
314 // Fields like headers have no "value" property
315 if ( isset ( $props["value"] ) ) {
316 $flags[$flag] = $props["value"];
317 }
318 }
319 return $flags;
320 }
321
322 /**
323 * Return combination of default and user compile options (flags)
324 *
325 * Initial compile options are in a global called $flag_table.
326 * Compile options may have been changed via form input. We return
327 * an array with either the default value of each option or a user
328 * supplied value from form input.
329 *
330 * @return array combined default and user supplied compile options (flags)
331 */
332 function get_flags ()
333 {
334 global $flag_table;
335
336 $flags = default_flags ();
337
338 if ( ! isset ( $_POST["use_flags"] ) )
339 return $flags;
340
341 foreach ( $flag_table as $key => $props ) {
342
343 $flag = $props["flag"];
344 $type = $props["type"];
345
346 if ( isset ( $_POST["$flag"] ) ) {
347 $flags[$flag] = $_POST["$flag"];
348 if ( $type == "integer-hex" ) {
349 if ( strtolower ( substr ( $flags[$flag], 0, 2 ) ) != "0x" ) {
350 $flags[$flag] = "0x" . $flags[$flag];
351 }
352 }
353 } else if ( $type == "on/off" ) {
354 // Unchecked checkboxes don't pass any POST value
355 // so we must check for them specially. At this
356 // point we know that there is no $_POST value set
357 // for this option. If it is a checkbox, this means
358 // it is unchecked, so record that in $flags so we
359 // can later generate an #undef for this option.
360 $flags[$flag] = "off";
361 }
362 }
363 return $flags;
364 }
365
366 /**
367 * Output given value in appropriate format for iPXE config file
368 *
369 * iPXE config/*.h files use C pre-processor syntax. Output the given
370 * compile option in a format appropriate to its type
371 *
372 * @param string $key index into $flag_table for given compile option
373 * @param string $value value we wish to set compile option to
374 *
375 * @return string code to set compile option to given value
376 */
377 function pprint_flag ( $key, $value )
378 {
379 global $flag_table;
380
381 // Determine type of given compile option (flag)
382 $type = $flag_table[$key]["type"];
383 $s = "";
384
385 if ( $type == "on/off" && $value == "on" ) {
386 $s = "#define $key";
387 } else if ( $type == "on/off" && $value != "on" ) {
388 $s = "#undef $key";
389 } else if ( $type == "string" ) {
390 $s = ( "#define $key \"" . cleanstring ( $value ) . "\"" );
391 } else if ($type == "qstring" ) {
392 $s = ( "#define $key \\\"" . cleanstring ( $value ) . "\\\"" );
393 } else {
394 $s = "#define $key " . cleanstring ( $value );
395 }
396
397 return $s;
398 }
399
400 /**
401 * Output html code to display all compile options as a table
402 *
403 * @param array $flags array of compile options
404 *
405 * @return void
406 */
407 function echo_flags ( $flags )
408 {
409 global $flag_table;
410
411 echo "<table>\n";
412
413 foreach ( $flag_table as $key => $props ) {
414
415 // Hide parameters from users that should not be changed.
416 $hide_from_user = isset ( $props["hide_from_user"] ) ? $props["hide_from_user"] : "no";
417
418 $flag = $props["flag"];
419 $type = $props["type"];
420
421 $value = isset ( $flags[$flag] ) ? $flags[$flag] : '';
422
423 if ( $hide_from_user == "yes" ) {
424
425 // Hidden flags cannot not be set by the user. We use hidden form
426 // fields to keep them at their default values.
427 if ( $type != "header" ) {
428 echo hidden ( $flag, $value );
429 }
430
431 } else {
432
433 // Flag (iPXE compile option) should be displayed to user
434
435 if ( $type == "header" ) {
436
437 $label = $props["label"];
438 echo "<td colspan=2><hr><h3>$label</h3><hr></td>";
439
440 } else if ($type == "on/off" ) {
441
442 echo "<td>", checkbox ( $flag, $value ), "</td><td><strong>$flag</strong></td>";
443
444 } else { // don't display checkbox for non-on/off flags
445
446 echo "<td>&nbsp;</td><td><strong>$flag: </strong>";
447
448 if ($type == "choice" ) {
449 $options = $props["options"];
450 echo menubox($flag, $options, $value);
451
452 } else {
453
454 echo textbox($flag, $value, ($type == "integer" ||
455 $type == "integer-hex"
456 ? 7 : 25));
457 }
458 echo "</td>";
459 }
460 echo "</tr>\n";
461
462 if ( $type != "header" ) {
463 echo "<tr><td>&nbsp;</td>";
464 echo "<td>\n";
465 if ( is_file ( "doc/$flag.html" ) ) {
466 include_once "doc/$flag.html";
467 }
468 echo "\n</td></tr>\n";
469 }
470 }
471 }
472 echo "</table>";
473 }
474
475 /**
476 * Return an array of configuration sections used in all compile options
477 *
478 * $flag_table, the global list of compile options contains a 'cfgsec'
479 * property for each flag we are interested in. We return a list of
480 * all the unique cfgsec options we find in $flag_table.
481 *
482 * @return array an array of strings representing all unique cfgsec values
483 * found in $flag_table
484 */
485 function get_flag_cfgsecs ()
486 {
487 global $flag_table;
488 $cfgsecs = array ();
489
490 foreach ( $flag_table as $key => $props ) {
491 if ( isset ( $props['cfgsec'] ) ) {
492 $cfgsec = $props["cfgsec"];
493 $cfgsecs[$cfgsec] = $cfgsec;
494 }
495 }
496 return $cfgsecs;
497 }
498
499 ////
500 // File and directory handling functions
501 ////
502
503 /**
504 * Create a copy of a given source directory to a given destination
505 *
506 * Since we are going to modify the source directory, we create a copy
507 * of the directory with a unique name in the given destination directory.
508 * We supply a prefix for the tempnam call to prepend to the random filename
509 * it generates.
510 *
511 * @param string $src source directory
512 * @param string $dst destination directory
513 * @param string $prefix string to append to directory created
514 *
515 * @return string absolute path to destination directory
516 */
517 function mktempcopy ( $src, $dst, $prefix )
518 {
519 if ( $src[0] != "/" ) {
520 $src = dirname ( $_SERVER['SCRIPT_FILENAME'] ) . "/" . $src;
521 }
522
523 // Create a file in the given destination directory with a unique name
524 $dir = tempnam ( $dst, $prefix );
525
526 // Delete the file just created, since it would interfere with the copy we
527 // are about to do. We only care that the dir name we copy to is unique.
528 unlink ( $dir );
529
530 exec ( "/bin/cp -a '$src' '$dir' 2>&1", $cpytxt, $status );
531
532 if ( $status != 0 ) {
533 die ( "src directory copy failed!" );
534 }
535 return $dir;
536 }
537
538 /**
539 * Write iPXE config files based on value of given flags
540 *
541 * iPXE compile options are stored in src/config/*.h .
542 * We write out a config file for each set of options.
543 *
544 * @param string $config_dir directory to write .h files to
545 * @param array $flags array of compile options for this build
546 *
547 * @return void
548 */
549 function write_ipxe_config_files ( $config_dir, $flags )
550 {
551 global $flag_table;
552
553 $cfgsecs = get_flag_cfgsecs ();
554
555 foreach ( $cfgsecs as $cfgsec ) {
556
557 $fname = $config_dir . "/" . $cfgsec . ".h";
558
559 $fp = fopen ( $fname, "wb" );
560 if ( $fp <= 0 ) {
561 die ( "Unable to open $fname file for output!" );
562 }
563
564 $ifdef_secname = "CONFIG_" . strtoupper ( $cfgsec ) . "_H";
565
566 fwrite ( $fp, "#ifndef ${ifdef_secname}\n" );
567 fwrite ( $fp, "#define ${ifdef_secname}\n" );
568 fwrite ( $fp, "#include <config/defaults.h>\n" );
569
570 foreach ( $flags as $key => $value ) {
571 // When the flag matches this section name, write it out
572 if ( $flag_table[$key]["cfgsec"] == $cfgsec ) {
573 fwrite ( $fp, pprint_flag ( $key, $value ) . "\n" );
574 }
575 }
576 fwrite ( $fp, "#endif /* ${ifdef_secname} */\n" );
577 fclose ( $fp );
578 }
579 }
580
581 /**
582 * Output a string to a file
583 *
584 * Output a given string to a given pathname. The file will be created if
585 * necessary, and the string will replace the file's contents in all cases.
586 *
587 * @param string $fname pathname of file to output string to
588 * @param string $ftext text to output to file
589 *
590 * @return void
591 */
592 function write_file_from_string ( $fname, $ftext )
593 {
594 $fp = fopen ( $fname, "wb" );
595 if ( ! $fp ) {
596 die ( "Unable to open $fname file for output!" );
597 }
598 fwrite ( $fp, $ftext );
599 fclose ( $fp );
600 }
601
602 /**
603 * Delete a file or recursively delete a directory tree
604 *
605 * @param string $file_or_dir_name name of file or directory to delete
606 * @return bool Returns TRUE on success, FALSE on failure
607 */
608 function rm_file_or_dir ( $file_or_dir_name )
609 {
610 if ( ! file_exists ( $file_or_dir_name ) ) {
611 return false;
612 }
613
614 if ( is_file ( $file_or_dir_name ) || is_link ( $file_or_dir_name ) ) {
615 return unlink ( $file_or_dir_name );
616 }
617
618 $dir = dir ( $file_or_dir_name );
619 while ( ( $dir_entry = $dir->read () ) !== false ) {
620
621 if ( $dir_entry == '.' || $dir_entry == '..') {
622 continue;
623 }
624 rm_file_or_dir ( $file_or_dir_name . '/' . $dir_entry );
625 }
626 $dir->close();
627
628 return rmdir ( $file_or_dir_name );
629 }
630
631 ////
632 // Debugging functions
633 ////
634
635 /**
636 * Emit html code to display given array of compile options (flags)
637 *
638 * @param array $flags array of compile options for this build
639 *
640 * @return void
641 */
642 function show_flags ( $flags )
643 {
644 echo ( "\$flags contains " . count ( $flags ) . " elements:" . "<br>" );
645
646 foreach ( $flags as $key => $flag ) {
647 echo ( "\$flags[" . $key . "]=" . "\"$flag\"" . "<br>" );
648 }
649 }
650
651 /**
652 * Emit HTML code to display default array of compile options (flags)
653 *
654 * $flag_table contains default compile options and properties. This
655 * routine outputs HTML code to display all properties of $flag_table.
656 *
657 * @return void
658 */
659 function dump_flag_table ()
660 {
661 global $flag_table;
662
663 echo ( "\$flag_table contains " . count ( $flag_table ) . " elements:" . "<br>" );
664
665 foreach ( $flag_table as $key => $props ) {
666 print ( "flag_table[" . $key . "] = " . "<br>" );
667
668 foreach ( $props as $key2 => $props2 ) {
669 print ( "&nbsp;&nbsp;&nbsp;" . $key2 . " = " . $props2 . "<br>" );
670 }
671 }
672 }
673
674 // Parse src/bin/NIC file
675 list ( $nics, $roms ) = parse_nic_file ();
676
677 // For emacs:
678 // Local variables:
679 // c-basic-offset: 4
680 // c-indent-level: 4
681 // tab-width: 4
682 // End:
683
684 ?>