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