pushing tty output to node - bash

For the satisfaction of my curiosity gene i'd like to play with bash/node combo.
I don't know how to make those 2 talk together. I just had a great smile on my face finding about TTY.JS ;-)
How do I feed terminal's output (sdtout?) to node? I thought about redirecting the stream to file and read it with node through 'fs' module. But there must be some prettier way I bet
thanks in advance.

Something like this should send terminal output to node
var app = require('express').createServer(),
io = require('socket.io').listen(app),
sys = require('util'),
exec = require('child_process').exec;
app.listen(4990);
io.sockets.on('connection', function(socket) {
socket.on('console', function(command, callBack) {
// client sends {command: 'ls -al'}
function puts(error, stdout, stderr) {
socket.emit('commandresult', stdout);
}
exec(command.command, puts);
});
});​
Hope this helps

Related

Using Rust to test telnet connection and log results

I am a Rust newbie. I've been wanting to learn Rust and decided my first project would be to build a connection testing tool packaged an executable for the tech support people at my work. Basically the tool needs to run by end-users on Windows computers and test three or more URLs using ping, tracert, and telnet. Also after running the tool, the results of the three commands should be logged into text files and lastly enclosed in a zip file at the end.
I put some code together and it's mostly working except for the telnet portion. I've been pulling my hair out trying to figure out why the telnet part is not working. I was able to compile my Rust code successfully and it runs, but no matter what the telnet part generates a telnet connection failed in the log indicating the telnet was not successful, even though I am able to run the telnet command on the same machine using the same command manually typed (telnet service1.somedomain.com 13101). So I can see telnet is installed and working...
Further down below is my code. I added some println! statements on lines 59-61 and the only clue I see so far is the status code that prints out when I run the tool says telnet command exited with status: exit code: 0xffffffff and nothing prints for telnet stdout/stderr. This seems to indicate telnet is aborting or not found, so I used the full path to the telnet.exe file on the Windows machine (C:\Windows\System32\telnet.exe) instead of just "telnet" and still got the same error.
use std::process::Command;
use std::fs::File;
use std::io::prelude::*;
use std::io::Error;
use std::path::{Path, PathBuf};
use std::io::Cursor;
//use zip::write::FileOptions;
//use zip::result::ZipWriter;
use zip::write::{FileOptions, ZipWriter};
use zip::result::ZipResult;
fn main() -> Result<(), Error> {
// Set the domains and ports to be tested
let domains_and_ports = [
("www.somedomain.com", "80"),
("serivce1.somedomain.com", "13101"),
("service2.somedomain.com", "13103")];
// Create a zip file to store the results
let zip_file_path = Path::new("results.zip");
let zip_file = File::create(zip_file_path)?;
let mut zip_writer = ZipWriter::new(zip_file);
// Set the password to encrypt the zip file
let password = b"password";
// Iterate over each domain and port combination
for (domain, port) in domains_and_ports {
// Run the ping command
let ping_output = Command::new("cmd")
.args(&["/C", format!("ping {}", domain).as_str()])
.output()?;
let ping_file_path = write_output_to_file(domain, "ping.txt", &ping_output)?;
// Run the tracert command
let tracert_output = Command::new("cmd")
.args(&["/C", format!("tracert {}", domain).as_str()])
.output()?;
let tracert_file_path = write_output_to_file(domain, "tracert.txt", &tracert_output)?;
let telnet_output = Command::new("cmd")
.args(&["/C", format!("telnet {} {}", domain, port).as_str()])
.output()?;
let telnet_file_path = write_output_to_file(domain, "telnet.txt", &telnet_output)?;
// Write the ping, tracert, and telnet results to the zip file
zip_writer.start_file(format!("{}_ping.txt", domain), FileOptions::default())?;
zip_writer.write_all(&read_file_contents(ping_file_path)?)?;
zip_writer.start_file(format!("{}_tracert.txt", domain), FileOptions::default())?;
zip_writer.write_all(&read_file_contents(tracert_file_path)?)?;
zip_writer.start_file(format!("{}_telnet.txt", domain), FileOptions::default())?;
println!("telnet command exited with status: {}", telnet_output.status);
println!("telnet stdout: {}", String::from_utf8_lossy(&telnet_output.stdout));
println!("telnet stderr: {}", String::from_utf8_lossy(&telnet_output.stderr));
if telnet_output.status.success() {
zip_writer.write_all(b"telnet connection successful")?;
} else {
zip_writer.write_all(b"telnet connection failed")?;
}
}
// Close the zip file
zip_writer.finish()?;
println!("Results saved in results.zip");
Ok(())
}
fn write_output_to_file(domain: &str, command: &str, output: &std::process::Output) -> Result<PathBuf, Error> {
let fname = format!("{}_{}", domain, command).as_str().to_owned();
//let file_path = Path::new(format!("{}_{}", domain, command).as_str());
let file_path = Path::new(&fname);
let mut file = File::create(file_path)?;
file.write_all(&output.stdout)?;
file.write_all(&output.stderr)?;
Ok(file_path.to_path_buf())
}
fn read_file_contents(file_path: PathBuf) -> Result<Vec<u8>, Error> {
let mut file = File::open(file_path)?;
let mut contents = Vec::new();
file.read_to_end(&mut contents)?;
Ok(contents)
}
This is what prints (one set shown for first domain, but it prints three sets with same error, for each domain/port combination)...
Does anyone have experience running telnet commands on Windows, plus logging telnet results using Rust? If anyone has tips or example code to fix my example above I would be truly grateful. As a side-note, I know something similar could be done with a Windows batch file or Python but I was really wanting to get the Rust project working so I could have a little "win" with this my first go around with it.
Thanks in advance for any help you can offer!
PS - the domains and ports are made-up for this post :).

