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