Linux下日誌重定向

最近由於項目的需要,需要將IPC中的日誌同步到SD卡中,以便後續IPC出現問題了進行分析。由於我們程序的架構是多進程的,爲了將所有進程的日誌同步到SD卡中,進程間需要傳遞文件描述符,然後將該描述符重定向即可。

//client.c
#include <stdio.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

#define  STD_OUT       (1)
#define  CONTROLLEN    CMSG_LEN(sizeof(int))
static struct cmsghdr    *cmptr = NULL;    /* malloc'ed first time */

int recv_fd(int fd)
{
    int              newfd,    nr, status;
    char            *ptr;
    char             buf[256];
    struct iovec     iov[1];
    struct msghdr    msg;
	
    status = -1;
    for(;;)
    {
        iov[0].iov_base   = buf;
        iov[0].iov_len    = sizeof(buf);
        msg.msg_iov       = iov;    
        msg.msg_iovlen    = 1;
        msg.msg_name      = NULL;
        msg.msg_namelen   = 0;
        
        if ((cmptr == NULL) && ((cmptr = malloc(CONTROLLEN)) == NULL))
		{
            return(-1);
		}
		
        msg.msg_control        = cmptr;
        msg.msg_controllen     = CONTROLLEN;
        if((nr = recvmsg(fd, &msg, 0)) < 0)
        {
            printf("recvmsg error");
			return(-1); 			
        }
        else if(nr == 0)
        {
            printf("connection close by server");
            return(-1);    
        }

        /*
        * See if this is the final data with null & status. Null
        * is next to last byte to buffer; status byte is last byte.
        * Zero status means there is a file descriptor to receive. 
        */
        for(ptr = buf; ptr < &buf[nr];)
        {
            if(*ptr++ == 0)
            {
                if(ptr != &buf[nr - 1])
                {
                    printf("message format error");
                }
                status = *ptr & 0xFF;    /* prevent sign extension */
                if(status == 0)
                {
                    if(msg.msg_controllen != CONTROLLEN)
                    {
                        printf("status = 0 but no fd");
                    }
                    newfd = *(int *)CMSG_DATA(cmptr);
                }
                else
                {
                    newfd = -status;
                }
                nr -= 2;
            }
        }
		
		/* final data has arrived */
        if(status >= 0)
		{
            return(newfd);    /* descriptor, or -status */
		}
    }
}

int main()
{
	int sockfd = -1;
	int recvfd = -1;
	int ret = 0;
	int i = 0;
	struct sockaddr_un addr_client;    
	int length;  
	const char path[] = "/home/guo/work/me/code/f2e/jooan-2020";
  
	sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		printf("client creat socket error!errno is %d\n", errno);
		return -1;
	}

	addr_client.sun_family = AF_UNIX;
	strcpy(addr_client.sun_path, path);
	length = sizeof(addr_client.sun_family) + sizeof(addr_client.sun_path);

	printf("Start connecting to the server\n");
    ret = connect(sockfd, (struct sockaddr*)&addr_client, length);
	if(ret < 0)
	{
		printf("in client connect error, errorno is %d\n",errno);
		close(sockfd);  
	}
 
	printf("Connection to server successful, Wait recv server send fd...\n");
	recvfd = recv_fd(sockfd);
	if(recvfd < 0)
	{
		printf("in client func_recv_fd failed\n");
		close(sockfd);  
	}
	printf("recv fd is %d\n", recvfd);

	//重定向文件描述符
	dup2(recvfd, STD_OUT);
	
	for (i=0; i<10; i++)
	{
		printf("I'm the clent sleep(%d)\n", i);
		sleep(1);
	}

	return 0;
}
//server.c
#include <stdio.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <dirent.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>

#define  STD_OUT       (1)
#define  CONTROLLEN    CMSG_LEN(sizeof(int))
static struct cmsghdr    *cmptr = NULL;    /* malloc'ed first time */

