Poking a character into a parent process's buffer - c

I am trying to write a program that runs in the background that can "type" into a parent process, e.g. issue shell commands as if I had typed them myself at the keyboard. I have tried doing this with ungetc() to push back to STDIN:
#include <stdio.h>
int main (int argc, char** argv) {
ungetc('x', stdin);
return 0;
}
I would expect that doing:
$ gcc -o unget unget.c
$ ./unget&
Would have left me at the $ prompt with x there as if I'd just typed it, but instead I get nothing. Have I "lost" STDIN by going into the background? Thanks!

What you're trying to do simply cannot work. ungetc operates on the stdio FILE buffer, not the underlying open file description, and thus there is no way for it to be shared with another process.
You might try running the interactive session in screen and using screen's exec command to redirect file descriptors through a process that will inject data. Or you could implement something like this yourself using pseudo-tty devices.
Further, from your comments, I think what you're trying to do is an extremely bad idea. If you get unlucky and the input comes in the middle of you typing something interactively, it could have disastrous consequences. For instance imaging the automated command is
command_foo my_important_file
Now suppose you're in the middle of typing
rm -rf useless_crap
Bam! my_important_file just got deleted.

This second answer is not so much an answer to your question as written, but to the problem you're trying to solve. It's much more robust than sending keystrokes to your shell.
In the shell, use the trap command to setup a signal handler. For example:
trap "echo hello" USR2
Replace USR2 with whatever signal you want to use. Then run a child process that periodically sends the signal to its parent.

No -- ungetc only "pushes" the character back into the programs own buffer, so when the next character that same program reads will be what was passed to ungetc. Transmitting something back to the parent requires something entirely different (e.g., creating some pipes).

Just off the top of my head, maybe you could tweak the pipes of your terminal so that the cout of your child is cin for the parent. In bash it would go something like this:
exec 6>&1
exec 7<&0
exec 1>&7
exec 0<&6
Then when you start your programs the pipes should be inverted. So everything you put into cout should come out at cin from your parent (the bash process in this case).

Related

Outputting to multiple terminals

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!

Create two processes when another terminal window is opened?

The topic might sound weird, but here's what I want to achieve:
In Terminal A, type command line as following:
./create proA
The first process proA is created. It outputs something like
This is process A.
Open another terminal window (called Terminal B). In Terminal B, type the following line:
./create proB
The second process proB is created. It outputs:
This is process B.
UPDATED:
I'm trying to create two processes that communicate with each other. Before going into more details, I just want to try if I can create another process that has some relationship with first process when another terminal window is opened.
Is it possible to achieve something like this? If so, can someone give any tip for how to start in c? Thanks!
The terminals don't matter for inter process communication. There are so many ways to communicate between processes that it doesn't make sense to highlight any of them here.
About having a own terminal for each process. Well:
(xterm -e "${COMMANDLINE1}" &) ; (xterm -e "${COMMANDLINE2}" &)
if you want to see only errors, you should use:
./process > /dev/null 2>&1
if you did't understood 2>&1, read below)
possible numbers:
0 — STDIN, 1 — STDOUT and 2 — STDERR
that means, all std errors will be printed in std out.

Using streams to pipe input/output between *nix processes

I'm working on a fairly simple application in C. The end goal is to pipe the output from one process to in input of another in a *nix environment (yes, I am aware of the pipe() command and dup/dup2 but I'm trying to find away around using those commands). I was wondering if there is any way to connect the streams rather than using file descriptors (The systems aren't guaranteed to be POSIX compliant).
So basically I want to do something like this (pseudo-code)
pid = fork()
if pid == 0
// assign this process's stdin to the parents stdout.
stdin = parent.stdout;
exec() // launch new process that receives the parents stdout as stdin
// child stuff....
else
// parent stuff....
I know that it probably won't be as simple as just doing an assignment as above, but is there any way to do this using only streams? I tried looking around, but couldn't find anything..
Thanks!
sorry if I'm missing the point here but the whole philosophy of *nix is one program, one job. If you need a program to dump the contents of a program to the screen then you have the cat command. If the files too big and you need page breaks you pipe the output of cat to the more command:
cat myfile.txt | more
If you need to pipe between two terminal applications then you're meant to use the command line to do so:
myprog1 | myprog2
Obviously that's the philosophical approach, so if that doesn't help then can you clarify what you're trying to pipe and why you're trying to do it in process ?

Is it possible to run a program from terminal and have it continue to run after you close the terminal?

I have written a program which I run after connecting to the box over SSH. It has some user interaction such as selecting options after being prompted, and usually I wait for the processes it carries out to finish before logging out which closes the terminal and ends the program. But now the process is quite lengthy and I don't want to wait whilst being logged in, so how could I implement a workaround for this in C please?
You can run a program in the background by following the command with "&"
wget -m www.google.com &
Or, you could use the "screen" program, that allows you to attach-deattach sessions
screen wget -m www.google.com
(PRESS CTRL+D)
screen -r (TO RE ATTACH)
http://linux.die.net/man/1/screen
The process is sent the HUP signal when the shell exits. All you have to do is install a signal handler that ignores SIGHUP.
Or just run the program using nohup.
The traditional way to do this is using the nohup(1) command:
nohup mycmd < /dev/null >& output.log &
Of course if you don't care about the output you can send it to /dev/null too, or you could take input from a file if you wanted.
Doing it this way will protect your process from a SIGHUP that would normally cause it to exit. You'll also want to redirect stdin/stdout/stderr like above, as you'll be ending your ssh session.
Syntax shown above is for bash.
you can use screen command. here is a tutorial. note you might need to install it to your systems.
There are many options :-) TIMTOWTDI… However, for your purposes, you might look into running a command-line utility such as dtach or GNU screen.
If you actually want to implement something in C, you could re-invent that wheel, but from your description of the problem, I doubt it should be necessary…
The actual C code to background a process is trivial:
//do interactive stuff...
if(fork())
exit(0);
//cool, I've been daemonized.
If you know the code will never wind up on a non-linux-or-BSD machine, you could even use daemon()
//interactive...
daemon(0, 0);
//background...

