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