Spawning Ruby from Node.js - How to require within the Ruby file?

I have succesfully spawn a ruby script from my node application. However, in my Ruby script I would like to require some gems and files, and it seems that when doing a require, node.js doesn't get any response.
Here is how this looks:
var cp = require('child_process')
var ruby_child = cp.spawn('ruby',['libs/scorer/test.rb']);
var result = '';
ruby_child.stdout.on('data', function(data) {
result += data.toString();
});
ruby_child.on('close', function() {
console.log(result);
});
And my Ruby script looks like this:
require 'utils' # if I remove this line, I can get the response.
# Does it have an argument?
if ARGV.nil? || ARGV.empty?
p 'test'
exit
end
That's probably the require line failed. The Ruby program sent some error status to STDERR and then exited, and your js program didn't capture STDERR output.
Add some STDERR capture code in your js program for diagnostic information of your problem. You may probably found that the Ruby cannot find the required library in $LOAD_PATH.
ruby_child.stderr.on('data', function(data) {
console.log("ERROR --- " + data);
});

How to send control C node.js and child_processes

Hello I want to send to the child_process, for example, ping 8.8.8.8-t, that is, an infinite number of ping. And some of the iterations I want to stop this command and execute a new, but in this case I do not want to kill a child process.
Example:
var spawn = require('child_process').spawn('cmd'),
iconv = require('iconv-lite');
spawn.stdout.on('data', function (data) {
console.log('Stdout: ', iconv.decode(data, 'cp866'));
});
spawn.stderr.on('data', function (data) {
console.log('Stderr: ', iconv.decode(data, 'cp866'));
});
spawn.stdin.write('ping 8.8.8.8 -t'+ '\r\n');
spawn.stdin.write(here control-c...); // WRONG
spawn.stdin.write('dir' + '\r\n');
I found your previous question. Looks like you are trying to create/emulate a terminal from within node.js. You can use readline for reading and writing from a terminal.
To write control character, you can see the example from its docs :
rl.write('Delete me!');
// Simulate ctrl+u to delete the line written previously
rl.write(null, {ctrl: true, name: 'u'});
To directly answer the question, to pass special characters you will need to pass their ASCII values. Ctrl + C becomes ASCII character 0x03. Value taken from here.
spawn.stdin.write("\x03");

Node.js: How to send control C to child process

I am writing one web-like linux shell using node.js + socket.io. Simple command like, ls, cd are working well.
But when issue command like ping google.com, the stdout is printing endlessly.
I tried to send Ctrl +C to stdin, but no luck.
1) spawn 'bash' process
spawn = require('child_process').spawn;
var sh = spawn('bash');
2) send bash stdout to socket.io
sh.stdout.on('data', function(data) {
console.log('stdout' + data);
listener.sockets.emit("stdout",new Buffer(data));
});
3) Sending Ctl C (\x03) to bash's stdin.
var listener = io.listen(server);
listener.set('log level',1);
listener.sockets.on('connection', function(client){
client.on('message', function(data){
if(data === "KILL") {
console.log('!!!!' + data);
sh.stdin.write('\x03');
client.broadcast.send(new Buffer("KILLING "));
//return;
};
console.log(data);
sh.stdin.write(data+"\n");
client.broadcast.send(new Buffer("> "+data));
});
});
I am stuck at this point. Seems like
Try process.kill(sh.pid). I use this to kill workers in a cluster when my master process shuts down. sh.signalCode should be equal to SIGTERM. Of course, I have no idea if this works on Windows.
try stdout.push(null).
I tried it on node 12. This will not kill your child process instead it will tell you output stream that there is no more input stream.

How to set up node.js interaction with shell application?

At:
node js interact with shell application
Trindaz linked to his YouTube video demonstrating how to interact with a bash shell (including interpreters available from the shell):
http://www.youtube.com/watch?v=16nFMucvwYQ
However I could not follow the frames from 20 seconds to 54 seconds. At 54 seconds the browser window shows:
....................................
connected
$ log in
$
.....................................
What are the steps required to get to this window? Any hints or guidance would be appreciated.
Thank you,
RP
I did not exactly replicate what is there in the video but I hope a sample like below should do it.
This is how I configured the server part.
var app = require('express').createServer(),
io = require('socket.io').listen(app),
sys = require('util'),
exec = require('child_process').exec;
app.listen(4990);
io.sockets.on('connection', function(socket) {
socket.on('console', function(command, callBack) {
// client sends {command: 'ls -al'}
function puts(error, stdout, stderr) {
socket.emit('commandresult', stdout);
}
exec(command.command, puts);
});
});​
I hope you can do the client part.
Hope this helps

Resources