A Linux Daemon and the STDIN/STDOUT

I am working on a linux daemon and having some issues with the stdin/stdout. Normally because of the nature of a daemon you do not have any stdin or stdout. However, I do have a function in my daemon that is called when the daemon runs for the first time to specify different parameters that are required for the daemon to run successfully. When this function is called the terminal becomes so sluggish that I have to launch a seperate shell and kill the daemon with top to get a responsive prompt back. Now I suspect that this has something to do with the forking process closing the stdin/stdout but I am not quite sure how I could work around this. If you guys could shed some light on the situation that would be most appreciated. Thanks.
Edit:
int main(argc, char *argv[]) {
/* setup signal handling */
/* check command line arguments */
pid_t pid, sid;
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
if(pid > 0){
exit(EXIT_SUCCESS);
}
sid = setsid();
if(sid < 0) {
exit(EXIT_FAILURE);
}
umask(027);
/* set syslogging */
/* do some logic to determine wether we are running the daemon for the first time and if we are call the one time function which uses fgets() to recieve some input */
while(1) {
/* do required work */
}
/* do some clean up procedures and exit */
return 0;
}
You guys mention using a config file. This is is exactly what I do to store the parameters recieved via input. However I still initially need to get these from the user via the stdin. The logic for determining whether we are running for the first time is based off of the existence of the config file.
Normally, the standard input of a daemon should be connected to /dev/null, so that if anything is read from standard input, you get an EOF immediately. Normally, standard output should be connected to a file - either a log file or /dev/null. The latter means all writes will succeed, but no information will be stored. Similarly, standard error should be connected to /dev/null or to a log file.
All programs, including daemons, are entitled to assume that stdin, stdout and stderr are appropriately opened file streams.
It is usually appropriate for a daemon to control where its input comes from and outputs go to. There is seldom occasion for input to come from other than /dev/null. If the code was written to survive without standard output or standard error (for example, it opens a standard log channel, or perhaps uses syslog(3)) then it may be appropriate to close stdout and stderr. Otherwise, it is probably appropriate to redirect them to /dev/null, while still logging messages to a log file. Alternatively, you can redirect both stdout and stderr to a log file - beware continuously growing log files.
Your sluggish-to-impossible response time might be because your program is not paying attention to EOF in a read loop somewhere. It might be prompting for user input on /dev/null, and reading a response from /dev/null, and not getting a 'y' or 'n' back, it tries again, which chews up your system horribly. Of course, the code is flawed in not handling EOF, and counting the number of times it gets an invalid response and stopping being silly after a reasonable number of attempts (16, 32, 64). The program should shut up shop sanely and safely if it expects a meaningful input and continues not to get it.
You guys mention using a config file. This is is exactly what I do to store the parameters recieved via input. However I still initially need to get these from the user via the stdin. The logic for determining whether we are running for the first time is based off of the existence of the config file.
Instead of reading stdin, have the user write the config file themselves; check for its existence before forking, and exit with an error if it doesn't. Include a sample config file with the daemon, and document its format in your daemon's manpage. You do have a manpage, yes? Your config file is textual, yes?
Also, your daemonization logic is missing a key step. After forking, but before calling setsid, you need to close fds 0, 1, and 2 and reopen them to /dev/null (do not attempt to do this with fclose and fopen). That should fix your sluggish terminal problem.
Your design is wrong. Daemon processes should not take input via stdin or deliver output to stdout/stderr. You'll close those descriptors as part of the daemonizing phase. Daemons should take configuration parameters from the command line, a config file, or both. If runtime-input is required you'll have to read a file, open a socket, etc., but the point of a daemon is that it should be able to run and do its thing without a user being present at the console.
If you want to run your program detached, use the shell: (setsid <command> &). Do not fork() inside your program, which will cause sysadmin nightmare.
Don't use syslog() nor redirect stdout or stderr.
Better yet, use a daemon manager such as daemon tools, runit, OpenRC and systemd, to daemonize your program for you.
Use a config file. Do not use STDIN or STDOUT with a daemon. Daemons are meant to run in the background with no user interaction.
If you insist on using stdin/keyboard input to fire up the daemon (e.g. to get some magic passphrase you wouldn't want to store in a file) then handle all I/O before the fork().

Resources