C redirect terminal descriptor - c

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.

Related

redirection to multiple ttys in 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.

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);

How to Obtain Pseudo Terminal Master file descriptor from inside ssh session?

in C or bash,
I was wondering how, if possible, do you obtain from inside an ssh session, the file descriptor to the pseudo terminal master responsible for getting input to that's session's slave(pts).
The shell process has no master file descriptor, only slave.
The shell's parent process (be it sshd or xterm or screen or whatever) creates a new master by calling getpt(3) or posix_openpt(3). The function returns the master file descriptor. The parent process then obtains the slave file descriptor by calling a combination of grantpt(3), unlockpt(3), ptsname(3) and open(2). This is for Linux and other POSIXized systems, other *nixes may use other functions, but the net result is the same. The parent process has the master/slave pair of file descriptors.
The slave descriptor, and the slave descriptor only, is then passed to the shell as its standard input, output and error.
From Solaris 5.8 PTS(7D) Man-page - STREAMS pseudo-tty slave driver
Only one open is allowed on a master device.
I guess that answers my question :)
EDIT: actually it does not, because if there is a way to obtain the file descriptor, i won't need to open again, it is a file descriptor lol , no need to open
On unix-based systems, you can open the controlling terminal of the current process by opening /dev/tty. In many cases your program will already have this open as stdin, stdout and stderr, but even if your program is being invoked with stdin, stdout or stderr redirected, /dev/tty will give you the controlling terminal of the process.

where stdin / stdout created

In c( ansi ) , we say input taken by (s/v/f)scanf and stored in stdin , same as we say
stdout . I wonder, in linux ( unix ) where are they reside, under which folder .
Or they ( stdin / stdout ) are arbitrary ( that is, no such things exist )
They are streams created for your process by the operating system. There is no named file object associated with them, and so they do not have a representation within the file system, although as unwind points out, they may be accessed via a pseudo file system if your UNIX variant supports such a thing.
stdin is a FILE * referring to the stdio (standard io) structure that is tied to the file descriptor 0. File descriptors are what Unix-like systems, such as Linux, use to talk with applications about particular file-like things. (Actually, I'm pretty sure that Windows does this as well).
File descriptor 0 may refer to any type of file, but to make sense it must be one that read can be called on (it must be a regular file, a steam socket, or a character device opened for reading or the read side of a pipe, as opposed to a directory file, data gram socket, or a block device).
Processes in Unix-like systems inherit their open file descriptors from their parent process in Unix-like systems. So to run a program with stdin set to something besides the parent's stdin you would do:
int new_stdin = open("new_stdin_file, O_RDONLY);
pid_t fk = fork();
if (!fk) { // in the child
dup2(new_stdin, 0);
close(new_stdin);
execl("program_name", "program_name", NULL);
_exit(127); // should not have gotten here, and calling exit (without _ ) can have
// side effects because it runs atexit registered functions, and we
// don't want that here
} else if (fk < 0) {
// in parent with error from fork
} else {
// in parent with no error so fk = pid of child
}
close(new_stdin); // we don't need this anymore
dup2 duplicates the first file descriptor argument as the second (closing the second before doing so if it were open for the current process).
fork creates a duplicate of the current process. execl is one of the exec family of functions, which use the execve system call to replace the current program with another program. The combination of fork and exec are how programs are generally run (even when hidden within other functions).
In the above example we could have run the new program with stdin set to the read end of a pipe, a tty (serial port / TeleTYpe), or several other things. Some of these have names present in the filesystem and others do not (like some pipes and sockets, though some do have names in the filesystem).
Linux makes /proc/self/fd/0 a symbolic link to the file opened as 0 in the current process. /proc/%i/fd/0, pid would represent the symbolic link to the same thing for an arbitrary pid (process ID) using the printf syntax. These symbolic links are often usable to find the real file in the filesystem (using the readlink system call), but if the file does not actually exist in the filesystem the link data (what would usually be a file name) instead is just a string that tells a little bit about the file.
I should point out here that a file that stdin (fd 0) refers to, even if it is in the filesystem, may not have just one name. It may have more than one hard link, so it would have more than one name -- and each of these would be just as much its name as any other hard link. Additionally it may have no name at all if all of its hard links have been unlinked since it was opened, though it's data would still live on the disk until all open file descriptors for it are closed.
If you don't actually need to know where it is in the filesystem, but just want some data about it you can use the fstat system call. This is like the stat system call and command line utility, except for already open files.
Everything I said here about stdin (fd 0) should be applicable to stdout (fd 1) and stderr (fd 2) except that they will both be writable rather than readable.
If you want to know more about any of the functions I mentioned be sure to look them up in the man pages by typing:
man fork
on the command line. Most functions I mentioned are in section 2 of the man pages, but one or two may be in section one, so man 2 fork will work too, and may be useful when a command line tool has the same name as a function.
In Linux, you can generally find stdin through the /proc file system in /proc/self/fd/0, and stdout is /proc/self/fd/1.
stdin is standard input - for example, keyboard input.
stdout is standard output - for example, monitor.
For more info, read this.
If you run:
./myprog < /etc/passwd
then stdin exists in the filesystem as /etc/passwd. If you just run
./myprog
interactively on a terminal, then stdin exists in the filesystem as whatever your terminal device is (probably /dev/pts/5 or something).
If you run
cat /etc/passwd | ./myprog
then stdin is an anonymous pipe and has no instantiation in the filesystem, but Linux allows you to get at it via /proc/12345/fd/0 where 12345 is the pid of myprog.

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

Resources