Linux non-blocking fifo (on demand logging)

前端 未结 10 2300
你的背包
你的背包 2020-11-29 19:20

I like to log a programs output \'on demand\'. Eg. the output is logged to the terminal, but another process can hook on the current output at any time.

The classic

10条回答
  •  無奈伤痛
    2020-11-29 19:58

    To follow in Fabraxias foot steps I'm going to share my small modification of racic's code. In one of my use cases I needed to suppress the writes to STDOUT, so I've added another parameter: swallow_stdout. If that is not 0, then output to STDOUT will be turned off.

    Since I'm no C coder I've added comments while reading the code, maybe they are useful for others.

    /* ftee - clone stdin to stdout and to a named pipe 
    (c) racic@stackoverflow
    WTFPL Licence */
    
    // gcc /tmp/ftee.c -o /usr/local/bin/ftee
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    int main(int argc, char *argv[])
    {
        int readfd, writefd;        // read & write file descriptors
        struct stat status;         // read file descriptor status
        char *fifonam;              // name of the pipe
        int swallow_stdout;         // 0 = write to STDOUT
        char buffer[BUFSIZ];        // read/write buffer
        ssize_t bytes;              // bytes read/written
    
        signal(SIGPIPE, SIG_IGN);   
    
        if(3!=argc)
        {
            printf("Usage:\n someprog 2>&1 | %s [FIFO] [swallow_stdout] \n" 
                "FIFO           - path to a named pipe (created beforehand with mkfifo), required argument\n"
                "swallow_stdout - 0 = output to PIPE and STDOUT, 1 = output to PIPE only, required argument\n", argv[0]);
            exit(EXIT_FAILURE);
        }
        fifonam = argv[1];
        swallow_stdout = atoi(argv[2]);
    
        readfd = open(fifonam, O_RDONLY | O_NONBLOCK);  // open read file descriptor in non-blocking mode
    
        if(-1==readfd)  // read descriptor error!
        {
            perror("ftee: readfd: open()");
            exit(EXIT_FAILURE);
        }
    
        if(-1==fstat(readfd, &status)) // read descriptor status error! (?)
        {
            perror("ftee: fstat");
            close(readfd);
            exit(EXIT_FAILURE);
        }
    
        if(!S_ISFIFO(status.st_mode)) // read descriptor is not a FIFO error!
        {
            printf("ftee: %s in not a fifo!\n", fifonam);
            close(readfd);
            exit(EXIT_FAILURE);
        }
    
        writefd = open(fifonam, O_WRONLY | O_NONBLOCK); // open write file descriptor non-blocking
        if(-1==writefd) // write file descriptor error!
        {
            perror("ftee: writefd: open()");
            close(readfd);
            exit(EXIT_FAILURE);
        }
    
        close(readfd); // reading complete, close read file descriptor
    
        while(1) // infinite loop
        {
            bytes = read(STDIN_FILENO, buffer, sizeof(buffer)); // read STDIN into buffer
            if (bytes < 0 && errno == EINTR)
                continue;   // skip over errors
    
            if (bytes <= 0) 
                break; // no more data coming in or uncaught error, let's quit since we can't write anything
    
            if (swallow_stdout == 0)
                bytes = write(STDOUT_FILENO, buffer, bytes); // write buffer to STDOUT
            if(-1==bytes) // write error!
                perror("ftee: writing to stdout");
            bytes = write(writefd, buffer, bytes); // write a copy of the buffer to the write file descriptor
            if(-1==bytes);// ignore errors
        }
        close(writefd); // close write file descriptor
        return(0); // return exit code 0
    }
    

提交回复
热议问题