How to send input to ssh which exec-ed by child process ?
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
How to send input to ssh which exec-ed by child process ?
Code:
if ((pid = fork()) < 0) {
perror("fork error");
} else if (pid > 0) {
/*parent, I want to send cmd like "ls" to clild */
} else { /* child */
execl("/usr/bin/sh","sh","-c","ssh user@host",NULL);
/*clild,I want to read cmd like "ls" from parent as the input for ssh, something like `expect` */
}
You need to make a pipe with pipe, dup2 the input end over the standard input descriptor of the fork (pause the fork with raise(SIGSTOP); afterward, close the output descriptor in the fork,) probably fork again and dup2 the output pipe descriptor over that fork's standard output (also pause that fork, close the input descriptor in the fork,) waitpid from the parent to make sure both forks are stopped, then SIGCONT them with kill. You can optionally put them in the same process group before you continue them with setpgid (using the first fork's process ID) and continue them with killpg. You will need to kill the forks with SIGKILL upon any failure in the parent process, or just SIGCONT them and let them fail on their own. The second fork should execvp the ls command and the first fork will still execl the ssh command. Sorry, I don't have time at the moment to come up with an example, but the manpages for these system calls help a lot.
ta0kira
Thanks for the reply, but maybe this is not what i'm asking...
After I exec "ssh user@host" in child process, what I type in the console, ie `ls` is sent to parent process, then
parent process send `ls` to child process , but child process is not going to execle `ls` in itself, instead, the `ls` cmd is sent to the user@host and executed there, like i type `ls` after I `ssh user@host` in bash. Like the `expect` send `ls` to remote host.
Sorry for the bad English and bad understanding, maybe I dont catch your point.
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
if (argc < 2)
{
fprintf(stderr, "%s [exec args ...]\n", argv[0]);
return 1;
}
//create a pipe with separate input and output descriptors
int pipes[2] = { -1, -1 };
if (pipe(pipes) != 0)
{
fprintf(stderr, "%s: could not create pipes: %s\n", argv[0], strerror(errno));
return 1;
}
//fork in order to exec the new process
pid_t new_process = -1;
if ((new_process = fork()) < 0)
{
fprintf(stderr, "%s: fork error: %s\n", argv[0], strerror(errno));
return 1;
}
if (!new_process)
//forked process
{
//replace standard input with the input descriptor
dup2(pipes[0], STDIN_FILENO);
//close the other descriptors
//NOTE: with other than standard ..., check to make sure you aren't
//closing what you just 'dup2'ed over!
close(pipes[0]);
close(pipes[1]);
//pause until signaled
raise(SIGSTOP);
//if 'execvp' returns then that's an error
int outcome = execvp(argv[1], argv + 1);
fprintf(stderr, "%s: 'execvp' error: %s\n", argv[0], strerror(errno));
_exit(outcome);
}
//parent process//wait for the fork(s) to pause
int status = 0;
while (waitpid(new_process, &status, WUNTRACED) == 0 && !WIFSTOPPED(status));
if (!WIFSTOPPED(status))
{
fprintf(stderr, "%s: error synchronizing with fork: %s\n", argv[0], strerror(errno));
kill(new_process, SIGCONT);
return 1;
}
//put the fork(s) in a new process group for group control
setpgid(new_process, new_process);
//the input descriptor isn't needed
close(pipes[0]);
//open a stream for output to the fork
FILE *output = fdopen(pipes[1], "w");
if (!output)
{
fprintf(stderr, "%s: internal communication error: %s\n", argv[0], strerror(errno));
kill(new_process, SIGCONT);
return 1;
}
//resume the process group all at once (will continue all in the group)
killpg(new_process, SIGCONT);
char buffer[256];
setlinebuf(output);
//read from standard input until the child exits or input is closed
while (!ferror(output) && !ferror(stdin) && fgets(buffer, sizeof buffer, stdin))
{
fprintf(stderr, "forwarding: %s", buffer);
fprintf(output, "%s", buffer);
}
return 0;
}
Your requirement will probably vary from this, but it's the easiest way I've found to chain input and output of separate commands. You can chain an arbitrary number of processes together with this by replacing the standard output of the most recent fork with a new pipe and replacing the standard input of the next fork with the same pipe, etc.
ta0kira
PS Call the program with a command-line following the program name. Standard input will be echoed and forwarded to the program being exec-ed.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.