如何在Linux平台下重定向running进程

如何在Linux平台下重定向running进程

一、简介

  本文通过一个具体的示例,介绍在Linux平台下重定向running(运行中)进程的几种方法。借助此方法,用户能够将进行打印重定向到需要的位置。

二、问题引入

  对于如何在shell下将进程的输出进行重定向,对于掌握Linux基本使用的人来说,相比并不陌生。那对于一个处于运行态的运行态的进程,要如何是好呢?
  我们举一个实际使用中可能会遇到的情况:设备运行过程中,遇到需要同事A帮忙解决的问题,常见的办法是A通过telnet或是ssh连接到设备,对问题进行分析,但由于其无法获得运行进程的打印,所以可能还是需要你帮忙抓取打印进行分析。
  针对类似的情况,我们是否有更好的解决办法呢?是否能够将进程的输出重定向到任意终端或是文件中呢?
  正是基于对上述问题的思考,在了解了相关资料后,最终找到了可行的解决方案,在下文中,会对其实现进行较为详细的介绍。

三、正文

1. 原理介绍

  重定向运行进程的实现,最终需要依赖linux下的ptrace系统调用,具体流程大如下:

Trace原理
图1:Trace原理

  Tracer(追踪者)通过ptrace系统调用,去追踪并监视Tracee(被追踪进程)的运行情况;在成功attach(附着——成功监控到Tracee进程)Tracee后,可以在Tracee每次调用系统调用(例如open,write)时,暂时挂起程序,此时Tracer能够获取并修改Tracee的寄存器信息,从而达到修改代码逻辑的目的。

  针对于重定向运行进程的应用场景,使用伪语言,描述如下:

if (Tracer attach Tracee == 成功)
{
    new_std_out = open("STD_OUT想要重定向的目的节点");
    dup2(new_std_out, 1);
    new_std_err = open("STD_ERR想要重定向的目的节点");
    dup2(new_std_out, 2);
}
else
{
    do nothing;
}

  关于更详细的说明,详见:Ptrace–Linux中一种代码注入技术的应用

2. 具体实现

  所谓万变不理其宗。为实现最终的重定向功能,有以下若干不同的实现路径,本节会通过以下示例(后文简称Demo)来介绍相应的使用方法。

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
void *thread_func(void *p_arg)
{
        while (1)
        {
                printf("--------------%s\n", (char*)p_arg);
                sleep(1);
        }
}
int main(void)
{
        pthread_t t1, t2;
		char thread_name_1[] = "Thread 1";
		char thread_name_2[] = "Thread 2";
        pthread_create(&t1, NULL, thread_func, thread_name_1);
        pthread_create(&t2, NULL, thread_func, thread_name_2);
        sleep(1000);
        return 0;
}

  如上所示,Demo会创建两个线程,并周期性输出打印到STD_OUT。

[root@Ambarella /home]#tty
/dev/ttyS0
[root@Ambarella /home]#./Demo &
[root@Ambarella /home]#
--------------Thread 1
--------------Thread 2
--------------Thread 1
--------------Thread 2
[root@Ambarella /home]#ps | grep 'Demo'
19404 root      0:00 ./Demo
[root@Ambarella /proc/19404/fd]#ls -al
total 0
root     0                0 Feb  6 17:49 .
dr-xr-xr-x    8 root     0                0 Feb  6 17:46 ..
lrwx------    1 root     0               64 Feb  6 17:49 0 -> /dev/ttyS0
lrwx------    1 root     0               64 Feb  6 17:49 1 -> /dev/ttyS0
lrwx------    1 root     0               64 Feb  6 17:49 2 -> /dev/ttyS0

  现我们在/dev/ttyS0下执行Demo,注意到对应的进程为19404,进一步查看描述符,标准输入与输出都为/dev/ttyS0
  接下来,我们打开一个新的终端/dev/pts/2,并尝试使用不同的方式将打印重定向到此处。

2.1 借助gdb实现重定向

  本节介绍如何借助gdb,将上述Demo进程进行重定向:

[root@Ambarella /var/mnt/emmc/scare_rw]#tty
/dev/pts/2
[root@Ambarella /var/mnt/emmc/scare_rw]#cat gdb_tty2.ini 
p (int)dup2((int)open("/dev/pts/2", 0x2101, 0777), 1)
detach
quit
[root@Ambarella /var/mnt/emmc/scare_rw]#gdb -p 19404 -x gdb_tty2.ini 
GNU gdb (Linaro_GDB-2018.08) 8.1.1.20180704-git
Copyright (C) 2018 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.
    ...
Attaching to process 19404
[New LWP 19405]
[New LWP 19406]
    ...
debugging will not be available.
0x0000007f92fd84c4 in nanosleep () from /lib/libc.so.6
$1 = 1
[root@Ambarella /var/mnt/emmc/scare_rw]#
--------------Thread 1
--------------Thread 2
--------------Thread 1
--------------Thread 2
--------------Thread 2
--------------Thread 1

[root@Ambarella /var/mnt/emmc/scare_rw]#cd /proc/19404/fd
[root@Ambarella /proc/19404/fd]#
[root@Ambarella /proc/19404/fd]#ls -al
total 0
dr-xr-xr-x    8 root     0                0 Feb  6 17:46 ..
lrwx------    1 root     0               64 Feb  6 17:49 0 -> /dev/ttyS0
l-wx------    1 root     0               64 Feb  6 17:49 1 -> /dev/pts/2
lrwx------    1 root     0               64 Feb  6 17:49 2 -> /dev/ttyS0
l-wx------    1 root     0               64 Feb  6 17:56 3 -> /dev/pts/2

  如上所示,在/dev/pts/2下,直接执行gdb -p 19404 -x gdb_tty2.iniDemo进程进行操作。可见,已成功将Demo的标准输出重定向到了/dev/pts/2,且进程19404的描述符,也发生了相应的改变。
  gdb_tty2.ini中,指定了gdb中要执行的命令。关于gdb的使用,详见:

  至于所执行的操作,详见前文的伪语言的解释。

2.2 借助三方库reredirect实现重定向

  关于reredirect的简单介绍:

  reredirect is a utility for taking an existing running program and attaching its outputs (standard output and error output) to files or another process.

  仓库地址详见:reredirect
:

  1. 该库已很久不再维护,且该库对于arm64的支持存在问题,目前尚未移植成功。而reredirect脱胎于另一个开源库reptyr,该仓库的维护相对活跃,且支持arm64平台,可以此为切入点,将reredirect移植到各平台。

四、参考与链接

  1. Ptrace–Linux中一种代码注入技术的应用: https://blog.csdn.net/litost000/article/details/82813641
  2. GDB -x 选项:https://blog.csdn.net/cindy9902/article/details/6146816
  3. GDB: The GNU Project Debugger:https://www.gnu.org/software/gdb/
  4. reredirect:https://github.com/jerome-pouiller/reredirect
  5. reptyr:https://github.com/nelhage/reptyr
  6. Litost_Cheng的博客:https://blog.csdn.net/litost000
  7. Litost_Cheng的Github:https://github.com/0Litost0

五、文档信息

作者: Litost_Cheng

发表日期:2021年02月02日
更多内容:

  1. Litost_Cheng的博客
  2. Litost_Cheng的Github
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值