1*b65280ffSSui Chenconst { spawn } = require('child_process');
2*b65280ffSSui Chenconst targz = require('targz');
3*b65280ffSSui Chen
4*b65280ffSSui Chenconst DBUS_MONITOR_LEGACY =
5*b65280ffSSui Chen    'dbus-monitor --system | grep "sendMessage\\|ReceivedMessage" -A7 \n';
6*b65280ffSSui Chenconst DBUS_MONITOR_NEW =
7*b65280ffSSui Chen    'dbus-monitor --system | grep "member=execute\\|method return" -A7 \n';
8*b65280ffSSui Chen
9*b65280ffSSui Chen// Capture state for all scripts
10*b65280ffSSui Chenvar g_capture_state = 'not started';
11*b65280ffSSui Chenvar g_capture_mode = 'live';
12*b65280ffSSui Chen
13*b65280ffSSui Chen// For capturing IPMI requests live
14*b65280ffSSui Chenvar g_dbus_monitor_cmd = '';
15*b65280ffSSui Chen
16*b65280ffSSui Chen// For tracking transfer
17*b65280ffSSui Chenvar g_hexdump = '';
18*b65280ffSSui Chenvar g_hexdump_received_size = 0;
19*b65280ffSSui Chenvar g_hexdump_total_size = 0;
20*b65280ffSSui Chen
21*b65280ffSSui Chenfunction currTimestamp() {
22*b65280ffSSui Chen  var tmp = new Date();
23*b65280ffSSui Chen  return (tmp.getTime() + tmp.getTimezoneOffset() * 60000) / 1000;
24*b65280ffSSui Chen}
25*b65280ffSSui Chen
26*b65280ffSSui Chenvar g_child;
27*b65280ffSSui Chenvar g_rz;
28*b65280ffSSui Chen
29*b65280ffSSui Chenvar g_capture_live = true;
30*b65280ffSSui Chenvar g_dbus_capture_tarfile_size = 0;
31*b65280ffSSui Chen
32*b65280ffSSui Chenfunction ParseHexDump(hd) {
33*b65280ffSSui Chen  let ret = [];
34*b65280ffSSui Chen  let lines = hd.split('\n');
35*b65280ffSSui Chen  let tot_size = 0;
36*b65280ffSSui Chen  for (let i = 0; i < lines.length; i++) {
37*b65280ffSSui Chen    const line = lines[i].trimEnd();
38*b65280ffSSui Chen    const sp = line.split(' ');
39*b65280ffSSui Chen    if (line.length < 1) continue;
40*b65280ffSSui Chen    if (sp.length < 1) continue;
41*b65280ffSSui Chen
42*b65280ffSSui Chen    for (let j = 1; j < sp.length; j++) {
43*b65280ffSSui Chen      let b0 = sp[j].slice(2);
44*b65280ffSSui Chen      let b1 = sp[j].slice(0, 2);
45*b65280ffSSui Chen      b0 = parseInt(b0, 16);
46*b65280ffSSui Chen      b1 = parseInt(b1, 16);
47*b65280ffSSui Chen      ret.push(b0);
48*b65280ffSSui Chen      ret.push(b1);
49*b65280ffSSui Chen    }
50*b65280ffSSui Chen
51*b65280ffSSui Chen    console.log('[' + line + ']')
52*b65280ffSSui Chen
53*b65280ffSSui Chen    {
54*b65280ffSSui Chen      tot_size = parseInt(sp[0], 16);
55*b65280ffSSui Chen      console.log('File size: ' + tot_size + ' ' + sp[0]);
56*b65280ffSSui Chen    }
57*b65280ffSSui Chen  }
58*b65280ffSSui Chen  ret = ret.slice(0, tot_size);
59*b65280ffSSui Chen  return new Buffer(ret);
60*b65280ffSSui Chen}
61*b65280ffSSui Chen
62*b65280ffSSui Chenfunction SaveHexdumpToFile(hd, file_name) {
63*b65280ffSSui Chen  const buf = ParseHexDump(hd);
64*b65280ffSSui Chen  fs.writeFileSync(file_name, buf)
65*b65280ffSSui Chen}
66*b65280ffSSui Chen
67*b65280ffSSui Chen// Delimiters: ">>>>>>" and "<<<<<<"
68*b65280ffSSui Chenfunction ExtractMyDelimitedStuff(x, parse_as = undefined) {
69*b65280ffSSui Chen  let i0 = x.lastIndexOf('>>>>>>'), i1 = x.lastIndexOf('<<<<<<');
70*b65280ffSSui Chen  if (i0 != -1 && i1 != -1) {
71*b65280ffSSui Chen    let ret = x.substr(i0 + 6, i1 - i0 - 6);
72*b65280ffSSui Chen    if (parse_as == undefined)
73*b65280ffSSui Chen      return ret;
74*b65280ffSSui Chen    else if (parse_as == 'int')
75*b65280ffSSui Chen      return parseInt(ret);
76*b65280ffSSui Chen  } else
77*b65280ffSSui Chen    return null;
78*b65280ffSSui Chen}
79*b65280ffSSui Chen
80*b65280ffSSui Chenfunction streamWrite(stream, chunk, encoding = 'utf8') {
81*b65280ffSSui Chen  return new Promise((resolve, reject) => {
82*b65280ffSSui Chen    const errListener = (err) => {
83*b65280ffSSui Chen      stream.removeListener('error', errListener);
84*b65280ffSSui Chen      reject(err);
85*b65280ffSSui Chen    };
86*b65280ffSSui Chen    stream.addListener('error', errListener);
87*b65280ffSSui Chen    const callback = () => {
88*b65280ffSSui Chen      stream.removeListener('error', errListener);
89*b65280ffSSui Chen      resolve(undefined);
90*b65280ffSSui Chen    };
91*b65280ffSSui Chen    stream.write(chunk, encoding, callback);
92*b65280ffSSui Chen  });
93*b65280ffSSui Chen}
94*b65280ffSSui Chen
95*b65280ffSSui Chenfunction ExtractTarFile() {
96*b65280ffSSui Chen  const tar_file = 'DBUS_MONITOR.tar.gz';
97*b65280ffSSui Chen  const target = '.';
98*b65280ffSSui Chen  targz.decompress({src: tar_file, dest: target}, function(err) {
99*b65280ffSSui Chen    if (err) {
100*b65280ffSSui Chen      console.log('Error decompressing .tar.gz file:' + err);
101*b65280ffSSui Chen    }
102*b65280ffSSui Chen    // Attempt to load even if error occurs
103*b65280ffSSui Chen    // example error: "Error decompressing .tar.gz file:Error: incorrect data check"
104*b65280ffSSui Chen    console.log('Done! will load file contents');
105*b65280ffSSui Chen    if (g_capture_mode == 'staged') {
106*b65280ffSSui Chen      fs.readFile('./DBUS_MONITOR', {encoding: 'utf-8'}, (err, data) => {
107*b65280ffSSui Chen        if (err) {
108*b65280ffSSui Chen          console.log('Error in readFile: ' + err);
109*b65280ffSSui Chen        } else {
110*b65280ffSSui Chen          ParseIPMIDump(data);
111*b65280ffSSui Chen        }
112*b65280ffSSui Chen      });
113*b65280ffSSui Chen    } else if (g_capture_mode == 'staged2') {
114*b65280ffSSui Chen      OpenDBusPcapFile('./DBUS_MONITOR');
115*b65280ffSSui Chen    }
116*b65280ffSSui Chen  });
117*b65280ffSSui Chen}
118*b65280ffSSui Chen
119*b65280ffSSui Chenfunction OnCaptureStart() {
120*b65280ffSSui Chen  switch (g_capture_state) {
121*b65280ffSSui Chen    case 'not started':
122*b65280ffSSui Chen      capture_info.textContent = 'dbus-monitor running on BMC';
123*b65280ffSSui Chen      break;
124*b65280ffSSui Chen    default:
125*b65280ffSSui Chen      break;
126*b65280ffSSui Chen  }
127*b65280ffSSui Chen}
128*b65280ffSSui Chen
129*b65280ffSSui Chenfunction OnCaptureStop() {
130*b65280ffSSui Chen  btn_start_capture.disabled = false;
131*b65280ffSSui Chen  select_capture_mode.disabled = false;
132*b65280ffSSui Chen  text_hostname.disabled = false;
133*b65280ffSSui Chen  g_capture_state = 'not started';
134*b65280ffSSui Chen}
135*b65280ffSSui Chen
136*b65280ffSSui Chenasync function OnTransferCompleted() {
137*b65280ffSSui Chen  setTimeout(function() {
138*b65280ffSSui Chen    console.log('OnTransferCompleted');
139*b65280ffSSui Chen    g_child.kill('SIGINT');
140*b65280ffSSui Chen  }, 5000);
141*b65280ffSSui Chen
142*b65280ffSSui Chen  capture_info.textContent = 'Loaded the capture file';
143*b65280ffSSui Chen  OnCaptureStop();
144*b65280ffSSui Chen  ExtractTarFile();
145*b65280ffSSui Chen}
146*b65280ffSSui Chen
147*b65280ffSSui Chen// Example output from stderr:
148*b65280ffSSui Chen// ^M Bytes received:    2549/   2549   BPS:6370
149*b65280ffSSui Chenasync function LaunchRZ() {
150*b65280ffSSui Chen  // On the Host
151*b65280ffSSui Chen
152*b65280ffSSui Chen  // Remove existing file
153*b65280ffSSui Chen  const file_names = ['DBUS_MONITOR', 'DBUS_MONITOR.tar.gz'];
154*b65280ffSSui Chen  try {
155*b65280ffSSui Chen    for (let i = 0; i < 2; i++) {
156*b65280ffSSui Chen      const fn = file_names[i];
157*b65280ffSSui Chen      if (fs.existsSync(fn)) {
158*b65280ffSSui Chen        fs.unlinkSync(fn);  // unlink is basically rm
159*b65280ffSSui Chen        console.log('Removed file: ' + fn);
160*b65280ffSSui Chen      }
161*b65280ffSSui Chen    }
162*b65280ffSSui Chen  } catch (err) {
163*b65280ffSSui Chen  }
164*b65280ffSSui Chen
165*b65280ffSSui Chen  g_rz = spawn(
166*b65280ffSSui Chen      'screen', ['rz', '-a', '-e', '-E', '-r', '-w', '32767'], {shell: false});
167*b65280ffSSui Chen  g_rz.stdout.on('data', (data) => {
168*b65280ffSSui Chen    console.log('[rz] received ' + data.length + ' B');
169*b65280ffSSui Chen    console.log(data);
170*b65280ffSSui Chen    console.log(data + '');
171*b65280ffSSui Chen    // data = MyCorrection(data);
172*b65280ffSSui Chen    if (data != undefined) g_child.stdin.write(data);
173*b65280ffSSui Chen  });
174*b65280ffSSui Chen  g_rz.stderr.on('data', (data) => {
175*b65280ffSSui Chen    console.log('[rz] error: ' + data);
176*b65280ffSSui Chen    let s = data.toString();
177*b65280ffSSui Chen    let idx = s.lastIndexOf('Bytes received:');
178*b65280ffSSui Chen    if (idx != -1) {
179*b65280ffSSui Chen      capture_info.textContent = s.substr(idx);
180*b65280ffSSui Chen    }
181*b65280ffSSui Chen    if (data.indexOf('Transfer complete') != -1) {
182*b65280ffSSui Chen      OnTransferCompleted();
183*b65280ffSSui Chen    } else if (data.indexOf('Transfer incomplete') != -1) {
184*b65280ffSSui Chen      // todo: retry transfer
185*b65280ffSSui Chen      // Bug info
186*b65280ffSSui Chen      // Uncaught Error [ERR_STREAM_WRITE_AFTER_END]: write after end
187*b65280ffSSui Chen      // at writeAfterEnd (_stream_writable.js:253)
188*b65280ffSSui Chen      // at Socket.Writable.write (_stream_writable.js:302)
189*b65280ffSSui Chen      // at Socket.<anonymous> (ipmi_capture.js:317)
190*b65280ffSSui Chen      // at Socket.emit (events.js:210)
191*b65280ffSSui Chen      // at addChunk (_stream_readable.js:308)
192*b65280ffSSui Chen      // at readableAddChunk (_stream_readable.js:289)
193*b65280ffSSui Chen      // at Socket.Readable.push (_stream_readable.js:223)
194*b65280ffSSui Chen      // at Pipe.onStreamRead (internal/stream_base_commons.js:182)
195*b65280ffSSui Chen      capture_info.textContent = 'Transfer incomplete';
196*b65280ffSSui Chen    }
197*b65280ffSSui Chen  });
198*b65280ffSSui Chen  await Promise.all(
199*b65280ffSSui Chen      [g_rz.stdin.pipe(g_child.stdout), g_rz.stdout.pipe(g_child.stdin)]);
200*b65280ffSSui Chen}
201*b65280ffSSui Chen
202*b65280ffSSui Chenfunction ClearAllPendingTimeouts() {
203*b65280ffSSui Chen  var id = setTimeout(function() {}, 0);
204*b65280ffSSui Chen  for (; id >= 0; id--) clearTimeout(id);
205*b65280ffSSui Chen}
206*b65280ffSSui Chen
207*b65280ffSSui Chenfunction StartDbusMonitorFileSizePollLoop() {
208*b65280ffSSui Chen  QueueDbusMonitorFileSize(5);
209*b65280ffSSui Chen}
210*b65280ffSSui Chen
211*b65280ffSSui Chenfunction QueueDbusMonitorFileSize(secs = 5) {
212*b65280ffSSui Chen  setTimeout(function() {
213*b65280ffSSui Chen    g_child.stdin.write(
214*b65280ffSSui Chen        'a=`ls -l /run/initramfs/DBUS_MONITOR | awk \'{print $5}\'` ; echo ">>>>>>$a<<<<<<"  \n\n\n\n');
215*b65280ffSSui Chen    QueueDbusMonitorFileSize(secs);
216*b65280ffSSui Chen  }, secs * 1000);
217*b65280ffSSui Chen}
218*b65280ffSSui Chen
219*b65280ffSSui Chenfunction StopCapture() {
220*b65280ffSSui Chen  switch (g_capture_mode) {
221*b65280ffSSui Chen    case 'live':
222*b65280ffSSui Chen      g_child.stdin.write('\x03 ');
223*b65280ffSSui Chen      g_capture_state = 'stopping';
224*b65280ffSSui Chen      capture_info.textContent = 'Ctrl+C sent to BMC console';
225*b65280ffSSui Chen      break;
226*b65280ffSSui Chen    case 'staged':
227*b65280ffSSui Chen      ClearAllPendingTimeouts();
228*b65280ffSSui Chen      g_child.stdin.write(
229*b65280ffSSui Chen          'echo ">>>>>>" && killall busctl && echo "<<<<<<" \n\n\n\n');
230*b65280ffSSui Chen      g_capture_state = 'stopping';
231*b65280ffSSui Chen      capture_info.textContent = 'Stopping dbus-monitor';
232*b65280ffSSui Chen    case 'staged2':
233*b65280ffSSui Chen      g_hexdump_received_size = 0;
234*b65280ffSSui Chen      g_hexdump_total_size = 0;
235*b65280ffSSui Chen      ClearAllPendingTimeouts();
236*b65280ffSSui Chen      g_child.stdin.write(
237*b65280ffSSui Chen          'echo ">>>>>>" && killall busctl && echo "<<<<<<" \n\n\n\n');
238*b65280ffSSui Chen      g_capture_state = 'stopping';
239*b65280ffSSui Chen      capture_info.textContent = 'Stopping busctl';
240*b65280ffSSui Chen      break;
241*b65280ffSSui Chen  }
242*b65280ffSSui Chen}
243*b65280ffSSui Chen
244*b65280ffSSui Chenfunction QueueBMCConsoleHello(secs = 3) {
245*b65280ffSSui Chen  setTimeout(function() {
246*b65280ffSSui Chen    try {
247*b65280ffSSui Chen      if (g_capture_state == 'not started') {
248*b65280ffSSui Chen        console.log('Sending hello <cr> to the BMC');
249*b65280ffSSui Chen        g_child.stdin.write('\n');
250*b65280ffSSui Chen        QueueBMCConsoleHello(secs);
251*b65280ffSSui Chen      }
252*b65280ffSSui Chen    } catch (err) {
253*b65280ffSSui Chen      console.log('g_child may have ended as intended');
254*b65280ffSSui Chen    }
255*b65280ffSSui Chen  }, secs * 1000);
256*b65280ffSSui Chen}
257*b65280ffSSui Chen
258*b65280ffSSui Chen// The command line needed to access the BMC. The expectation is
259*b65280ffSSui Chen// executing this command brings the user to the BMC's console.
260*b65280ffSSui Chenfunction GetCMDLine() {
261*b65280ffSSui Chen  let v = text_hostname.value.split(' ');
262*b65280ffSSui Chen  return [v[0], v.slice(1, v.length)];
263*b65280ffSSui Chen}
264*b65280ffSSui Chen
265*b65280ffSSui Chenasync function StartCapture(host) {
266*b65280ffSSui Chen  // Disable buttons
267*b65280ffSSui Chen  HideWelcomeScreen();
268*b65280ffSSui Chen  ShowIPMITimeline();
269*b65280ffSSui Chen  ShowNavigation();
270*b65280ffSSui Chen  let args = GetCMDLine();
271*b65280ffSSui Chen  btn_start_capture.disabled = true;
272*b65280ffSSui Chen  select_capture_mode.disabled = true;
273*b65280ffSSui Chen  text_hostname.disabled = true;
274*b65280ffSSui Chen  capture_info.textContent = 'Contacting BMC console: ' + args.toString();
275*b65280ffSSui Chen
276*b65280ffSSui Chen  // On the B.M.C.
277*b65280ffSSui Chen  let last_t = currTimestamp();
278*b65280ffSSui Chen  let attempt = 0;
279*b65280ffSSui Chen  console.log('Args: ' + args);
280*b65280ffSSui Chen  g_child = spawn(args[0], args[1], {shell: true});
281*b65280ffSSui Chen  g_child.stdout.on('data', async function(data) {
282*b65280ffSSui Chen    QueueBMCConsoleHello();
283*b65280ffSSui Chen
284*b65280ffSSui Chen    var t = currTimestamp();
285*b65280ffSSui Chen    {
286*b65280ffSSui Chen      switch (g_capture_state) {
287*b65280ffSSui Chen        case 'not started':  // Do nothing
288*b65280ffSSui Chen          break;
289*b65280ffSSui Chen        case 'started':
290*b65280ffSSui Chen          attempt++;
291*b65280ffSSui Chen          console.log('attempt ' + attempt);
292*b65280ffSSui Chen          g_child.stdin.write('echo "haha" \n');
293*b65280ffSSui Chen          await streamWrite(g_child.stdin, 'whoami \n');
294*b65280ffSSui Chen          let idx = data.indexOf('haha');
295*b65280ffSSui Chen          if (idx != -1) {
296*b65280ffSSui Chen            ClearAllPendingTimeouts();
297*b65280ffSSui Chen            OnCaptureStart();  // Successfully logged on, start
298*b65280ffSSui Chen
299*b65280ffSSui Chen            if (g_capture_mode == 'live') {
300*b65280ffSSui Chen              g_child.stdin.write(
301*b65280ffSSui Chen                  '\n\n' +
302*b65280ffSSui Chen                  'a=`pidof btbridged`;b=`pidof kcsbridged`;c=`pidof netipmid`;' +
303*b65280ffSSui Chen                  'echo ">>>>>>$a,$b,$c<<<<<<"\n\n');
304*b65280ffSSui Chen              g_capture_state = 'determine bridge daemon';
305*b65280ffSSui Chen            } else {
306*b65280ffSSui Chen              g_capture_state = 'dbus monitor start';
307*b65280ffSSui Chen            }
308*b65280ffSSui Chen            capture_info.textContent = 'Reached BMC console';
309*b65280ffSSui Chen
310*b65280ffSSui Chen          } else {
311*b65280ffSSui Chen            console.log('idx=' + idx);
312*b65280ffSSui Chen          }
313*b65280ffSSui Chen          break;
314*b65280ffSSui Chen        case 'determine bridge daemon': {
315*b65280ffSSui Chen          const abc = ExtractMyDelimitedStuff(data.toString());
316*b65280ffSSui Chen          if (abc == null) break;
317*b65280ffSSui Chen          const sp = abc.split(',');
318*b65280ffSSui Chen          if (parseInt(sp[0]) >= 0) {  // btbridged, legacy interface
319*b65280ffSSui Chen            g_dbus_monitor_cmd = DBUS_MONITOR_LEGACY;
320*b65280ffSSui Chen            console.log('The BMC is using btbridged.');
321*b65280ffSSui Chen          } else if (parseInt(sp[1]) >= 0) {  // new iface
322*b65280ffSSui Chen            g_dbus_monitor_cmd = DBUS_MONITOR_NEW;
323*b65280ffSSui Chen            console.log('The BMC is using kcsbridged.');
324*b65280ffSSui Chen          } else if (parseInt(sp[2]) >= 0) {
325*b65280ffSSui Chen            g_dbus_monitor_cmd = DBUS_MONITOR_NEW;
326*b65280ffSSui Chen            console.log('The BMC is using netipmid.');
327*b65280ffSSui Chen          } else {
328*b65280ffSSui Chen            console.log('Cannot determine the IPMI bridge daemon\n')
329*b65280ffSSui Chen            return;
330*b65280ffSSui Chen          }
331*b65280ffSSui Chen          g_capture_state = 'dbus monitor start';
332*b65280ffSSui Chen          break;
333*b65280ffSSui Chen        }
334*b65280ffSSui Chen        case 'dbus monitor start':
335*b65280ffSSui Chen          if (g_capture_mode == 'live') {
336*b65280ffSSui Chen            // It would be good to make sure the console bit rate is greater
337*b65280ffSSui Chen            // than the speed at which outputs are generated.
338*b65280ffSSui Chen            //            g_child.stdin.write("dbus-monitor --system | grep
339*b65280ffSSui Chen            //            \"sendMessage\\|ReceivedMessage\" -A7 \n")
340*b65280ffSSui Chen            ClearAllPendingTimeouts();
341*b65280ffSSui Chen            g_child.stdin.write(
342*b65280ffSSui Chen                'dbus-monitor --system | grep "member=execute\\|method return" -A7 \n');
343*b65280ffSSui Chen            capture_info.textContent = 'Started dbus-monitor for live capture';
344*b65280ffSSui Chen          } else {
345*b65280ffSSui Chen            //            g_child.stdin.write("dbus-monitor --system | grep
346*b65280ffSSui Chen            //            \"sendMessage\\|ReceivedMessage\" -A7 >
347*b65280ffSSui Chen            //            /run/initramfs/DBUS_MONITOR & \n\n\n")
348*b65280ffSSui Chen            ClearAllPendingTimeouts();
349*b65280ffSSui Chen            if (g_capture_mode == 'staged') {
350*b65280ffSSui Chen              g_child.stdin.write(
351*b65280ffSSui Chen                  'dbus-monitor --system > /run/initramfs/DBUS_MONITOR & \n\n\n');
352*b65280ffSSui Chen              capture_info.textContent =
353*b65280ffSSui Chen                  'Started dbus-monitor for staged IPMI capture';
354*b65280ffSSui Chen            } else if (g_capture_mode == 'staged2') {
355*b65280ffSSui Chen              g_child.stdin.write(
356*b65280ffSSui Chen                  'busctl capture > /run/initramfs/DBUS_MONITOR & \n\n\n');
357*b65280ffSSui Chen              capture_info.textContent =
358*b65280ffSSui Chen                  'Started busctl for staged IPMI + DBus capture';
359*b65280ffSSui Chen            }
360*b65280ffSSui Chen            StartDbusMonitorFileSizePollLoop();
361*b65280ffSSui Chen          }
362*b65280ffSSui Chen          g_capture_state = 'dbus monitor running';
363*b65280ffSSui Chen          break;
364*b65280ffSSui Chen        case 'dbus monitor running':
365*b65280ffSSui Chen          if (g_capture_mode == 'staged' || g_capture_mode == 'staged2') {
366*b65280ffSSui Chen            let s = data.toString();
367*b65280ffSSui Chen            let tmp = ExtractMyDelimitedStuff(s, 'int');
368*b65280ffSSui Chen            if (tmp != undefined) {
369*b65280ffSSui Chen              let sz = Math.floor(parseInt(tmp) / 1024);
370*b65280ffSSui Chen              if (!isNaN(sz)) {
371*b65280ffSSui Chen                capture_info.textContent =
372*b65280ffSSui Chen                    'Raw Dbus capture size: ' + sz + ' KiB';
373*b65280ffSSui Chen              } else {  // This can happen if the output is cut by half & may be
374*b65280ffSSui Chen                        // fixed by queuing console outputs
375*b65280ffSSui Chen              }
376*b65280ffSSui Chen            }
377*b65280ffSSui Chen          } else {
378*b65280ffSSui Chen            AppendToParseBuffer(data.toString());
379*b65280ffSSui Chen            MunchLines();
380*b65280ffSSui Chen            UpdateLayout();
381*b65280ffSSui Chen            ComputeHistogram();
382*b65280ffSSui Chen          }
383*b65280ffSSui Chen          break;
384*b65280ffSSui Chen        case 'dbus monitor end':  // Todo: add speed check
385*b65280ffSSui Chen          let s = data.toString();
386*b65280ffSSui Chen          let i0 = s.lastIndexOf('>>>>'), i1 = s.lastIndexOf('<<<<');
387*b65280ffSSui Chen          if (i0 != -1 && i1 != -1) {
388*b65280ffSSui Chen            let tmp = s.substr(i0 + 4, i1 - i0 - 4);
389*b65280ffSSui Chen            let sz = parseInt(tmp);
390*b65280ffSSui Chen            if (isNaN(sz)) {
391*b65280ffSSui Chen              console.log(
392*b65280ffSSui Chen                  'Error: the tentative dbus-profile dump is not found!');
393*b65280ffSSui Chen            } else {
394*b65280ffSSui Chen              let bps = sz / 10;
395*b65280ffSSui Chen              console.log('dbus-monitor generates ' + bps + 'B per second');
396*b65280ffSSui Chen            }
397*b65280ffSSui Chen          }
398*b65280ffSSui Chen          g_child.kill('SIGINT');
399*b65280ffSSui Chen          break;
400*b65280ffSSui Chen        case 'sz sending':
401*b65280ffSSui Chen          console.log('[sz] Received a chunk of size ' + data.length);
402*b65280ffSSui Chen          console.log(data);
403*b65280ffSSui Chen          console.log(data + '');
404*b65280ffSSui Chen          //          capture_info.textContent = "Received a chunk of size " +
405*b65280ffSSui Chen          //          data.length
406*b65280ffSSui Chen          g_rz.stdin.write(data);
407*b65280ffSSui Chen          break;
408*b65280ffSSui Chen        case 'stopping':
409*b65280ffSSui Chen          let t = data.toString();
410*b65280ffSSui Chen          if (g_capture_mode == 'live') {
411*b65280ffSSui Chen            if (t.lastIndexOf('^C') != -1) {
412*b65280ffSSui Chen              // Live mode
413*b65280ffSSui Chen              g_child.kill('SIGINT');
414*b65280ffSSui Chen              g_capture_state = 'not started';
415*b65280ffSSui Chen              OnCaptureStop();
416*b65280ffSSui Chen              capture_info.textContent = 'connection to BMC closed';
417*b65280ffSSui Chen              // Log mode
418*b65280ffSSui Chen            }
419*b65280ffSSui Chen          } else if (
420*b65280ffSSui Chen              g_capture_mode == 'staged' || g_capture_mode == 'staged2') {
421*b65280ffSSui Chen            ClearAllPendingTimeouts();
422*b65280ffSSui Chen            if (t.lastIndexOf('<<<<<<') != -1) {
423*b65280ffSSui Chen              g_capture_state = 'compressing';
424*b65280ffSSui Chen              g_child.stdin.write(
425*b65280ffSSui Chen                  'echo ">>>>>>" && cd /run/initramfs && tar cfz DBUS_MONITOR.tar.gz DBUS_MONITOR && echo "<<<<<<" \n\n\n\n');
426*b65280ffSSui Chen              capture_info.textContent = 'Compressing dbus monitor dump on BMC';
427*b65280ffSSui Chen            }
428*b65280ffSSui Chen          }
429*b65280ffSSui Chen          break;
430*b65280ffSSui Chen        case 'compressing':
431*b65280ffSSui Chen          g_child.stdin.write(
432*b65280ffSSui Chen              '\n\na=`ls -l /run/initramfs/DBUS_MONITOR.tar.gz | awk \'{print $5}\'` && echo ">>>>>>$a<<<<<<"   \n\n\n\n');
433*b65280ffSSui Chen          g_capture_state = 'dbus_monitor size';
434*b65280ffSSui Chen          capture_info.textContent = 'Obtaining size of compressed dbus dump';
435*b65280ffSSui Chen          break;
436*b65280ffSSui Chen        case 'dbus_monitor size':
437*b65280ffSSui Chen          // Starting RZ
438*b65280ffSSui Chen          let tmp = ExtractMyDelimitedStuff(data.toString(), 'int');
439*b65280ffSSui Chen          if (tmp != null && !isNaN(tmp)) {  // Wait until result shows up
440*b65280ffSSui Chen            g_hexdump_total_size = tmp;
441*b65280ffSSui Chen            console.log(
442*b65280ffSSui Chen                'dbus_monitor size tmp=' + tmp + ', ' + data.toString());
443*b65280ffSSui Chen
444*b65280ffSSui Chen            // if (tmp != undefined) {
445*b65280ffSSui Chen            //   g_dbus_capture_tarfile_size = tmp;
446*b65280ffSSui Chen            //   capture_info.textContent =
447*b65280ffSSui Chen            //       'Starting rz and sz, file size: ' + Math.floor(tmp / 1024)
448*b65280ffSSui Chen            //       + ' KiB';
449*b65280ffSSui Chen            // } else {
450*b65280ffSSui Chen            //   capture_info.textContent = 'Starting rz and sz';
451*b65280ffSSui Chen            // }
452*b65280ffSSui Chen            // g_capture_state = 'sz start';
453*b65280ffSSui Chen            // g_child.stdin.write(
454*b65280ffSSui Chen            //   '\n\n\n\n' +
455*b65280ffSSui Chen            //   'sz -a -e -R -L 512 -w 32767 -y
456*b65280ffSSui Chen            //   /run/initramfs/DBUS_MONITOR.tar.gz\n');
457*b65280ffSSui Chen            // g_capture_state = 'sz sending';
458*b65280ffSSui Chen            // LaunchRZ();
459*b65280ffSSui Chen            g_child.stdin.write(
460*b65280ffSSui Chen                'echo ">>>>>>"; hexdump /run/initramfs/DBUS_MONITOR.tar.gz ; echo "<<<<<<"; \n');
461*b65280ffSSui Chen            g_capture_state = 'test hexdump running';
462*b65280ffSSui Chen            g_hexdump = new Buffer([]);
463*b65280ffSSui Chen          }
464*b65280ffSSui Chen
465*b65280ffSSui Chen          break;
466*b65280ffSSui Chen        case 'test hexdump start':
467*b65280ffSSui Chen          g_child.stdin.write(
468*b65280ffSSui Chen              'echo ">>>>>>"; hexdump /run/initramfs/DBUS_MONITOR.tar.gz ; echo "<<<<<<"; \n');
469*b65280ffSSui Chen          g_capture_state = 'test hexdump running';
470*b65280ffSSui Chen          g_hexdump = new Buffer([]);
471*b65280ffSSui Chen          g_hexdump_received_size = 0;
472*b65280ffSSui Chen          break;
473*b65280ffSSui Chen        case 'test hexdump running':
474*b65280ffSSui Chen          g_hexdump += data;
475*b65280ffSSui Chen          const lines = data.toString().split('\n');
476*b65280ffSSui Chen          for (let j = lines.length - 1; j >= 0; j--) {
477*b65280ffSSui Chen            sp = lines[j].trimEnd().split(' ');
478*b65280ffSSui Chen            if (sp.length >= 1) {
479*b65280ffSSui Chen              const sz = parseInt(sp[0], 16)
480*b65280ffSSui Chen              if (!isNaN(sz)) {
481*b65280ffSSui Chen                if (g_hexdump_received_size < sz) {
482*b65280ffSSui Chen                  g_hexdump_received_size = sz;
483*b65280ffSSui Chen                  capture_info.textContent = 'Receiving capture file: ' + sz +
484*b65280ffSSui Chen                      ' / ' + g_hexdump_total_size + ' B';
485*b65280ffSSui Chen                  break;
486*b65280ffSSui Chen                }
487*b65280ffSSui Chen              }
488*b65280ffSSui Chen            }
489*b65280ffSSui Chen          }
490*b65280ffSSui Chen          if (data.includes('<<<<<<') && !data.includes('echo')) {
491*b65280ffSSui Chen            g_hexdump = ExtractMyDelimitedStuff(g_hexdump);
492*b65280ffSSui Chen            SaveHexdumpToFile(g_hexdump, 'DBUS_MONITOR.tar.gz');
493*b65280ffSSui Chen            OnTransferCompleted();
494*b65280ffSSui Chen          }
495*b65280ffSSui Chen          break;
496*b65280ffSSui Chen      }
497*b65280ffSSui Chen      last_t = t;
498*b65280ffSSui Chen    }
499*b65280ffSSui Chen  });
500*b65280ffSSui Chen  g_child.stderr.on('data', (data) => {
501*b65280ffSSui Chen    console.log('[bmc] err=' + data);
502*b65280ffSSui Chen    g_child.stdin.write('echo "haha" \n\n');
503*b65280ffSSui Chen  });
504*b65280ffSSui Chen  g_child.on('close', (code) => {
505*b65280ffSSui Chen    console.log('return code: ' + code);
506*b65280ffSSui Chen  });
507*b65280ffSSui Chen}
508