How to Redirect Output of an Already Running Process

How to redirect output of an already running process

See Redirecting Output from a Running Process.

Firstly I run the command cat > foo1 in one session and test that data from stdin is copied to the file. Then in another session I redirect the output.

Firstly find the PID of the process:

$ ps aux | grep cat
rjc 6760 0.0 0.0 1580 376 pts/5 S+ 15:31 0:00 cat

Now check the file handles it has open:

$ ls -l /proc/6760/fd
total 3
lrwx—— 1 rjc rjc 64 Feb 27 15:32 0 -> /dev/pts/5
l-wx—— 1 rjc rjc 64 Feb 27 15:32 1 -> /tmp/foo1
lrwx—— 1 rjc rjc 64 Feb 27 15:32 2 -> /dev/pts/5

Now run GDB:

$ gdb -p 6760 /bin/cat
GNU gdb 6.4.90-debian

[license stuff snipped]

Attaching to program: /bin/cat, process 6760

[snip other stuff that's not interesting now]

(gdb) p close(1)
$1 = 0
(gdb) p creat("/tmp/foo3", 0600)
$2 = 1
(gdb) q
The program is running. Quit anyway (and detach it)? (y or n) y
Detaching from program: /bin/cat, process 6760

The p command in GDB will print the value of an expression, an expression can be a function to call, it can be a system call… So I execute a close() system call and pass file handle 1, then I execute a creat() system call to open a new file. The result of the creat() was 1 which means that it replaced the previous file handle. If I wanted to use the same file for stdout and stderr or if I wanted to replace a file handle with some other number then I would need to call the dup2() system call to achieve that result.

For this example I chose to use creat() instead of open() because there are fewer parameter. The C macros for the flags are not usable from GDB (it doesn’t use C headers) so I would have to read header files to discover this – it’s not that hard to do so but would take more time. Note that 0600 is the octal permission for the owner having read/write access and the group and others having no access. It would also work to use 0 for that parameter and run chmod on the file later on.

After that I verify the result:

ls -l /proc/6760/fd/
total 3
lrwx—— 1 rjc rjc 64 2008-02-27 15:32 0 -> /dev/pts/5
l-wx—— 1 rjc rjc 64 2008-02-27 15:32 1 -> /tmp/foo3 <====
lrwx—— 1 rjc rjc 64 2008-02-27 15:32 2 -> /dev/pts/5

Typing more data in to cat results in the file /tmp/foo3 being appended to.

If you want to close the original session you need to close all file handles for it, open a new device that can be the controlling tty, and then call setsid().

Redirect STDERR / STDOUT of a process AFTER it's been started, using command line?

Short of closing and reopening your tty (i.e. logging off and back on, which may also terminate some of your background processes in the process) you only have one choice left:

  • attach to the process in question using gdb, and run:

    • p dup2(open("/dev/null", 0), 1)
    • p dup2(open("/dev/null", 0), 2)
    • detach
    • quit

e.g.:

$ tail -f /var/log/lastlog &
[1] 5636

$ ls -l /proc/5636/fd
total 0
lrwx------ 1 myuser myuser 64 Feb 27 07:36 0 -> /dev/pts/0
lrwx------ 1 myuser myuser 64 Feb 27 07:36 1 -> /dev/pts/0
lrwx------ 1 myuser myuser 64 Feb 27 07:36 2 -> /dev/pts/0
lr-x------ 1 myuser myuser 64 Feb 27 07:36 3 -> /var/log/lastlog

$ gdb -p 5636
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Attaching to process 5636
Reading symbols from /usr/bin/tail...(no debugging symbols found)...done.
Reading symbols from /lib/librt.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/librt.so.1
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/libpthread.so.0...(no debugging symbols found)...done.
[Thread debugging using libthread_db enabled]
[New Thread 0x7f3c8f5a66e0 (LWP 5636)]
Loaded symbols for /lib/libpthread.so.0
Reading symbols from /lib/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2

(no debugging symbols found)
0x00007f3c8eec7b50 in nanosleep () from /lib/libc.so.6

(gdb) p dup2(open("/dev/null",0),1)
[Switching to Thread 0x7f3c8f5a66e0 (LWP 5636)]
$1 = 1

(gdb) p dup2(open("/dev/null",0),2)
$2 = 2

(gdb) detach
Detaching from program: /usr/bin/tail, process 5636

(gdb) quit

$ ls -l /proc/5636/fd
total 0
lrwx------ 1 myuser myuser 64 Feb 27 07:36 0 -> /dev/pts/0
lrwx------ 1 myuser myuser 64 Feb 27 07:36 1 -> /dev/null
lrwx------ 1 myuser myuser 64 Feb 27 07:36 2 -> /dev/null
lr-x------ 1 myuser myuser 64 Feb 27 07:36 3 -> /var/log/lastlog
lr-x------ 1 myuser myuser 64 Feb 27 07:36 4 -> /dev/null
lr-x------ 1 myuser myuser 64 Feb 27 07:36 5 -> /dev/null

You may also consider:

  • using screen; screen provides several virtual TTYs you can switch between without having to open new SSH/telnet/etc, sessions
  • using nohup; this allows you to close and reopen your session without losing any background processes in the... process.

Redirect output from running process (Visual C#)

It turns out that attaching to already running separate process using managed framework is not possible.

However, It is possible to achieve this using Console Api Functions under kernel32.dll.

Edit: The code is Improved for better usability

In order to achieve this we need to use FreeConsole, AttachConsole, ReadConsoleOutputCharacter, GetConsoleScreenBufferInfo and AttachConsole from WinApi

Declarations of static external libraries:

[DllImport("kernel32.dll")]
private extern static IntPtr GetStdHandle(int nStdHandle);

[DllImport("kernel32.dll")]
static extern bool ReadConsoleOutputCharacter(IntPtr hConsoleOutput,
[Out] StringBuilder lpCharacter, uint nLength, COORD dwReadCoord,
out uint lpNumberOfCharsRead);

[DllImport("kernel32.dll")]
static extern bool FreeConsole();
[DllImport("kernel32.dll")]
static extern bool AttachConsole(int dwProcessId);

[DllImport("kernel32.dll")]
static extern bool GetConsoleScreenBufferInfo(
IntPtr hConsoleOutput,
out CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo
);

[StructLayout(LayoutKind.Sequential)]
struct COORD
{
public short X;
public short Y;
}

[StructLayout(LayoutKind.Sequential)]
struct CONSOLE_SCREEN_BUFFER_INFO
{

public COORD dwSize;
public COORD dwCursorPosition;
public short wAttributes;
public SMALL_RECT srWindow;
public COORD dwMaximumWindowSize;

}

[StructLayout(LayoutKind.Sequential)]
struct SMALL_RECT
{

public short Left;
public short Top;
public short Right;
public short Bottom;

}

const int STD_OUTPUT_HANDLE = -11;
const Int64 INVALID_HANDLE_VALUE = -1;

We first need to free current console handle because we can only Attach to a single Console

private static string ReadALineOfConsoleOutput(IntPtr stdout, ref short currentPosition)
{

if (stdout.ToInt32() == INVALID_HANDLE_VALUE)
throw new Win32Exception();

//Get Console Info
if (!GetConsoleScreenBufferInfo(stdout, out CONSOLE_SCREEN_BUFFER_INFO outInfo))
throw new Win32Exception();

//Gets Console Output Line Size
short lineSize = outInfo.dwSize.X;

//Calculates Number of Lines to be read
uint numberofLinesToRead = (uint)(outInfo.dwCursorPosition.Y - currentPosition);

if (numberofLinesToRead < 1) return null;

// read from the first character of the first line (0, 0).
COORD dwReadCoord;
dwReadCoord.X = 0;
dwReadCoord.Y = currentPosition;

//total characters to be read
uint nLength = (uint)lineSize * numberofLinesToRead + 2*numberofLinesToRead;

StringBuilder result = new StringBuilder((int)nLength);
StringBuilder lpCharacter = new StringBuilder(lineSize);
for (int i = 0; i < numberofLinesToRead; i++)
{
if (!ReadConsoleOutputCharacter(stdout, lpCharacter, (uint) lineSize, dwReadCoord, out uint lpNumberOfCharsRead))
throw new Win32Exception();
result.AppendLine(lpCharacter.ToString(0, (int)lpNumberOfCharsRead-1));
dwReadCoord.Y++;
}

currentPosition = outInfo.dwCursorPosition.Y;
return result.ToString();
}

public static async Task Main()
{
var processId = 8560;
if (!FreeConsole()) return ;
if (!AttachConsole(processId)) return;

IntPtr stdout = GetStdHandle(STD_OUTPUT_HANDLE);
short currentPosition = 0;

while (true)
{
var r1 = ReadALineOfConsoleOutput(stdout, ref currentPosition);
if (r1 != null)
//write to file or somewhere => //Debug.WriteLine(r1);
}
}

Improvements

  • ref short currentPosition added to ReadALineOfConsoleOutput function for synchronizing currentPosition of the Standard Output
  • GetConsoleScreenBufferInfo is used to get lineSize of the console

    • short lineSize = outInfo.dwSize.X is added for lineSize
  • uint numberofLinesToRead = (uint) (outInfo.dwCursorPosition.Y - currentPosition) is used to calculate number of lines to be read using difference between actual position of the console and current position of the cursor.
  • considering lpNumberOfCharsRead to avoid garbage line endings

How to redirect output of a running process to a file in Linux Shell

A process may send output to standard output or standard error to get it to the terminal. Generally, the former is for information and the latter for errors, but in some cases, a process may mix them up.

I'm supposing that in your case, the standard error is being used. To get both of these to the output file, you can use:

airmon-ng mon0 > file.txt 2>&1

This says to send standard output to file.txt and to reroute 2 (which is the file id for standard error) into 1 (the file id for standard output) so that it also goes to the file.

view output of already running processes in linux

There is already an program that uses ptrace(2) in linux to do this, retty:

http://pasky.or.cz/dev/retty/

It works if your running program is already attached to a tty, I do not know if it will work if you run your program in background.

At least it may give some good hints. :)

You can probably retreive the exit code from the program using ptrace(2), otherwise just attach to the process using gdb -p <pid>, and it will be printed when the program dies.

You can also manipulate file descriptors using gdb:

(gdb) p close(1)
$1 = 0
(gdb) p creat("/tmp/stdout", 0600)
$2 = 1

http://etbe.coker.com.au/2008/02/27/redirecting-output-from-a-running-process/

How to get a direct output from a running process?

Be aware that the code below can throw an IOException.

Runtime runtime = Runtime.getRuntime() ;
Process process = runtime.exec("Your command") ;
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())) ;
String line = null ;
while ((line = reader.readLine())!= null){
System.out.println(line);
}


Related Topics



Leave a reply



Submit