redirection to multiple ttys in c - c

I see that I can do freopen to redirect stdout going to a console to one another tty. I am trying to redirect the same to multiple terminals including the console. Console is where the program is running. What is the best way to do it?
TIA

You didn't specify what platform you're using, but assuming you can find the file path to the TTY you'd like to redirect to, you can call freopen on the stdout file descriptor. However, that would close the initial file descriptor, which doesn't sound like your desired behavior. A file descriptor can only point to one file.
The easiest C solution is probably going to be a wrapper around printf that calls it on all of your specified files. You might be able to do something with threading, but that's likely to complicate things.
If you're on a *nix system, I suggest using tee which is made for outputting to stdout and secondary files.

There is no really easy way to do this like with freopen. You need some wrapper that takes the input and writes it to each output tty individually.
For example there is the tee program that multiplexes its input to stdout and a number of files. You could for example create a pipe in C that is connected to tee /dev/ttyX /dev/ttyY .... Then you can replace stdout with the pipe file descriptor and you will get the desired behaviour.

Related

C redirect terminal descriptor

It's possible to redirect everything that is written in the terminal to a process?
For example, after I started the process, if I write "command" in the terminal, this should be redirected to a pipe from my process or something like this.
Yes, it should be practical to redirect all terminal output from your program (and all of its child processes) after your program has started. Unix programs usually write to the terminal by writing to standard output (stdout). Standard output is always on the file descriptor number 1 (the C constant is STDOUT_FILENO), for all processes. You can use the dup2() system call to replace any file descriptor number with another file descriptor.
So you can e.g. create a pipe using int fds[2]; pipe(fds);. Then fds[1] will be a file descriptor number that you can use to write to the pipe. If you do dup2(fds[1], STDOUT_FILENO); then standard output will also write to the pipe. (You can close(fds[1]); afterwards since you probably don't need it, now that you can use stdout instead.)
You can also open a file for writing with fd = open("filename", O_WRONLY); and then dup2(fd, STDOUT_FILENO); so everything written to stdout goes into your file.
Note that you need to redirect stdout at the very beginning of your program before doing anything that might write to stdout.
The above trick will make standard output go to your pipe instead of the terminal. If you want the output to go to the terminal, and also get a copy of the output in a pipe of file, that's more difficult but can also be done. You need to create an internal pipe, then dup2(that_pipe, STDOUT_FILENO); so stdout writes to that pipe. Then you need to read from that pipe (probably using poll() then read()) and write everything you got to both 1) the terminal and 2) to another pipe or file that is going outside your program. So you need two pipes if you want to copy output.
The tee command does this (copy stdout to files) from the shell.
This dup2() approach is not bulletproof because a Unix terminal (even when using a GUI terminal emulator instead of a hardware console) is a device in /dev. You can type tty in a shell or use ttyname(STDOUT_FILENO) in C to see which file in /dev corresponds to the terminal that stdout is writing to. In principle, any program (under the same user account) could open the terminal device using that filename and write to it without asking for permission from any other program. You can easily try this from the shell using the write program:
echo hello world | write $(whoami) /dev/ttys123
where /dev/ttys123 is whatever you got by typing tty in some other terminal window (the name looks a bit different on different operating systems, e.g. Linux and MacOS). You should see hello world appear in that other window.
From a child process, no. You must set this up in the parent preocess, and have it propagate downwards to children (barring some kind of crazy hack).
From the shell, you can redirect.
exec >file
This will redirect standard output to file, and it will apply to all future commands run in the shell. You can make this into a function, if you like.

Redirect stderr to both file and stdout in C

Is there a way to write the error messages to a log file and also print them on the terminal screen?
I tried the following:
dup2(fileno(pFile), STDERR_FILENO); /* redirect stderr to file */
which redirects stderr to the file. However, that writes the error messages to the file but does not show them on screen.
Can this be done without reading and copying the contents of stderr to the file?
Note: I would like to not invoke the shell (system, popen). I did look the implementation of the tee command of coreutils. It copies the standard stream to files.
You have to copy the data "by hand" to send it to two places, though it can be made slightly more efficient with the linux-specific tee and splice system calls (note tee syscall not tee command, http://blog.superpat.com/2010/07/08/a-cup-of-tee-and-a-splice-of-cake/)
It sounds like you might know how to do it and were just hoping not to, but for others, the solution could be something like:
dup2 the original stderr (typically the terminal) to a new file descriptor to save it. Then make a pipe with pipe(). dup2 the write end of the pipe to fd 2. close original write end fd. Now your stderr is a pipe. Start up a thread, or process. In this thread, you copy data from the read end of your pipe into both the file and the original stderr which you saved. When the thread or process gets EOF reading the pipe, close it and exit.
The popen("tee") solution is the same except that it creates an extra shell process (and you have to properly quote the filename passed to the shell in case there are special chars in it... be sure to test weird filenames with greater than sign, spaces, and quote marks in them...). If using popen I think you may also have a (cosmetic?) problem that you can't pclose() because your stderr would stop working, so you will always leave an extra fd open and won't wait4() the child.
If you were using something like GLib, it has a g_spawn_async family of functions which could be used to spawn the tee command without a shell. Otherwise, you would have to do the fork/exec stuff by hand to avoid the shell; you could exec the tee command, or you could fork but NOT exec - just have the child code after fork do the stderr copying, don't rely on the tee command. Or, you could use a thread instead of a process.
If using fork, you may find the source code in gspawn.c helpful; in any complex program it's quite a nightmare that FD_CLOEXEC is not the default on unix for example and it's easy to have the child inherit descriptors that cause problems.
It is also pretty annoying to avoid zombie processes and handle all the errors and blah blah.
Anyway yeah it is more code than one might hope but between the tee source in coreutils and gspawn.c you might have most of it available to copy.
Use a pipe to the tee command.
pFile = popen("tee logfile", "w");
dup2(fileno(pFile), STDERR_FILENO);

Where does stderr file dumps its content to?

I wanted to know like where does the stderr dumps its content.
I have a question like whether it dumps to syslog?
Please explain.
stderr is just another output stream, just like stdout.
Where it's hooked up depends on how the application is called.
For example if I run foo.exe 2> errors.txt then stderr will write to the specified file.
Stderr output is dumped whenever you decide to redirect it.
If you run a program in a GUI enviroment, by clicking on an icon or something, look for .xsession-errors in your $HOME.
If you run a program from a shell and don't redirect stderr, you just see it on your terminal (and it is not saved anywhere else).
That depends on the environment.
By default, stderr is typically connected to the same place as stdout, i.e. the current terminal.
Otherwise, you wouldn't see the errors which would be kind of annoying.
Here is a blog post about redirecting stderr to the system's logging mechanism.
stderr is a stream. It's managed by and output to by the owning process. Where it 'goes' is defined by how the process is invoked. The parent process can gather it and write it to a file, ignore it, redirect it to /dev/null (esssentially binning it) etc.
Whilst stderr can be redirected elsewhere, it typically outputs to the same place as stdout. To make it into syslog, you'd definitely have to work a bit. This link:
With bash, how can I pipe standard error into another process?
shows how you pipe stderr to a pipe, and if the other process is a process that writes to "syslog", it would do what you want. But for most cases, it's probably easier to just add syslog functionality to your own program.

How to redirect the output of a c program to a file?

I am trying to redirect the output of a c program to file, even when it generates some errors because of problems with the input data. I can send the output but the error messages to a file.
Does somebody know how to do it?
From within C source code, you can redirect outputs using freopen():
General outputs:
freopen("myfile.txt", "w", stdout);
Errors:
freopen("myfile_err.txt", "w", stderr);
(This answer applies to bash shell, and similar flavors. You didn't specify your environment and this sort of question needs that detail.)
I assume you know about basic redirection with ">". To also capture STDERR in addition to STDOUT, use the following syntax:
command > file-name 2>&1
For some more background on standard streams and numbers:
http://en.wikipedia.org/wiki/Standard_streams#Standard_input_.28stdin.29
This depends on what you mean and what platform you are using. Very often you can accomplish this from the command line, which has been covered in another answer. If you use this method to accomplish this you should be aware that FILE * stderr is typically written immediately (unbuffered) while FILE * stdout may be buffered (usually line buffered) so you could end up with some of your error messages appearing to have been printed earlier than some other messages, but actually the other messages are just being printed late.
From within a C program you can also do something similar within the stdio system using freopen, which will effect the FILE *, so you could make fprintf(stderr, "fungus"); print to something besides what stderr normally would print to.
But if you want to know how to make a program redirect the actual file descriptors under a unix like system you need to learn about the dup and dup2 system calls. They allow you to duplicate a file descriptor.
int fd = open("some_file", O_WRONLY);
dup2(2,fd);
close(fd);
This code will make "some_file" the new stderr at the OS level. The dup2 call will close and replace file descriptor 2 (stderr, which is usually used by FILE * stderr but not necessarily if you call freopen(x,y,stderr) since that may make FILE *stderr use a different file descriptor).
This is how shell programs redirect input and output of programs. The open all of the files that the new program will need, fork, then the child uses dup2 to set up the files descriptors for the new program, then it closes any files that the new program won't need (usually just leaving 0, 1, and 2 open), and then uses one of the exec functions to become the program that the shell was told to run. (some of this isn't entirely accurate because some shells may rely on close on exe flags)
Using a simple linux command you can save the output into the file. here is a simple linux terminal command.
ls > file.txt
The output of this command will be stored into the file.
same as you can store the output of the program like this suppose, object file name is a, run the following command to save output in a file:
./a > file.txt

How to access the default stdin while using file redirection?

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.

Resources