ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

通过dup2实现linux命令回显的捕获

2019-04-22 10:52:48  阅读:333  来源: 互联网

标签:FILENO 回显 dup2 int sz fd linux org buf


前言

在bash代码中,看到关闭了一个fd后,屏幕上才出现linux命令执行后的回显内容.
做了一个试验,实现了回显数据的捕获。
实现思路:

  • dup2重定向stdin到自己建立的管道
  • select管道,如果有数据就读取管道中的数据,并转发. 如果超时,就跳出.
    做了好久的试验,终于达到预期的效果了:)

demo

// @file main.cpp
// @note on fedora22 view syslog use 'journalctl -f'
// 'tail -f /var/log/message' is invalid

#include <stdlib.h>
#include <stdio.h>

#include <string.h>
#include <unistd.h>

#include <syslog.h>
#include <signal.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

// 日志级别 - 调试
#ifndef MYLOG_D
	
#define MYLOG_D(fmt, ...) \
	do { \
		syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "LS_LOG", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
	} while (0);
	
#endif // #ifndef MYLOG_D

void init(const char* psz_log_owner_name);
void uninit();
void proc_sig_term(int num);
int fn_test();

int main(int argc, char** argv)
{
    char sz_buf[1024] = {'\0'};

#ifdef MAKE_FILE_MACRO__BIN_NAME
    sprintf(sz_buf, "%s", MAKE_FILE_MACRO__BIN_NAME);
    init(sz_buf);
    MYLOG_D("MAKE_FILE_MACRO__BIN_NAME = [%s]", MAKE_FILE_MACRO__BIN_NAME);
#else
    init(NULL);
#endif // #ifdef MAKE_FILE_MACRO__BIN_NAME

    fn_test();
    uninit();

    MYLOG_D("THE END");
    return EXIT_SUCCESS;
}

void init(const char* psz_log_owner_name)
{
    int i = 0;

    // daemon(0, 0);
    openlog(((NULL != psz_log_owner_name) ? psz_log_owner_name : "my_syslog"), LOG_NOWAIT | LOG_PID, LOG_LOCAL1);

    // clear screen (print 25 empty line)
    for (i = 0; i < 25; i++) {
        MYLOG_D("");
    }

    signal(SIGTERM, proc_sig_term);
}

void uninit()
{
	closelog();
}

void proc_sig_term(int num)
{
    MYLOG_D("SIGTERM = %d, num = %d", SIGTERM, num);
    MYLOG_D("maybe can do some clean task before quit");
    exit(1);    
}

int fn_test()
{
	int fd_stdin_org = -1;
	int fd_stdout_org = -1;
	int fd_stderr_org = -1;
	char sz_buf[1024] = {'\0'};
	// char* p_rd = NULL;
	int n = 0;

	int my_pipe[2] = {0};

	int fd0 = -1;
    int fd1 = -1;
	FILE* fp = NULL;
    const char* msg = NULL;

	fd_set rfds;
    struct timeval tv;
    int retval;

    MYLOG_D(">> fn_test()");

//	printf("STDIN_FILENO = %d\n", STDIN_FILENO);
//	printf("STDOUT_FILENO = %d\n", STDOUT_FILENO);
//	printf("STDERR_FILENO = %d\n", STDERR_FILENO);
	/*
	STDIN_FILENO = 0
	STDOUT_FILENO = 1
	STDERR_FILENO = 2
	*/

	do {
		// backup original STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO
		fd_stdin_org = dup(STDIN_FILENO);
		if (fd_stdin_org < 0) {
			break;
		}
		
		fd_stdout_org = dup(STDOUT_FILENO);
		if (fd_stdout_org < 0) {
			break;
		}
		
		fd_stderr_org = dup(STDERR_FILENO);
		if (fd_stderr_org < 0) {
			break;
		}
		
		// if want view a file will be create later, can use 'tail -F obj_file_path_name'
		msg = "1. write to stdout";
	    printf("%s\n", msg); // write to stdout

	    if(pipe(my_pipe) == -1)
	    {
	        break;
	    }

		fd0 = dup2(my_pipe[0], STDIN_FILENO);
		if (fd0 != STDIN_FILENO) {
			break;
		}

		fd1 = dup2(my_pipe[1], STDOUT_FILENO);
		if (fd1 != STDOUT_FILENO) {
			break;
		}
		
		msg = "2. write to my_pipe[0]";
		printf("%s\n", msg); // write to my_pipe

		msg = "3. write to my_pipe[0]";
		printf("%s\n", msg); // write to my_pipe

		fp = fdopen(fd0, "r");
		if (NULL != fp) {
			FD_ZERO(&rfds);
    		FD_SET(fd0, &rfds);

			tv.tv_sec = 5;
			tv.tv_usec = 0;

			do {
				retval = select(1, &rfds, NULL, NULL, &tv);
				if (retval < 0) {
			        // error happen
			        break;
				} else if (retval > 0) {
					// now, data is available
					if (FD_ISSET(fd0, &rfds)) {
						// method 1
						memset(sz_buf, 0, sizeof(sz_buf));
						// read 可以将用户多次输入的数据都读全
						n = read(fd0, sz_buf, sizeof(sz_buf));
						if	(n < 0) {
							break;
						}
						// MYLOG_D("read from pipe : %s", buf);

						// method 2
						// get user input

						/*
						// 输入多句,fgets只能读第一句, 再select时,就超时了, 第2句没读到
						memset(sz_buf, 0, sizeof(sz_buf));
						// 因为上面就写了1句,fgets执行一次就没数据了
						// 为了防止阻塞, 不能直接调用fgets, 必须用select的超时机制来防止阻塞
						p_rd = fgets(sz_buf, sizeof(sz_buf) - 1, fp); // if user not input and fp is valid, will block here
						if (NULL == p_rd) {
							break;
						}
						*/
					} else {
						// fd is invalid, break
						break;
					}
				}
			    else {
			        // time out
			        break;
			    }
				
				// trans user input to real stdout
				// can trans user input to other from this point
				write(fd_stdout_org, sz_buf, sizeof(sz_buf));

				// read user input continue
			} while (1);

			fclose(fp);
			fp = NULL;
		}

		close(my_pipe[0]);
		my_pipe[0] = -1;

		close(my_pipe[1]);
		my_pipe[1] = -1;
	} while (0);

	if (fd0 >= 0) {
	    close(fd0);
		fd0 = -1;
	}

	if (fd1 >= 0) {
	    close(fd1);
		fd1 = -1;
	}

	if (fd_stdin_org >= 0) {
		close(STDIN_FILENO);
		dup2(fd_stdin_org, STDIN_FILENO); // restore original stdin
		
		close(fd_stdin_org);
		fd_stdin_org = -1;
	}

	if (fd_stdout_org >= 0) {
		close(STDOUT_FILENO);
		dup2(fd_stdout_org, STDOUT_FILENO); // restore original stdout
		
		close(fd_stdout_org);
		fd_stdout_org = -1;
	}

	if (fd_stderr_org >= 0) {
		close(STDERR_FILENO);
		dup2(fd_stdout_org, STDERR_FILENO); // restore original stderr
		
		close(fd_stderr_org);
		fd_stderr_org = -1;
	}
	
    return 0;
}



标签:FILENO,回显,dup2,int,sz,fd,linux,org,buf
来源: https://blog.csdn.net/LostSpeed/article/details/80727983

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有