int send_fd(int fd, int fd_to_send)
{
    struct iovec     iov[1];
    struct msghdr    msg;
    char             buf[2];    /* send_fd()/recv_fd() 2-byte protocol */

    iov[0].iov_base     = buf;
    iov[0].iov_len      = 2;
    msg.msg_iov         = iov;
    msg.msg_iovlen      = 1;
    msg.msg_name        = NULL;
    msg.msg_namelen     = 0;
    
    if(fd_to_send < 0)
    {
        msg.msg_control    = NULL;
        msg.msg_controllen = 0;
        buf[1] = -fd_to_send;    /* nonzero status means error */
        if(buf[1] == 0)
		{
            buf[1] = 1;    /* -256, etc. would screw up protocol */ 
		}			
    }
    else
    {
        if(cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL)
		{
            return(-1);
		}
        cmptr->cmsg_level      = SOL_SOCKET;
        cmptr->cmsg_type       = SCM_RIGHTS;
        cmptr->cmsg_len        = CONTROLLEN;
        msg.msg_control        = cmptr;
        msg.msg_controllen     = CONTROLLEN;
        *(int *)CMSG_DATA(cmptr) = fd_to_send;    /* the fd to pass */
        buf[1] = 0;    /* zero status means ok */
    }
    buf[0] = 0;    /* null byte flag to recv_fd() */
    if(sendmsg(fd, &msg, 0) != 2)
        return(-1);
    return(0);
}

int main(int argc, char *argv)
{
	int recvfd = 0;
	int ret = 0;
	int i = 0;
	int on = 1;
	int fdsock, fdaccept;
	struct sockaddr_un addr_server;    
	int len;    
	const char path1[] = "/home/guo/work/me/code/f2e/jooan-2020";  
	const char path2[] = "/home/guo/work/me/code/f2e/log";
	
	recvfd = open(path2, O_RDWR|O_CREAT|O_TRUNC);
	if(recvfd < 0)
	{
		perror("open:");
		printf("open return %d, err...", recvfd);
		return -1;
	}
	chmod(path2, 0777);
	printf("open %s fd is %d\n",path2, recvfd);
	dup2(recvfd, STD_OUT);

	fdsock = socket(AF_UNIX, SOCK_STREAM, 0);
	if(-1 == fdsock)
	{
		printf("myopen creat socket error!errno is %d\n", errno);
		return -1;
	}

	memset(&addr_server, 0, sizeof(addr_server));
	addr_server.sun_family = AF_UNIX;
	strcpy(addr_server.sun_path, path1);
	len = sizeof(struct sockaddr_un);
	unlink(addr_server.sun_path);

	ret = setsockopt(fdsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ); 
	if(ret < 0)
	{
		printf("setsockopt error, errorno is %d\n",errno);
		close(fdsock);
		return -1;
	}
	
	printf("Start bind...\n");
	ret = bind(fdsock, (struct sockaddr*)&addr_server, len);
	if(ret < 0)
	{
		printf("in myopen bind error, errorno is %d\n",errno);
		close(fdsock);
		return -1;
	}

	printf("Start listen...\n");
	ret = listen(fdsock,1);
	if(ret < 0)
	{
		printf("in myopen listen error, errorno is %d\n",errno);
		close(fdsock);
		return -1;
	}
	
	printf("Start accept...\n");
	fdaccept = accept(fdsock, (struct sockaddr*)&addr_server, &len);
	if(ret < 0)
	{
		printf("in myopen accept error, errorno is %d\n",errno);
		close(fdsock);
		return -1;
	}

	/* 向已經連接的client傳遞文件描述符 */
	printf("Start passing the fd to the client...\n");
	send_fd(fdaccept, recvfd);
	
	printf("send fd to client ...\n");
	for (i=0; i<10; i++)
	{
		printf("I'm the server sleep(%d)\n", i);
		sleep(1);
	}

	return 0;
}

編譯運行結果如下:

 

參考文檔:

https://www.cnblogs.com/nufangrensheng/p/3571370.html

https://blog.csdn.net/genzld/article/details/84639298

https://blog.csdn.net/IOT_SHUN/article/details/80922734

https://blog.csdn.net/KingOfMyHeart/article/details/90272050

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章