I am trying to control ftp client from C program (OS X). I did fork and execve - process is started ok. The problem is with pipes - I can send command to ftp client process and get feedback from it just fine (If i send "help\n" i get back help output) but what I never get in pipe is "ftp> " prompt. Any ideas?
Ivan
Your ftp client is probably behaving differently if stdin/stdout is a terminal or something else (lots of program do, for a start the C library does buffering in a different way...) If you want to control that, search information about pseudo-terminals, that's a little too technical to be explained here. (And looks first at programs like expect, it's possible you won't have to write yours).
A program can examine stdin to find out whether it's a terminal or a pipe. In your case, the FTP program probably does that (for example to know whether it can use escape sequences to render progress bars or offer command line editing).
If you really need the prompt, you have to look into PTYs (pseudo terminals) which emulate a console.
wild guess: isn't the "ftp>" prompt written to STDERR ?
Related
I know how to get the stdout into a file using dup/dup2 system calls, but how do I get the entire output that would be normally shown on my terminal(including the prompt that says my username along with the $ symbol and the current working directory) to a file?
Yes you can, but this may be difficult in many details (depending on your expert level). For the shell to behave normally (I would mean exactly as in a terminal), then it needs to interact with a terminal (special system object). So you need to create a program that behave like a terminal, this what pseudo-terminals devices (/dev) are intended for. Read documentation about this to implement it but roughly, your application should behave like the user so should be connected to the slave side of the pseudo-terminal, and the shell to the master side of the pseudo-terminal. Then you can easily log real inputs made by the user and catch outputs made by the shell.
Can't comment cause of low reputation.
I would say there is no way to do that inside a code in C. Instead, you could use bash for example to redirect everything to a file, and leave the code in C as it is.
In this way you have all the info you want to save: prompt, current directory, call to the program (including flags), and of course the output of the program.
Well, you can do:
-For bash prompt PS1: Echo expanded PS1 (in case you want it expanded, if not there is a simple way to do it just echong PS1)
- For executed command: https://unix.stackexchange.com/questions/169259/how-to-capture-command-line-input-into-logfile-and-execute-it-at-the-same-time
- Standard output and error output: Redirect stderr and stdout in a Bash script
And that's all you want to capture, I think.
Look up the script command in Unix systems. If you want to capture all keyboard and std in/out for a command, use the script executable. If you want to see how it's done, look up the source.
I've currently written a udp client, which simply listens on specified port, for packets destined to a specific multicast group.
at the end, i'm printing the input to stdout in the following manner:
write(STDOUT_FILENO, buffer, num_of_bytes);
And executing the program in the following manner:
./udp_listen 224.10.10.10 4567 | mpg321 -
That way all output is piped to mpg321 app, which plays the stream of bytes as music.
The above implementation, is of course making me kind of "lose control" over my program, as it opens mpg321 app and plays.
I want to avoid this, and in someway, pipe the write(....) into mpg321, directly within my program.
How can one achieve this? I'm coding in C.
Thank you.
Thanks #kaylum for providing the answer i was looking for.
i've used popen with the command to initiate mpg321 , with redirecting its stderr output to a file.
After that i've used fileno() method to get the file descriptor number,
to be used with write() calls.
Worked great.
Thanks
I'm parsing a large log file. I would like to pull out particular messages based on a severity classification (critical, warning, etc). As I am parsing the log I would like to send messages, based on their severity, to a given, spawned, severity-specific, terminal. The terminals should not close when the main program finishes reading the log file. Environment is solaris 10/gcc 3.4.6. I found the following example that captures what I was thinking of, but doesn't quite work (xterm spawns, but no output is sent to it):
#include <stdio.h>
int main()
{
FILE *output;
int i;
output = popen ("xterm", "w");
for (i = 0; i < 10; i++)
fprintf (output, "%d\n", i);
pclose (output);
}
I'm not married to xterm, I simply used it as handy and I do like the ability to title, color and size them. I sort of get that writing to the handle generated by popen is not the same as writing to the terminal's output (just sort of...). This seems like an easy thing to do.
in general, what can be done is:
1) adjust your application so it can accept a parameter that indicates what level of severity to output to stdout.
2) open three terminals from the keyboard
3) run your application in each terminal, giving each execution the appropriate command line parameter
if your going to open the terminals from your application, for 'xterm' and others, the --hold parameter will stop the terminal from closing when you application exits
The idea of the pipe sounds reasonable, but there are a few problems:
you cannot, of course, simply write to a newly-spawned terminal via a pipe. xterm will ignore that; it is the application running within xterm which reads/writes from the pseudo-terminal.
there is no way to scroll back in the messages sent to a given terminal
the suggested writes to the pty device cannot be captured by a program running in the terminal
Rather than sending to a terminal, you might consider getting xless (a simple X application which might already be part of a package, but is simple enough to build), and structuring your output function to do this:
for each message category, open a pipe to xless once
write the message
do not close the pipe
That would give you windows which do not close. Here is a sample screenshot:
The source can be found on ftp.x.org, as noted in the Debian package description.
Thank you all for the great responses, I do appreciate them!
OK, sounds like a slight re-design is called for =) I did a quick prototype and it looks like it will work. Will write the output to separate severity files, then when complete, pop up an xterm for each file, something like
sprintf (Crit, "xterm <yadda yadda> -e sh -c 'cat <crit-log>; <yadda yadda>');
popen (Crit, "r");
Writing to intermediate log files is actually a bonus should they need to be reviewed at a later time without having to go through the large-log-parsing program again.
Thanks again everyone!
My situation is the following: I've got a lot of small gizmos ( pretty close to routers, not exactly but anyway that's irrelevant) ; they are running a bare-bones MIPS-based Linux distro.
To control them, one can telnet there ( thru serial port ) and issue commands to an interactive bash-like shell which then writes back some output. The shell's input and output are both attached to /dev/ttyAS0.
Now, I'd like to automate all of this, i.e. write a program that will run inside the gizmo, be a small server listening on some port, and which would pass on any command to the said shell, capture shell's output and relay it back to whoever contacted to server.
I:
1) can install (small, <500KB) programs inside the gizmo
2) can't modify the OS, startup scripts, the shell, anything
3) have root access
4) know how to write a SOAP server
5) know how to get a SOAP message, translate it to a command and inject it into /dev/ttyAS0
6) DONT KNOW how to capture the shell's reply
7) know how to, having shell's reply, translate it back to a SOAP message and reply to the original inquirer.
So basically, the problem is 6) : how to, having injected a string to /dev/ttyAS0 and thus having made the shell execute it, capture the shell's output ?
I am aware of
http://etbe.coker.com.au/2008/02/27/redirecting-output-from-a-running-process/
i.e. I know that I could change the shell's stdout if I had GDB ( or strace ) running inside the box, but I can't install it there - it's too big and anyway this approach seems too much like a hack.
So, summarizing:
How root can capture stdout of an already running process, IN PURE C, without gdb or strace, with no access to the way the process is started?
Or - almost equivalently - how to capture what's being written to a terminal, IN PURE C ?
You might want to take a look at reptyr. It will probably need some adaptation to work for your system though
Have you tried driving the serial port with a kermit script? I would probably forgo trying to insert a more clever proxy on the device and just try and drive the existing interface.
If you really want to get it on the device, you may be able to look at the source to something like screen or kermit to get a sense of how they interact with ttys.
I need to run a script and have access to the default stdin (terminal input) in my program. I could do ./program "script", opening and parsing the script through the program, but I want to make it POSIX style, accepting input from pipes or from redirection.
I mean, since my program is a parser, I could run ./program, type the script and still use stdin (in a scanf, for example). But I'd like to run ./program < script and still be able to use stdin (in a scanf).
My program is a simplified Pascal interpreter, that's why I need to run read(x) and write(x) in my scripts.
Yes, it's homework (the intepreter), but the doubt just popped up in the brainstorming process.
The current controlling terminal can be accessed using /dev/tty, even if stdin has been redirected.
ttyname(0) will return the filename of the current terminal associated with stdin. You can then open that and read from it.
If I understand what you're asking, you're asking for the ability to take in interactive input from a user when using file redirection, like the ./program < script bit above.
I don't believe there's a way to do that. A POSIX system will feed the script in via stdin and that's that. No interaction from the user.
It's also worth noting that you don't have to do anything special to realize that. Just treat stdin like you normally would. You don't have to think about whether it's coming in interactively or from a file, which is really quite nice.