use inet_ntop, inet_ntop instead of self-made ones
[racktables] / wwwroot / inc / remote.php
CommitLineData
7cb57a03
AA
1<?php
2
cddbb9fd
DO
3# This file is a part of RackTables, a datacenter and server room management
4# framework. See accompanying file "COPYING" for the full copyright and
5# licensing information.
6
1319f245
DO
7# The array below maps availability of particular commands for each particular
8# device breed. Array values are functions implemented in deviceconfig.php, which
9# is not normally included until any of the functions is actually called.
9d3ef879
DO
10$breedfunc = array
11(
12 'ios12-getcdpstatus-main' => 'ios12ReadCDPStatus',
13 'ios12-getlldpstatus-main' => 'ios12ReadLLDPStatus',
14 'ios12-get8021q-main' => 'ios12ReadVLANConfig',
cfc28da9 15 'ios12-get8021q-swports' => 'ios12ReadSwitchPortList',
9d3ef879
DO
16 'ios12-get8021q-top' => 'ios12ScanTopLevel',
17 'ios12-get8021q-readport' => 'ios12PickSwitchportCommand',
18 'ios12-get8021q-readvlan' => 'ios12PickVLANCommand',
19 'ios12-getportstatus-main' => 'ciscoReadInterfaceStatus',
20 'ios12-getmaclist-main' => 'ios12ReadMacList',
21 'ios12-xlatepushq-main' => 'ios12TranslatePushQueue',
22 'ios12-getallconf-main' => 'ios12SpotConfigText',
23 'fdry5-get8021q-main' => 'fdry5ReadVLANConfig',
24 'fdry5-get8021q-top' => 'fdry5ScanTopLevel',
25 'fdry5-get8021q-readvlan' => 'fdry5PickVLANSubcommand',
26 'fdry5-get8021q-readport' => 'fdry5PickInterfaceSubcommand',
27 'fdry5-xlatepushq-main' => 'fdry5TranslatePushQueue',
28 'fdry5-getallconf-main' => 'fdry5SpotConfigText',
29 'vrp53-getlldpstatus-main' => 'vrp5xReadLLDPStatus',
30 'vrp53-get8021q-main' => 'vrp53ReadVLANConfig',
31 'vrp53-get8021q-top' => 'vrp53ScanTopLevel',
32 'vrp53-get8021q-readport' => 'vrp53PickInterfaceSubcommand',
33 'vrp53-getportstatus-main' => 'vrpReadInterfaceStatus',
34 'vrp53-getmaclist-main' => 'vrp53ReadMacList',
35 'vrp53-xlatepushq-main' => 'vrp53TranslatePushQueue',
36 'vrp53-getallconf-main' => 'vrp5xSpotConfigText',
37 'vrp55-getlldpstatus-main' => 'vrp5xReadLLDPStatus',
38 'vrp55-get8021q-main' => 'vrp55Read8021QConfig',
39 'vrp55-getportstatus-main' => 'vrpReadInterfaceStatus',
40 'vrp55-getmaclist-main' => 'vrp55ReadMacList',
41 'vrp55-xlatepushq-main' => 'vrp55TranslatePushQueue',
42 'vrp55-getallconf-main' => 'vrp5xSpotConfigText',
43 'nxos4-getcdpstatus-main' => 'ios12ReadCDPStatus',
44 'nxos4-getlldpstatus-main' => 'nxos4ReadLLDPStatus',
cfc28da9 45 'nxos4-get8021q-main' => 'ios12ReadVLANConfig',
9d3ef879
DO
46 'nxos4-getportstatus-main' => 'ciscoReadInterfaceStatus',
47 'nxos4-getmaclist-main' => 'nxos4ReadMacList',
48 'nxos4-xlatepushq-main' => 'nxos4TranslatePushQueue',
49 'nxos4-getallconf-main' => 'nxos4SpotConfigText',
50 'dlink-get8021q-main' => 'dlinkReadVLANConfig',
51 'dlink-get8021q-top' => 'dlinkScanTopLevel',
52 'dlink-get8021q-pickvlan' => 'dlinkPickVLANCommand',
53 'dlink-getportstatus-main' => 'dlinkReadInterfaceStatus',
54 'dlink-getmaclist-main' => 'dlinkReadMacList',
55 'dlink-xlatepushq-main' => 'dlinkTranslatePushQueue',
56 'linux-get8021q-main' => 'linuxReadVLANConfig',
57 'linux-getportstatus-main' => 'linuxReadInterfaceStatus',
58 'linux-getmaclist-main' => 'linuxReadMacList',
59 'linux-xlatepushq-main' => 'linuxTranslatePushQueue',
60 'xos12-getlldpstatus-main' => 'xos12ReadLLDPStatus',
61 'xos12-get8021q-main' => 'xos12Read8021QConfig',
62 'xos12-xlatepushq-main' => 'xos12TranslatePushQueue',
63 'xos12-getallconf-main' => 'xos12SpotConfigText',
64 'jun10-get8021q-main' => 'jun10Read8021QConfig',
65 'jun10-xlatepushq-main' => 'jun10TranslatePushQueue',
66 'jun10-getallconf-main' => 'jun10SpotConfigText',
1ff39492 67 'jun10-getlldpstatus-main' => 'jun10ReadLLDPStatus',
9d3ef879
DO
68 'ftos8-xlatepushq-main' => 'ftos8TranslatePushQueue',
69 'ftos8-getlldpstatus-main' => 'ftos8ReadLLDPStatus',
70 'ftos8-getmaclist-main' => 'ftos8ReadMacList',
71 'ftos8-getportstatus-main' => 'ftos8ReadInterfaceStatus',
72 'ftos8-get8021q-main' => 'ftos8Read8021QConfig',
73 'ftos8-getallconf-main' => 'ftos8SpotConfigText',
74 'air12-xlatepushq-main' => 'air12TranslatePushQueue',
75 'air12-getallconf-main' => 'ios12SpotConfigText',
76 'eos4-getallconf-main' => 'eos4SpotConfigText',
77 'eos4-getmaclist-main' => 'eos4ReadMacList',
78 'eos4-getportstatus-main' => 'eos4ReadInterfaceStatus',
79 'eos4-getlldpstatus-main' => 'eos4ReadLLDPStatus',
80 'eos4-get8021q-main' => 'eos4Read8021QConfig',
81 'eos4-xlatepushq-main' => 'eos4TranslatePushQueue',
82 'ros11-getallconf-main' => 'ros11SpotConfigText',
83 'ros11-xlatepushq-main' => 'ros11TranslatePushQueue',
84 'ros11-getlldpstatus-main' => 'ros11ReadLLDPStatus',
85 'ros11-getportstatus-main' => 'ros11ReadInterfaceStatus',
86 'ros11-getmaclist-main' => 'ros11ReadMacList',
87 'ros11-get8021q-main' => 'ros11Read8021QConfig',
88 'ros11-get8021q-scantop' => 'ros11Read8021QScanTop',
89 'ros11-get8021q-vlandb' => 'ros11Read8021QVLANDatabase',
90 'ros11-get8021q-readports' => 'ros11Read8021QPorts',
1319f245
DO
91 'iosxr4-xlatepushq-main' => 'iosxr4TranslatePushQueue',
92 'iosxr4-getallconf-main' => 'iosxr4SpotConfigText',
816c0ab8 93 'iosxr4-getlldpstatus-main'=> 'iosxr4ReadLLDPStatus',
9d3ef879
DO
94 'ucs-xlatepushq-main' => 'ucsTranslatePushQueue',
95 'ucs-getinventory-main' => 'ucsReadInventory',
96);
97
f99dd0f0
AA
98define ('MAX_GW_LOGSIZE', 1024*1024); // do not store more than 1 MB of log data
99
bdf2d22a
AA
100$breed_by_swcode = array
101(
90cdae19
AA
102 244 => 'ios12', // IOS 12.0
103 251 => 'ios12', // IOS 12.1
104 252 => 'ios12', // IOS 12.2
105 254 => 'ios12', // IOS 12.0 (router OS)
e2f4f341
AA
106 255 => 'ios12', // IOS 12.1 (router OS)
107 256 => 'ios12', // IOS 12.2 (router OS)
108 257 => 'ios12', // IOS 12.3 (router OS)
7e7327d8 109 258 => 'ios12', // IOS 12.4 (router OS)
90cdae19 110 1901 => 'ios12', // IOS 15.0
7e7327d8 111 1963 => 'ios12', // IOS 15.1 (router OS)
90cdae19
AA
112 963 => 'nxos4', // NX-OS 4.0
113 964 => 'nxos4', // NX-OS 4.1
bdf2d22a 114 1365 => 'nxos4', // NX-OS 4.2
90cdae19 115 1410 => 'nxos4', // NX-OS 5.0
bdf2d22a
AA
116 1411 => 'nxos4', // NX-OS 5.1
117 1809 => 'nxos4', // NX-OS 5.2
118 1643 => 'nxos4', // NX-OS 6.0
90cdae19
AA
119 1352 => 'xos12', // Extreme XOS 12
120 1360 => 'vrp53', // Huawei VRP 5.3
121 1361 => 'vrp55', // Huawei VRP 5.5
122 1369 => 'vrp55', // Huawei VRP 5.7
123 1363 => 'fdry5', // IronWare 5
124 1367 => 'jun10', // 10S
125 1597 => 'jun10', // 10R
126 1598 => 'jun10', // 11R
127 1599 => 'jun10', // 12R
128 1594 => 'ftos8', // Force10 FTOS 8
129 1673 => 'air12', // AIR IOS 12.3
130 1674 => 'air12', // AIR IOS 12.4
131 1675 => 'eos4', // Arista EOS 4
132 1759 => 'iosxr4', // Cisco IOS XR 4.2
133 1786 => 'ros11', // Marvell ROS 1.1
bdf2d22a
AA
134
135 //... linux items added by the loop below
136);
137
138$breed_by_hwcode = array (
139 //... dlink items added by the loop below
140);
141
142$breed_by_mgmtcode = array (
143 1788 => 'ucs',
144);
145
146// add 'linux' items into $breed_by_swcode
147$linux_sw_ranges = array (
148 225,235,
149 418,436,
150 1331,1334,
151 1395,1396,
152 1417,1422,
153);
154for ($i = 0; $i + 1 < count ($linux_sw_ranges); $i += 2)
26d6a121 155 for ($j = $linux_sw_ranges[$i]; $j <= $linux_sw_ranges[$i + 1]; $j++)
bdf2d22a
AA
156 $breed_by_swcode[$j] = 'linux';
157
158// add 'dlink' items into $breed_by_hwcode
159for ($i = 589; $i <= 637; $i++)
160 $breed_by_hwcode[$i] = 'dlink';
161
9d3ef879
DO
162function detectDeviceBreed ($object_id)
163{
bdf2d22a 164 global $breed_by_swcode, $breed_by_hwcode, $breed_by_mgmtcode;
9d3ef879
DO
165 foreach (getAttrValues ($object_id) as $record)
166 if ($record['id'] == 4 and array_key_exists ($record['key'], $breed_by_swcode))
167 return $breed_by_swcode[$record['key']];
168 elseif ($record['id'] == 2 and array_key_exists ($record['key'], $breed_by_hwcode))
169 return $breed_by_hwcode[$record['key']];
170 elseif ($record['id'] == 30 and array_key_exists ($record['key'], $breed_by_mgmtcode))
171 return $breed_by_mgmtcode[$record['key']];
172 return '';
173}
174
2a46177c
DO
175function assertDeviceBreed ($object_id)
176{
177 if ('' == $breed = detectDeviceBreed ($object_id))
178 throw new RTGatewayError ('Cannot determine device breed');
179 return $breed;
180}
181
9d3ef879
DO
182function validBreedFunction ($breed, $command)
183{
184 global $breedfunc;
185 return array_key_exists ("${breed}-${command}-main", $breedfunc);
186}
187
188function assertBreedFunction ($breed, $command)
189{
190 global $breedfunc;
191 if (! validBreedFunction ($breed, $command))
2a46177c
DO
192 throw new RTGatewayError ("unsupported command '${command}' for breed '${breed}'");
193 return $breedfunc["${breed}-${command}-main"];
9d3ef879
DO
194}
195
7cb57a03
AA
196function queryDevice ($object_id, $command)
197{
1be899cd
AA
198 $query = translateDeviceCommands ($object_id, array (array ('opcode' => $command)));
199 if ($command == 'xlatepushq')
200 return $query;
2a46177c
DO
201 $breed = assertDeviceBreed ($object_id);
202 $funcname = assertBreedFunction ($breed, $command);
7cb57a03 203 require_once 'deviceconfig.php';
2a46177c
DO
204 if (! is_callable ($funcname))
205 throw new RTGatewayError ("undeclared function '${funcname}'");
1be899cd
AA
206 $ret = $funcname (queryTerminal ($object_id, $query, FALSE));
207 if (NULL !== ($subst = callHook ('alterDeviceQueryResult', $ret, $object_id, $command)))
208 $ret = $subst;
209 return $ret;
7cb57a03
AA
210}
211
212function translateDeviceCommands ($object_id, $crq, $vlan_names = NULL)
213{
2a46177c
DO
214 $breed = assertDeviceBreed ($object_id);
215 $funcname = assertBreedFunction ($breed, 'xlatepushq');
7cb57a03 216 require_once 'deviceconfig.php';
2a46177c
DO
217 if (! is_callable ($funcname))
218 throw new RTGatewayError ("undeclared function '${funcname}'");
219 return $funcname ($object_id, $crq, $vlan_names);
7cb57a03
AA
220}
221
ee64514c
AA
222// takes settings struct (declared in queryTerminal) and CLI commands (plain text) as input by reference
223// returns an array of command-line parameters to $ref_settings[0]['protocol']
224// this function is called by callHook, so you can override/chain it
225// to customize command-line options to particular gateways.
226function makeGatewayParams ($object_id, $tolerate_remote_errors, /*array(&)*/$ref_settings, /*array(&)*/$ref_commands)
227{
228 $ret = array();
229 $settings = &$ref_settings[0];
230 $commands = &$ref_commands[0];
231
232 switch ($settings['protocol'])
233 {
234 case 'telnet':
235 case 'netcat':
236 // prepend telnet commands by credentials
237 if (isset ($settings['password']))
238 $commands = $settings['password'] . "\n" . $commands;
239 if (isset ($settings['username']))
240 $commands = $settings['username'] . "\n" . $commands;
241 break;
242 case 'ucssdk': # remote XML through a Python backend
243 # UCS in its current implementation besides the terminal_settings() provides
244 # an additional username/password feed through the HTML from. Whenever the
245 # user provides the credentials through the form, use these instead of the
246 # credentials [supposedly] set by terminal_settings().
247 global $script_mode;
248 if ($script_mode != TRUE && ! isCheckSet ('use_terminal_settings'))
249 {
250 $settings['username'] = assertStringArg ('ucs_login');
251 $settings['password'] = assertStringArg ('ucs_password');
252 }
253 foreach (array ('hostname', 'username', 'password') as $item)
254 if (empty ($settings[$item]))
255 throw new RTGatewayError ("${item} not available, check terminal_settings()");
256 $commands = "login ${settings['hostname']} ${settings['username']} ${settings['password']}\n" . $commands;
257 break;
258 }
259
260 $ret = array();
261 switch ($settings['protocol'])
262 {
263 case 'telnet':
264 $params_from_settings['port'] = 'port';
265 $params_from_settings['prompt'] = 'prompt';
266 $params_from_settings['connect-timeout'] = 'connect_timeout';
267 $params_from_settings['timeout'] = 'timeout';
268 $params_from_settings['prompt-delay'] = 'prompt_delay';
269 $params_from_settings[] = $settings['hostname'];
270 break;
271 case 'netcat':
272 $params_from_settings['p'] = 'port';
273 $params_from_settings['w'] = 'timeout';
274 $params_from_settings['b'] = 'ncbin';
275 $params_from_settings[] = $settings['hostname'];
276 break;
277 case 'ssh':
278 $params_from_settings['sudo-user'] = 'sudo_user';
279 $params_from_settings[] = '--';
280 $params_from_settings['p'] = 'port';
281 $params_from_settings['l'] = 'username';
282 $params_from_settings['i'] = 'identity_file';
283 if (isset ($settings['proto']))
284 switch ($settings['proto'])
285 {
286 case 4:
287 $params_from_settings[] = '-4';
288 break;
289 case 6:
290 $params_from_settings[] = '-6';
291 break;
292 default:
293 throw new RTGatewayError ("Proto '${settings['proto']}' is invalid. Valid protocols are: '4', '6'");
294 }
295 if (isset ($settings['connect_timeout']))
296 $params_from_settings[] = '-oConnectTimeout=' . $settings['connect_timeout'];
297 $params_from_settings[] = '-T';
298 $params_from_settings[] = '-oStrictHostKeyChecking=no';
299 $params_from_settings[] = '-oBatchMode=yes';
300 $params_from_settings[] = '-oCheckHostIP=no';
301 $params_from_settings[] = '-oLogLevel=ERROR';
302 $params_from_settings[] = $settings['hostname'];
303 break;
304 default:
305 throw RTGatewayError ("Invalid terminal protocol '${settings['protocol']}' specified");
306 }
307
308 foreach ($params_from_settings as $param_name => $setting_name)
309 if (is_int ($param_name))
310 $ret[] = $setting_name;
311 elseif (isset ($settings[$setting_name]))
312 $ret[$param_name] = $settings[$setting_name];
313
314 return $ret;
315}
316
7cb57a03
AA
317// This function returns a text output received from the device
318// You can override connection settings by implement a callback named 'terminal_settings'.
319// Errors are thrown as exceptions if not $tolerate_remote_errors, and shown as warnings otherwise.
320function queryTerminal ($object_id, $commands, $tolerate_remote_errors = TRUE)
321{
322 $objectInfo = spotEntity ('object', $object_id);
323 $endpoints = findAllEndpoints ($object_id, $objectInfo['name']);
324 if (count ($endpoints) == 0)
325 throw new RTGatewayError ('no management address set');
326 if (count ($endpoints) > 1)
327 throw new RTGatewayError ('cannot pick management address');
328
5d2988fb 329 // telnet prompt and mode specification
7cb57a03
AA
330 switch ($breed = detectDeviceBreed ($object_id))
331 {
77b7e03c 332 case 'ios12':
7a0e9964 333 case 'ftos8':
a3447df9 334 $protocol = 'netcat'; // default is netcat mode
eb03a5eb 335 $prompt = '^(Login|Username|Password): $|^\S+[>#]$|\[[^][]*\]\? $'; // set the prompt in case user would like to specify telnet protocol
ee64514c 336 $commands = "terminal length 0\nterminal no monitor\n" . $commands;
7cb57a03 337 break;
d4a957e0
DO
338 case 'air12':
339 $protocol = 'telnet'; # Aironet IOS is broken
340 $prompt = '^(Username|Password): $|^\S+[>#]$';
ee64514c
AA
341 $commands = "terminal length 0\nterminal no monitor\n" . $commands;
342 break;
343 case 'fdry5':
344 $protocol = 'netcat'; // default is netcat mode
345 $prompt = '^(Login|Username|Password): $|^\S+[>#]$'; // set the prompt in case user would like to specify telnet protocol
346 $commands = "skip-page-display\n" . $commands;
d4a957e0 347 break;
7cb57a03 348 case 'vrp55':
ee64514c
AA
349 $commands = "screen-length 0 temporary\n" . $commands;
350 /* fall-through */
351 case 'vrp53':
5d2988fb 352 $protocol = 'telnet';
338465a8 353 $prompt = '^\[[^[\]]+\]$|^<[^<>]+>$|^(Username|Password):$|(?:\[Y\/N\]|\(Y\/N\)\[[YN]\]):?$';
7cb57a03
AA
354 break;
355 case 'nxos4':
5d2988fb 356 $protocol = 'telnet';
f6943818 357 $prompt = '(^([Ll]ogin|[Pp]assword):|[>#]) $';
ee64514c 358 $commands = "terminal length 0\nterminal no monitor\n" . $commands;
7cb57a03
AA
359 break;
360 case 'xos12':
5d2988fb 361 $protocol = 'telnet';
18997a72 362 $prompt = ': $|\.\d+ # $|\?\s*\([Yy]\/[Nn]\)\s*$';
ee64514c 363 $commands = "disable clipaging\n" . $commands;
7cb57a03
AA
364 break;
365 case 'jun10':
5d2988fb 366 $protocol = 'telnet';
7cb57a03 367 $prompt = '^login: $|^Password:$|^\S+@\S+[>#] $';
ee64514c 368 $commands = "set cli screen-length 0\n" . $commands;
7cb57a03 369 break;
85703049
DO
370 case 'eos4':
371 $protocol = 'telnet'; # strict RFC854 implementation, netcat won't work
587560e8 372 $prompt = '^\xf2?(login|Username|Password): $|^\S+[>#]$';
ee64514c 373 $commands = "enable\nno terminal monitor\nterminal length 0\n" . $commands;
85703049 374 break;
919bb8b6
DO
375 case 'ros11':
376 $protocol = 'netcat'; # see ftos8 case
377 $prompt = '^(User Name|\rPassword):$|^\r?\S+# $';
ee64514c
AA
378 $commands = "terminal datadump\n" . $commands;
379 $commands .= "\n\n"; # temporary workaround for telnet server
919bb8b6 380 break;
7a0e9964
AA
381 case 'iosxr4':
382 $protocol = 'telnet';
383 $prompt = '^\r?(Login|Username|Password): $|^\r?\S+[>#]$';
ee64514c 384 $commands = "terminal length 0\nterminal monitor disable\n" . $commands;
7a0e9964 385 break;
be91a564
JS
386 case 'ucs':
387 $protocol = 'ucssdk';
388 break;
ee64514c 389 case 'dlink':
5d2988fb 390 $protocol = 'netcat';
ee64514c
AA
391 $commands = "disable clipaging\n" . $commands;
392 break;
7cb57a03 393 }
ee64514c
AA
394 if (! isset ($protocol))
395 $protocol = 'netcat';
396 if (! isset ($prompt))
397 $prompt = NULL;
7cb57a03
AA
398
399 // set the default settings before calling user-defined callback
400 $settings = array
401 (
402 'hostname' => $endpoints[0],
a3447df9 403 'protocol' => $protocol,
7cb57a03
AA
404 'port' => NULL,
405 'prompt' => $prompt,
406 'username' => NULL,
407 'password' => NULL,
ada8a703 408 'timeout' => 15,
7cb57a03 409 'connect_timeout' => 2,
a9edde6c 410 'prompt_delay' => 0.001, # 1ms
7cb57a03
AA
411 'sudo_user' => NULL,
412 'identity_file' => NULL,
413 );
503ee8b2 414
ee64514c
AA
415 // override default settings
416 if (is_callable ('terminal_settings'))
417 call_user_func ('terminal_settings', $objectInfo, array (&$settings));
418 // make gateway-specific CLI params out of settings
419 $params = callHook ('makeGatewayParams', $object_id, $tolerate_remote_errors, array (&$settings), array (&$commands));
420 // call gateway
7cb57a03 421 $ret_code = callScript ($settings['protocol'], $params, $commands, $out, $errors);
ee64514c 422
01b0c68f 423 if ($settings['protocol'] != 'ssh' || ! $tolerate_remote_errors)
7cb57a03
AA
424 {
425 if (! empty ($errors))
e75026f8 426 throw new RTGatewayError ("${settings['protocol']} error: " . rtrim ($errors));
7cb57a03
AA
427 elseif ($ret_code !== 0)
428 throw new RTGatewayError ("${settings['protocol']} error: result code $ret_code");
429 }
ba2d4431 430 elseif (! empty ($errors)) // ssh and tolerate and non-empty $errors
7cb57a03
AA
431 foreach (explode ("\n", $errors) as $line)
432 if (strlen ($line))
433 showWarning ("${settings['protocol']} ${settings['hostname']}: $line");
434 return strtr($out, array("\r" => "")); // cut ^M symbols
435}
436
437function callScript ($gwname, $params, $in, &$out, &$errors)
438{
f99dd0f0
AA
439 global $racktables_gwdir, $local_gwdir, $gateway_log;
440 if (isset ($gateway_log))
441 $gateway_log = '';
442
82c41727
AA
443 $cwd = NULL;
444 if ('/' === substr ($gwname, 0, 1))
445 // absolute path to executable
446 $binary = $gwname;
447 else
448 {
449 // path relative to one of RackTables' gwdirs
450 if (isset ($local_gwdir) && file_exists ("$local_gwdir/$gwname"))
451 $cwd = $local_gwdir;
452 elseif (isset ($racktables_gwdir) && file_exists ("$racktables_gwdir/$gwname"))
453 $cwd = $racktables_gwdir;
454 if (! isset ($cwd))
455 throw new RTGatewayError ("Could not find the gateway file called '$gwname'");
456 $binary = "./$gwname";
457 }
7cb57a03 458
82c41727 459 $cmd_line = $binary;
7cb57a03
AA
460 foreach ($params as $key => $value)
461 {
462 if (! isset ($value))
463 continue;
464 if (preg_match ('/^\d+$/', $key))
465 $cmd_line .= " " . escapeshellarg ($value);
466 else
467 {
468 if (strlen ($key) == 1)
469 $cmd_line .= " " . escapeshellarg ("-$key") . " " . escapeshellarg ($value);
470 else
471 $cmd_line .= " " . escapeshellarg("--$key=$value");
472 }
473 }
424604b4 474
7cb57a03 475 $pipes = array();
dec748f6 476 $child = proc_open
7cb57a03
AA
477 (
478 $cmd_line,
479 array (
480 0 => array ('pipe', 'r'),
481 1 => array ('pipe', 'w'),
482 2 => array ('pipe', 'w'),
483 ),
484 $pipes,
82c41727 485 $cwd
7cb57a03
AA
486 );
487 if (! is_resource ($child))
82c41727 488 throw new RTGatewayError ("cant execute $binary");
15da1b37
AA
489
490 $buff_size = 4096;
491 $write_left = array ($pipes[0]);
492 $read_left = array ($pipes[1], $pipes[2]);
493 $write_fd = $write_left;
494 $read_fd = $read_left;
495 $except_fd = array();
e9222a8a
AA
496 $out = '';
497 $errors = '';
15da1b37
AA
498 while ((! empty ($read_fd) || ! empty ($write_fd)) && stream_select ($read_fd, $write_fd, $except_fd, NULL))
499 {
500 foreach ($write_fd as $fd)
501 {
502 $written = fwrite ($fd, $in, $buff_size);
f99dd0f0
AA
503 // log all communication data into global var
504 if ($written != 0 && isset ($gateway_log))
505 $gateway_log .= preg_replace ('/^/m', '> ', substr ($in, 0, $written));
15da1b37 506 $in = substr ($in, $written);
f99dd0f0 507
15da1b37
AA
508 if ($written == 0 || empty ($in))
509 {
510 // close input fd
511 $write_left = array_diff ($write_left, array ($fd));
512 fclose ($fd);
513 }
514 }
515 foreach ($read_fd as $fd)
516 {
517 $str = fread ($fd, $buff_size);
518 if (strlen ($str) == 0)
519 {
520 // close output fd
521 $read_left = array_diff ($read_left, array ($fd));
522 fclose ($fd);
523 }
524 else
525 {
f99dd0f0
AA
526 // log all communication data into global var
527 if (isset ($gateway_log))
528 $gateway_log .= $str;
529
15da1b37
AA
530 if ($fd == $pipes[1])
531 $out .= $str;
532 elseif ($fd == $pipes[2])
533 $errors .= $str;
534 }
535 }
536
537 $write_fd = $write_left;
538 $read_fd = $read_left;
15da1b37 539
f99dd0f0
AA
540 // limit the size of gateway_log
541 if (isset ($gateway_log) && strlen ($gateway_log) > MAX_GW_LOGSIZE * 1.1)
542 $gateway_log = substr ($gateway_log, -MAX_GW_LOGSIZE);
543
544 }
7da04382 545 return proc_close ($child);
7cb57a03
AA
546}
547
bc93236a
AA
548function getRunning8021QConfig ($object_id)
549{
550 $ret = queryDevice ($object_id, 'get8021q');
551 // Once there is no default VLAN in the parsed data, it means
552 // something else was parsed instead of config text.
1c0a61e2 553 if (!in_array (VLAN_DFL_ID, $ret['vlanlist']) || empty ($ret['portdata']))
bc93236a
AA
554 throw new RTGatewayError ('communication with device failed');
555 return $ret;
556}
557
558function setDevice8021QConfig ($object_id, $pseudocode, $vlan_names)
559{
560 // FIXME: this is a perfect place to log intended changes
561 // $object_id argument isn't used by default translating functions, but
562 // may come in handy for overloaded versions of these.
9f1da7de 563 $commands = translateDeviceCommands ($object_id, $pseudocode, $vlan_names);
dc68fd36
AA
564 $breed = detectDeviceBreed ($object_id);
565 $output = queryTerminal ($object_id, $commands, FALSE);
dec748f6 566
dc68fd36
AA
567 // throw an exception if Juniper did not allow to enter config mode or to commit changes
568 if ($breed == 'jun10')
569 {
570 if (preg_match ('/>\s*configure exclusive\s*$[^#>]*?^error:/sm', $output))
571 throw new RTGatewayError ("Configuration is locked by other user");
572 elseif (preg_match ('/#\s*commit\s*$([^#]*?^error: .*?)$/sm', $output, $m))
573 throw new RTGatewayError ("Commit failed: ${m[1]}");
574 }
bc93236a
AA
575}
576
7cb57a03 577?>