使用dup,dup2重定向的试验

前言

想在bash修改版代码中得到执行用户输入命令后的回显数据,没调通。管道中没有数据, 应该是找到的fd不对。
bash代码执行用户输入的命令后,具体命令回显用的是重定向。
重定向用linuxC实现时,用的是dup和dup2. 从头做个试验,体会一下dup和dup2的效果。
本来可以在sshd代码中尝试得到回显,因为sshd服务端和ssh客户端(xshell, putty)之间是有通讯的,将回显内容发送到ssh客户端的实现找到即可截获回显. 可是fedora-powerpc版中编译不过公版的sshd代码,编译时缺的组件, 找不到对应的powerpc版的rpm包。

试验

通过试验,明确了dup和dup2的效果。知道了如何保存和恢复原始的stdin, stdout, stderr的fd.

开源代码中,用到fd时,经常会直接写死0,1,2. 这样不规范,应该写宏 : STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO. 可能大神们觉得写0,1,2方便吧。

// @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

// info for crrent tty info
typedef struct _tag_who_info {
    char user_name[64];
    char tty_name[64];
    char login_time[64];
    char ip[64];
}TAG_WHO_INFO;

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;

    int fd1 = -1;
    int fd2 = -1;
    int fd3 = -1;
	int fd4 = -1;
	int fd5 = -1;
    const char* msg = NULL;

    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

	    fd1 = open("/home/dev/test.txt", O_CREAT | O_SYNC | O_RDWR | O_APPEND);
		if (fd1 < 0) {
			break;
		}
		
	    fd2 = dup(fd1);
		if (fd2 < 0) {
			break;
		}

	    fd3 = dup(fd1);
		if (fd3 < 0) {
			break;
		}

		msg = "2. write to /home/dev/test.txt\n";
	    write(fd1, msg, strlen(msg));
	    
		msg = "3. write to /home/dev/test.txt too\n";
	    write(fd2, msg, strlen(msg));

		msg = "4. write to /home/dev/test.txt too\n";
	    write(fd3, msg, strlen(msg));

		msg = "5. write to stdout\n";
	    printf("%s", msg);

	    close(STDOUT_FILENO);
		// change stdout to fd1("/home/dev/test.txt")
		fd4 = dup2(fd1, STDOUT_FILENO);
		if (fd4 != STDOUT_FILENO) {
			break;
		}
		// from now, write to stdout is write to fd1("/home/dev/test.txt")

		msg = "6. write to /home/dev/test.txt\n";
	    printf("%s", msg);

		msg = "7. write to /home/dev/test.txt too\n";
	    write(fd1, msg, strlen(msg));

		// change stdout to original stdout
		fd5 = dup2(fd_stdout_org, STDOUT_FILENO); // restore original stdout fd
		if (fd5 != STDOUT_FILENO) {
			break;
		}
		// from now, write to stdout is real write stdout
		
		msg = "8. write to stdout\n";
		printf("%s", msg);
		
		close(fd1);
		msg = "9. after close fd1, write to fd1 do nothing\n";
	    write(fd1, msg, strlen(msg));
	    
		msg = "10. write to /home/dev/test.txt\n";
	    write(fd2, msg, strlen(msg));

		msg = "10. write to /home/dev/test.txt too\n";
	    write(fd3, msg, strlen(msg));

		msg = "10. write to stdout\n";
		write(fd5, msg, strlen(msg));
	} while (0);

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

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

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

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

	if (fd5 >= 0) {
		close(fd5);
		fd5 = -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;
}



上一篇:Vue、element-ui的resetFields()方法重置表单无效问题及解决办法


下一篇:Element中 resetFields()方法不生效