summaryrefslogtreecommitdiffstats
path: root/modules-available/serversetup-bwlp-pxelinux/inc/ipxe.inc.php
blob: c42de80b770203218c5c243b85fa417b503eb54c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
<?php


class Ipxe
{

	/**
	 * Takes a (partial) pxelinux menu and parses it into
	 * a PxeMenu object.
	 * @param string $input The pxelinux menu to parse
	 * @return PxeMenu the parsed menu
	 */
	public static function parsePxeLinux($input)
	{
		/*
		LABEL openslx-debug
			MENU LABEL ^bwLehrpool-Umgebung starten (nosplash, debug)
			KERNEL http://IPADDR/boot/default/kernel
			INITRD http://IPADDR/boot/default/initramfs-stage31
			APPEND slxbase=boot/default
			IPAPPEND 3
		*/
		$menu = new PxeMenu;
		$sectionPropMap = [
			'menu label' => ['string', 'title'],
			'menu default' => ['true', 'isDefault'],
			'menu hide' => ['true', 'isHidden'],
			'menu disabled' => ['true', 'isDisabled'],
			'menu indent' => ['int', 'indent'],
			'kernel' => ['string', 'kernel'],
			'initrd' => ['string', 'initrd'],
			'append' => ['string', 'append'],
			'ipappend' => ['int', 'ipAppend'],
			'localboot' => ['int', 'localBoot'],
		];
		$globalPropMap = [
			'timeout' => ['int', 'timeoutMs', 100],
			'totaltimeout' => ['int', 'totalTimeoutMs', 100],
			'menu title' => ['string', 'title'],
			'menu clear' => ['true', 'menuClear'],
			'menu immediate' => ['true', 'immediateHotkeys'],
			'ontimeout' => ['string', 'timeoutLabel'],
		];
		$lines = preg_split('/[\r\n]+/', $input);
		$section = null;
		$count = count($lines);
		for ($li = 0; $li < $count; ++$li) {
			$line =& $lines[$li];
			if (!preg_match('/^\s*([^m]\S*|menu\s+\S+)(\s+.*?|)\s*$/i', $line, $out))
				continue;
			$key = trim($out[1]);
			$key = strtolower($key);
			$key = preg_replace('/\s+/', ' ', $key);
			if ($key === 'label') {
				if ($section !== null) {
					$menu->sections[] = $section;
				}
				$section = new PxeSection($out[2]);
			} elseif ($key === 'menu separator') {
				if ($section !== null) {
					$menu->sections[] = $section;
					$section = null;
				}
				$menu->sections[] = new PxeSection(null);
			} elseif (self::handleKeyword($key, $out[2], $globalPropMap, $menu)) {
				continue;
			} elseif ($section === null) {
				continue;
			} elseif ($key === 'text' && strtolower($out[2]) === 'help') {
				$text = '';
				while (++$li < $count) {
					$line =& $lines[$li];
					if (strtolower(trim($line)) === 'endtext')
						break;
					$text .= $line . "\n";
				}
				$section->helpText = $text;
			} elseif (self::handleKeyword($key, $out[2], $sectionPropMap, $section)) {
				continue;
			}
		}
		if ($section !== null) {
			$menu->sections[] = $section;
		}
		return $menu;
	}

	/**
	 * Check if keyword is valid and if so, add its interpreted value
	 * to the given object. The map to look up the keyword has to be passed
	 * as well as the object to set the value in. Map and object should
	 * obviously match.
	 * @param string $key keyword of parsed line
	 * @param string $val raw value of currently parsed line (empty if not present)
	 * @param array $map Map in which $key is looked up as key
	 * @param PxeMenu|PxeSection The object to set the parsed and sanitized value in
	 * @return bool true if the value was found in the map (and set in the object), false otherwise
	 */
	private static function handleKeyword($key, $val, $map, $object)
	{
		if (!isset($map[$key]))
			return false;
		$opt = $map[$key];
		// opt[0] is the type the value should be cast to; special case "true" means
		// this is a bool option that will be set as soon as the keyword is present,
		// as it doesn't have any parameters
		if ($opt[0] === 'true') {
			$val = true;
		} else {
			settype($val, $opt[0]);
		}
		// If opt[2] is present it's a multiplier for the value
		if (isset($opt[2])) {
			$val *= $opt[2];
		}
		$object->{$opt[1]} = $val;
		return true;
	}

}

/**
 * Class representing a parsed pxelinux menu. Members
 * will be set to their annotated type if present or
 * be null otherwise, except for present-only boolean
 * options, which will default to false.
 */
class PxeMenu
{
	/**
	 * @var string menu title, shown at the top of the menu
	 */
	public $title;
	/**
	 * @var int initial timeout after which $timeoutLabel would be executed
	 */
	public $timeoutMs;
	/**
	 * @var int if the user canceled the timeout by pressing a key, this timeout would still eventually
	 *          trigger and launch the $timeoutLabel section
	 */
	public $totalTimeoutMs;
	/**
	 * @var string label of section which will execute if the timeout expires
	 */
	public $timeoutLabel;
	/**
	 * @var bool hide menu and just show background after triggering an entry
	 */
	public $menuClear = false;
	/**
	 * @var bool boot the associated entry directly if its corresponding hotkey is presed instead of just highlighting
	 */
	public $immediateHotkeys = false;
	/**
	 * @var PxeSection[] list of sections the menu contains
	 */
	public $sections = [];
}

/**
 * Class representing a parsed pxelinux menu entry. Members
 * will be set to their annotated type if present or
 * be null otherwise, except for present-only boolean
 * options, which will default to false.
 */
class PxeSection
{
	/**
	 * @var string label used internally in PXEMENU definition to address this entry
	 */
	public $label;
	/**
	 * @var string MENU LABEL of PXEMENU - title of entry displayed to the user
	 */
	public $title;
	/**
	 * @var int Number of spaces to prefix the title with
	 */
	public $indent;
	/**
	 * @var string help text to display when the entry is highlighted
	 */
	public $helpText;
	/**
	 * @var string Kernel to load
	 */
	public $kernel;
	/**
	 * @var string initrd to load for the kernel
	 */
	public $initrd;
	/**
	 * @var string command line options to pass to the kernel
	 */
	public $append;
	/**
	 * @var int IPAPPEND from PXEMENU. Bitmask of valid options 1 and 2.
	 */
	public $ipAppend;
	/**
	 * @var string Password protecting the entry. This is most likely in crypted form.
	 */
	public $passwd;
	/**
	 * @var bool whether this section is marked as default (booted after timeout)
	 */
	public $isDefault = false;
	/**
	 * @var bool Menu entry is not visible (can only be triggered by timeout)
	 */
	public $isHidden = false;
	/**
	 * @var bool Disable this entry, making it unselectable
	 */
	public $isDisabled = false;
	/**
	 * @var int Value of the LOCALBOOT field
	 */
	public $localBoot;

	public function __construct($label) { $this->label = $label; }
}