Thread: InfoBox with a FIFO file.

  1. #1
    Registered User
    Join Date
    Apr 2019
    Posts
    62

    InfoBox with a FIFO file.

    Hi,

    I will try to not be long winded, but I do want you to have a proper understanding...

    I have an `info-box` on my desktop, which is nothing more than a `xterm` window which displays the output from a FIFO file. It's a way I can have the output of my programs in one place, instead of always having windows open until a command completes (to check if there were errors).

    The first thing I tried was to just redirect the output from whichever command I wanted, to the `info-box` with a redirect:
    Code:
    command_to_run > $INFOBOX
    And it worked, but not the way I wanted it. It's simple for commands where the output IS the end of the program. But for programs that have output throughout the life of it, the output doesn't get displayed until the entire program is finished, and then it gets dumped.

    So I created a function for all my programs, to fork a child process and print the output to the FIFO file in the child process. This way I get current updates during the program. But it's done via a `system` command:
    Code:
    system("echo 'Text to display!' > $INFOBOX");
    Now, things are working the way I want them, but I feel the way I was able to accomplish it was horribly hacky. After doing some more searching, I came across someone saying I could use `dup2` to change the `STDOUT_FILENO` to the FIFO file and print the info directly. This sounds good to me, but when I try it, I get no output in the `info-box`.

    Could someone please shed some light on this (if they were able to follow my description)? Is this the way I should be doing it? What am I doing wrong with `dup2`? Any and all comments are welcome.

    Here is the working code (hacky):
    Code:
    #define PRINT_PREFIX     "echo \"YD: "
    #define PRINT_SUFFIX     "\" > " INFO_BOX_PATH
    
    void print_output (char *text)
    {
    // Declare variables.
        int fd = {0};
        char *text_working = NULL;
    
    // Allocate enough memory for a copy of 'text'.
        if((text_working = malloc(sizeof(char) * (strlen(text) + 1))) == NULL)
        {
            fprintf(stderr, "%s: %s error: malloc failed\n", program_invocation_short_name, __func__);
            exit(EXIT_FAILURE);
        }
    
    // Make working copy of text.
        strcpy(text_working, text);
    
    // Remove trailing newline '\n', if any.
        if(text_working[strlen(text_working) - 1] == '\n')
            text_working[strlen(text_working) - 1] = '\0';
    
    // Evaluate the fork.
        switch(fork())
        {
            case -1: // Error.
                fprintf(stderr, "%s: %s error: fork failed (%s)\n", program_invocation_short_name, __func__, strerror(errno));
                exit(EXIT_FAILURE);
                break;
            case 0: // Child.
    // Open output fifo file.
                if((fd = open(INFO_BOX_PATH, O_WRONLY)) == -1)
                {
                    fprintf(stderr, "%s: %s error: open failed (%s) (%s)\n", program_invocation_short_name, __func__, strerror(errno), INFO_BOX_PATH);
                    exit(EXIT_FAILURE);
                }
    
    // Duplicate stdout stream.
                if(dup2(fd, STDOUT_FILENO) == -1)
                {
                    fprintf(stderr, "%s: %s error: dup2 failed (%s)\n", program_invocation_short_name, __func__, strerror(errno));
                    exit(EXIT_FAILURE);
                }
    
    // Print out to fifo file.
                puts(text_working);
    // Close the output file and exit child process cleanly.
                close(fd);
                _exit(EXIT_SUCCESS);
            default:
                wait(0);
        }
    
    // Free allocated memory.
        free(text_working);
    }
    Here is the code using `dup2` which doesn't work:
    Code:
    void print_output (char *text)
    {
    // Declare variables.
        int fd = {0};
        char *text_working = NULL;
    
    // Allocate enough memory for a copy of 'text'.
        if((text_working = malloc(sizeof(char) * (strlen(text) + 1))) == NULL)
        {
            fprintf(stderr, "%s: %s error: malloc failed\n", program_invocation_short_name, __func__);
            exit(EXIT_FAILURE);
        }
    
    // Make working copy of text.
        strcpy(text_working, text);
    
    // Remove trailing newline '\n', if any.
        if(text_working[strlen(text_working) - 1] == '\n')
            text_working[strlen(text_working) - 1] = '\0';
    
    // Evaluate the fork.
        switch(fork())
        {
            case -1: // Error.
                fprintf(stderr, "%s: %s error: fork failed (%s)\n", program_invocation_short_name, __func__, strerror(errno));
                exit(EXIT_FAILURE);
                break;
            case 0: // Child.
    // Open output fifo file.
                if((fd = open(INFO_BOX_PATH, O_WRONLY)) == -1)
                {
                    fprintf(stderr, "%s: %s error: open failed (%s) (%s)\n", program_invocation_short_name, __func__, strerror(errno), INFO_BOX_PATH);
                    exit(EXIT_FAILURE);
                }
    
    // Duplicate stdout stream.
                if(dup2(fd, STDOUT_FILENO) == -1)
                {
                    fprintf(stderr, "%s: %s error: dup2 failed (%s)\n", program_invocation_short_name, __func__, strerror(errno));
                    exit(EXIT_FAILURE);
                }
    
    // Print out to fifo file.
                puts(text_working);
    // Close the output file and exit child process cleanly.
                close(fd);
                _exit(EXIT_SUCCESS);
            default:
                wait(0);
        }
    
    // Free allocated memory.
        free(text_working);
    }

  2. #2
    Registered User
    Join Date
    Sep 2020
    Posts
    126
    two qns. First is genuine. Why

    Code:
       intfd = {0};


    and not

    Code:
       int fd = 0;


    And now the less genuine: Why are you using close(fd) after puts()?

    Hint: If data is in the program's output buffer (and stdout is buffered) where will it write it to if the underlying fd is closed?

  3. #3
    Registered User
    Join Date
    Apr 2019
    Posts
    62
    Quote Originally Posted by hamster_nz View Post
    Why

    Code:
       intfd = {0};
    and not

    Code:
       int fd = 0;
    For me, programming is about structure. When declaring variables, I
    just always initialize them to
    Code:
    {0} or NULL
    for pointers. And the declaration is just that, no adding value, just initializing.

    I do see what you're saying though.


    Quote Originally Posted by hamster_nz View Post
    Why are you using close(fd) after puts()?

    Hint: If data is in the program's output buffer (and stdout is buffered) where will it write it to if the underlying fd is closed?
    My understanding is that the output buffer (stdout) is flush with every newline '\n' encountered. From the man page for `puts`:

    puts() writes the string s and a trailing newline to stdout.
    But now that I think about it, I should just open up the FIFO file at the start and use dup2. Then there's no need for a seperate output function.

  4. #4
    Registered User
    Join Date
    Sep 2020
    Posts
    126
    I am 99% sure if you remove the close(), or call fflush() before the close it will work.

    I suspect that dup2() will convert the line-buffered stdout into being a block-buffered file stream. You could maybe call setlinebuf() to change it back to line buffered.

    The whole idea of fork()ing a separate process seems dangerous to me.

    If nothing is draining your FIFO it will block, and then you may end up with 100s of processes all attempting to write to the full FIFO.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. FIFO files
    By Belka in forum C Programming
    Replies: 5
    Last Post: 10-08-2012, 11:32 AM
  2. Help with FIFO queue
    By Martin_T in forum C Programming
    Replies: 10
    Last Post: 11-08-2009, 10:30 AM
  3. A fifo file and select() problem
    By itsdafoetime in forum C Programming
    Replies: 2
    Last Post: 03-08-2009, 02:23 AM
  4. mknod FIFO
    By Thinker in forum Linux Programming
    Replies: 6
    Last Post: 03-14-2003, 08:16 AM
  5. FIFO help
    By Unregistered in forum C Programming
    Replies: 1
    Last Post: 04-15-2002, 11:57 AM

Tags for this Thread