fork - execlp - read output from interactive commands (telnet, ftp) - Unix

This is a discussion on fork - execlp - read output from interactive commands (telnet, ftp) - Unix ; Hi all, I am writing a program which accepts as parameter a command, executes the command (fork and execlp) and prints out the output of the command. It works fine with programs which don't require user's input, but it doesn't ...

+ Reply to Thread
Results 1 to 4 of 4

Thread: fork - execlp - read output from interactive commands (telnet, ftp)

  1. fork - execlp - read output from interactive commands (telnet, ftp)

    Hi all,

    I am writing a program which accepts as parameter a command, executes
    the command (fork and execlp) and prints out the output of the
    command. It works fine with programs which don't require user's input,
    but it doesn't work with programs like telnet or ftp, it blocks trying
    to read data from the command.

    The program is:

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    static int run_program (const char *program);

    int main (int argc, char **argv)
    {
    if (argc != 2) {
    printf ("Usage: %s \n", argv[0]);
    return -1;
    }

    return run_program (argv[1]);
    }

    int run_program (const char *program)
    {
    int read_pipe[2];
    int write_pipe[2];
    char buffer[4096];
    pid_t pid;
    ssize_t bytes;

    /* Create pipe for reading data from the child process. */
    if (pipe (read_pipe) < 0) {
    return -1;
    }

    /* Create pipe for writing data to the child process. */
    if (pipe (write_pipe) < 0) {
    close (read_pipe[0]);
    close (read_pipe[1]);
    return -1;
    }

    pid = fork ();
    if (pid < 0) {
    /* Fork failed. */
    close (write_pipe[0]);
    close (write_pipe[1]);
    close (read_pipe[0]);
    close (read_pipe[1]);
    return -1;
    }

    if (pid == 0) {
    /* Child process. */
    close (0);
    close (1);

    close (read_pipe[0]);
    close (write_pipe[1]);

    if (dup2 (read_pipe[1], 1) < 0) {
    close (read_pipe[1]);
    close (write_pipe[0]);
    _exit (1);
    }

    if (dup2 (read_pipe[1], 2) < 0) {
    close (read_pipe[1]);
    close (write_pipe[0]);
    _exit (1);
    }

    close (read_pipe[1]);

    if (dup2 (write_pipe[0], 0) < 0) {
    close (write_pipe[0]);
    _exit (1);
    }

    close (write_pipe[0]);

    execlp ("/bin/sh", "sh", "-c", program, NULL);
    exit (1);
    } else {
    /* Parent process. */
    close (read_pipe[1]);
    read_pipe[1] = -1;

    close (write_pipe[0]);
    write_pipe[0] = -1;

    do {
    bytes = read (read_pipe[0], buffer, sizeof
    (buffer));
    printf ("Read = %d.\n", bytes);
    if (bytes <= 0) {
    break;
    }

    printf ("%.*s", bytes, buffer);
    } while (1);
    }

    return 0;
    }

    What I am doing wrong? what am I missing?

    Thanks in advance,

    Guido.

  2. Re: fork - execlp - read output from interactive commands (telnet, ftp)

    In article
    <150c2d19-eed2-4984-b02f-b5a702ec9ee4@m73g2000hsh.googlegroups.com>,
    guidoreina@gmail.com wrote:

    > Hi all,
    >
    > I am writing a program which accepts as parameter a command, executes
    > the command (fork and execlp) and prints out the output of the
    > command. It works fine with programs which don't require user's input,
    > but it doesn't work with programs like telnet or ftp, it blocks trying
    > to read data from the command.


    The command is waiting for input on the write_pipe, and you're not
    supplying it.

    I suppose you're wondering why you don't even get the FTP prompt, since
    it's sent before waiting for input. This is because the program is
    probably using stdio, and stdio buffers output to stdout when it's not
    connected to a terminal. You won't get anything until the buffer fills
    up, but it can't fill up until you supply input, so you're in a deadlock.

    To get around this you need to use a pseudo-tty. One of the best ways
    to control interactive applications is by using the Expect scripting
    language, it takes care of this for you. If you don't want to go that
    far, you can use the "unbuffer" tool that comes with it; instead of
    running "ftp", run "unbuffer ftp" and it will use a pty to prevent
    buffering.

    >
    > The program is:
    >
    > #include
    > #include
    > #include
    > #include
    > #include
    > #include
    > #include
    > #include
    >
    > static int run_program (const char *program);
    >
    > int main (int argc, char **argv)
    > {
    > if (argc != 2) {
    > printf ("Usage: %s \n", argv[0]);
    > return -1;
    > }
    >
    > return run_program (argv[1]);
    > }
    >
    > int run_program (const char *program)
    > {
    > int read_pipe[2];
    > int write_pipe[2];
    > char buffer[4096];
    > pid_t pid;
    > ssize_t bytes;
    >
    > /* Create pipe for reading data from the child process. */
    > if (pipe (read_pipe) < 0) {
    > return -1;
    > }
    >
    > /* Create pipe for writing data to the child process. */
    > if (pipe (write_pipe) < 0) {
    > close (read_pipe[0]);
    > close (read_pipe[1]);
    > return -1;
    > }
    >
    > pid = fork ();
    > if (pid < 0) {
    > /* Fork failed. */
    > close (write_pipe[0]);
    > close (write_pipe[1]);
    > close (read_pipe[0]);
    > close (read_pipe[1]);
    > return -1;
    > }
    >
    > if (pid == 0) {
    > /* Child process. */
    > close (0);
    > close (1);
    >
    > close (read_pipe[0]);
    > close (write_pipe[1]);
    >
    > if (dup2 (read_pipe[1], 1) < 0) {
    > close (read_pipe[1]);
    > close (write_pipe[0]);
    > _exit (1);
    > }
    >
    > if (dup2 (read_pipe[1], 2) < 0) {
    > close (read_pipe[1]);
    > close (write_pipe[0]);
    > _exit (1);
    > }
    >
    > close (read_pipe[1]);
    >
    > if (dup2 (write_pipe[0], 0) < 0) {
    > close (write_pipe[0]);
    > _exit (1);
    > }
    >
    > close (write_pipe[0]);
    >
    > execlp ("/bin/sh", "sh", "-c", program, NULL);
    > exit (1);
    > } else {
    > /* Parent process. */
    > close (read_pipe[1]);
    > read_pipe[1] = -1;
    >
    > close (write_pipe[0]);
    > write_pipe[0] = -1;
    >
    > do {
    > bytes = read (read_pipe[0], buffer, sizeof
    > (buffer));
    > printf ("Read = %d.\n", bytes);
    > if (bytes <= 0) {
    > break;
    > }
    >
    > printf ("%.*s", bytes, buffer);
    > } while (1);
    > }
    >
    > return 0;
    > }
    >
    > What I am doing wrong? what am I missing?
    >
    > Thanks in advance,
    >
    > Guido.


    --
    Barry Margolin, barmar@alum.mit.edu
    Arlington, MA
    *** PLEASE post questions in newsgroups, not directly to me ***
    *** PLEASE don't copy me on replies, I'll read them in the group ***

  3. Re: fork - execlp - read output from interactive commands (telnet,ftp)

    Hi Barry,

    thank you very much for your quick answer, now I know what to search
    for in google . I would like to do it programmatically, I hope it is
    not difficult .

    Cheers,

    Guido.

    On May 24, 4:52 pm, Barry Margolin wrote:
    > In article
    > <150c2d19-eed2-4984-b02f-b5a702ec9...@m73g2000hsh.googlegroups.com>,
    >
    > guidore...@gmail.com wrote:
    > > Hi all,

    >
    > > I am writing a program which accepts as parameter a command, executes
    > > the command (fork and execlp) and prints out the output of the
    > > command. It works fine with programs which don't require user's input,
    > > but it doesn't work with programs like telnet or ftp, it blocks trying
    > > to read data from the command.

    >
    > The command is waiting for input on the write_pipe, and you're not
    > supplying it.
    >
    > I suppose you're wondering why you don't even get the FTP prompt, since
    > it's sent before waiting for input. This is because the program is
    > probably using stdio, and stdio buffers output to stdout when it's not
    > connected to a terminal. You won't get anything until the buffer fills
    > up, but it can't fill up until you supply input, so you're in a deadlock.
    >
    > To get around this you need to use a pseudo-tty. One of the best ways
    > to control interactive applications is by using the Expect scripting
    > language, it takes care of this for you. If you don't want to go that
    > far, you can use the "unbuffer" tool that comes with it; instead of
    > running "ftp", run "unbuffer ftp" and it will use a pty to prevent
    > buffering.
    >
    >
    >
    >
    >
    > > The program is:

    >
    > > #include
    > > #include
    > > #include
    > > #include
    > > #include
    > > #include
    > > #include
    > > #include

    >
    > > static int run_program (const char *program);

    >
    > > int main (int argc, char **argv)
    > > {
    > > if (argc != 2) {
    > > printf ("Usage: %s \n", argv[0]);
    > > return -1;
    > > }

    >
    > > return run_program (argv[1]);
    > > }

    >
    > > int run_program (const char *program)
    > > {
    > > int read_pipe[2];
    > > int write_pipe[2];
    > > char buffer[4096];
    > > pid_t pid;
    > > ssize_t bytes;

    >
    > > /* Create pipe for reading data from the child process. */
    > > if (pipe (read_pipe) < 0) {
    > > return -1;
    > > }

    >
    > > /* Create pipe for writing data to the child process. */
    > > if (pipe (write_pipe) < 0) {
    > > close (read_pipe[0]);
    > > close (read_pipe[1]);
    > > return -1;
    > > }

    >
    > > pid = fork ();
    > > if (pid < 0) {
    > > /* Fork failed. */
    > > close (write_pipe[0]);
    > > close (write_pipe[1]);
    > > close (read_pipe[0]);
    > > close (read_pipe[1]);
    > > return -1;
    > > }

    >
    > > if (pid == 0) {
    > > /* Child process. */
    > > close (0);
    > > close (1);

    >
    > > close (read_pipe[0]);
    > > close (write_pipe[1]);

    >
    > > if (dup2 (read_pipe[1], 1) < 0) {
    > > close (read_pipe[1]);
    > > close (write_pipe[0]);
    > > _exit (1);
    > > }

    >
    > > if (dup2 (read_pipe[1], 2) < 0) {
    > > close (read_pipe[1]);
    > > close (write_pipe[0]);
    > > _exit (1);
    > > }

    >
    > > close (read_pipe[1]);

    >
    > > if (dup2 (write_pipe[0], 0) < 0) {
    > > close (write_pipe[0]);
    > > _exit (1);
    > > }

    >
    > > close (write_pipe[0]);

    >
    > > execlp ("/bin/sh", "sh", "-c", program, NULL);
    > > exit (1);
    > > } else {
    > > /* Parent process. */
    > > close (read_pipe[1]);
    > > read_pipe[1] = -1;

    >
    > > close (write_pipe[0]);
    > > write_pipe[0] = -1;

    >
    > > do {
    > > bytes = read (read_pipe[0], buffer, sizeof
    > > (buffer));
    > > printf ("Read = %d.\n", bytes);
    > > if (bytes <= 0) {
    > > break;
    > > }

    >
    > > printf ("%.*s", bytes, buffer);
    > > } while (1);
    > > }

    >
    > > return 0;
    > > }

    >
    > > What I am doing wrong? what am I missing?

    >
    > > Thanks in advance,

    >
    > > Guido.

    >
    > --
    > Barry Margolin, bar...@alum.mit.edu
    > Arlington, MA
    > *** PLEASE post questions in newsgroups, not directly to me ***
    > *** PLEASE don't copy me on replies, I'll read them in the group ***



  4. Re: fork - execlp - read output from interactive commands (telnet,ftp)

    Hi again,

    I have found this article:

    http://www.ddj.com/cpp/184403468

    Thank you very much, Barry.

    Guido.

    On May 24, 5:09 pm, guidore...@gmail.com wrote:
    > Hi Barry,
    >
    > thank you very much for your quick answer, now I know what to search
    > for in google . I would like to do it programmatically, I hope it is
    > not difficult .
    >
    > Cheers,
    >
    > Guido.
    >
    > On May 24, 4:52 pm, Barry Margolin wrote:
    >
    > > In article
    > > <150c2d19-eed2-4984-b02f-b5a702ec9...@m73g2000hsh.googlegroups.com>,

    >
    > > guidore...@gmail.com wrote:
    > > > Hi all,

    >
    > > > I am writing a program which accepts as parameter a command, executes
    > > > the command (fork and execlp) and prints out the output of the
    > > > command. It works fine with programs which don't require user's input,
    > > > but it doesn't work with programs like telnet or ftp, it blocks trying
    > > > to read data from the command.

    >
    > > The command is waiting for input on the write_pipe, and you're not
    > > supplying it.

    >
    > > I suppose you're wondering why you don't even get the FTP prompt, since
    > > it's sent before waiting for input. This is because the program is
    > > probably using stdio, and stdio buffers output to stdout when it's not
    > > connected to a terminal. You won't get anything until the buffer fills
    > > up, but it can't fill up until you supply input, so you're in a deadlock.

    >
    > > To get around this you need to use a pseudo-tty. One of the best ways
    > > to control interactive applications is by using the Expect scripting
    > > language, it takes care of this for you. If you don't want to go that
    > > far, you can use the "unbuffer" tool that comes with it; instead of
    > > running "ftp", run "unbuffer ftp" and it will use a pty to prevent
    > > buffering.

    >
    > > > The program is:

    >
    > > > #include
    > > > #include
    > > > #include
    > > > #include
    > > > #include
    > > > #include
    > > > #include
    > > > #include

    >
    > > > static int run_program (const char *program);

    >
    > > > int main (int argc, char **argv)
    > > > {
    > > > if (argc != 2) {
    > > > printf ("Usage: %s \n", argv[0]);
    > > > return -1;
    > > > }

    >
    > > > return run_program (argv[1]);
    > > > }

    >
    > > > int run_program (const char *program)
    > > > {
    > > > int read_pipe[2];
    > > > int write_pipe[2];
    > > > char buffer[4096];
    > > > pid_t pid;
    > > > ssize_t bytes;

    >
    > > > /* Create pipe for reading data from the child process. */
    > > > if (pipe (read_pipe) < 0) {
    > > > return -1;
    > > > }

    >
    > > > /* Create pipe for writing data to the child process. */
    > > > if (pipe (write_pipe) < 0) {
    > > > close (read_pipe[0]);
    > > > close (read_pipe[1]);
    > > > return -1;
    > > > }

    >
    > > > pid = fork ();
    > > > if (pid < 0) {
    > > > /* Fork failed. */
    > > > close (write_pipe[0]);
    > > > close (write_pipe[1]);
    > > > close (read_pipe[0]);
    > > > close (read_pipe[1]);
    > > > return -1;
    > > > }

    >
    > > > if (pid == 0) {
    > > > /* Child process. */
    > > > close (0);
    > > > close (1);

    >
    > > > close (read_pipe[0]);
    > > > close (write_pipe[1]);

    >
    > > > if (dup2 (read_pipe[1], 1) < 0) {
    > > > close (read_pipe[1]);
    > > > close (write_pipe[0]);
    > > > _exit (1);
    > > > }

    >
    > > > if (dup2 (read_pipe[1], 2) < 0) {
    > > > close (read_pipe[1]);
    > > > close (write_pipe[0]);
    > > > _exit (1);
    > > > }

    >
    > > > close (read_pipe[1]);

    >
    > > > if (dup2 (write_pipe[0], 0) < 0) {
    > > > close (write_pipe[0]);
    > > > _exit (1);
    > > > }

    >
    > > > close (write_pipe[0]);

    >
    > > > execlp ("/bin/sh", "sh", "-c", program, NULL);
    > > > exit (1);
    > > > } else {
    > > > /* Parent process. */
    > > > close (read_pipe[1]);
    > > > read_pipe[1] = -1;

    >
    > > > close (write_pipe[0]);
    > > > write_pipe[0] = -1;

    >
    > > > do {
    > > > bytes = read (read_pipe[0], buffer, sizeof
    > > > (buffer));
    > > > printf ("Read = %d.\n", bytes);
    > > > if (bytes <= 0) {
    > > > break;
    > > > }

    >
    > > > printf ("%.*s", bytes, buffer);
    > > > } while (1);
    > > > }

    >
    > > > return 0;
    > > > }

    >
    > > > What I am doing wrong? what am I missing?

    >
    > > > Thanks in advance,

    >
    > > > Guido.

    >
    > > --
    > > Barry Margolin, bar...@alum.mit.edu
    > > Arlington, MA
    > > *** PLEASE post questions in newsgroups, not directly to me ***
    > > *** PLEASE don't copy me on replies, I'll read them in the group ***



+ Reply to Thread