Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C, how do I redirect STDOUT_FILENO to /dev/null using dup2 and then redirect back to its original value later?

Tags:

c

fork

stdout

dup

dup2

I have an assignment I'm working on and I'm having difficulty finishing it. The idea is to write a program if.c that executes one program and if that succeeds it executes the second program. I'm supposed to suppress the standard output of the first program and unsupress standard output for the second. I'm getting the error message on multiple tests. For instance: "./if echo no then echo yes" returns "echo:write error: Bad file descriptor". I've tried finding what I'm doing wrong online but no luck.

Here's my code:

#include <fcntl.h>
#include <sys/wait.h>
#include <stdio.h>
#include "tlpi_hdr.h"

int main(int argc, char *argv[])
{
    if(argc < 4){
        fprintf(stderr,"Incorrect number of arguments.\n");
        exit(EXIT_FAILURE);
    }

    int thenArg = 0;
    char then[4];
    strcpy(then,"then");
    for(int x=1; x<argc; x++){
        if(strncmp(argv[x], then, 4) == 0) thenArg = x;
    }

    if(thenArg == 0){
        fprintf(stderr,"No 'then' argument found.\n");
        exit(EXIT_FAILURE);
    }

    int save_out = dup(STDOUT_FILENO);
    if(save_out == -1){
        fprintf(stderr,"Error in dup(STDOUT_FILENO)\n");
        exit(EXIT_FAILURE);
    }

    int devNull = open("/dev/null",0);
    if(devNull == -1){
        fprintf(stderr,"Error in open('/dev/null',0)\n");
        exit(EXIT_FAILURE);
    }

    int dup2Result = dup2(devNull, STDOUT_FILENO);
    if(dup2Result == -1) {
        fprintf(stderr,"Error in dup2(devNull, STDOUT_FILENO)\n");
        exit(EXIT_FAILURE);
    }

    int program1argLocation = 1;
    int program2argLocation = thenArg + 1;
    int program1argCount = thenArg-1;
    int program2argCount = argc-(program2argLocation);
    char *program1args[program1argCount+1];
    char *program2args[program2argCount+1];

    for(int i=0; i<program1argCount; i++){
        program1args[i]=argv[program1argLocation + i];
    }
    program1args[program1argCount] = NULL;
    for(int i=0; i<program2argCount; i++){
        program2args[i]=argv[program2argLocation + i];
    }
    program2args[program2argCount] = NULL;

    pid_t pid = fork();
    int child_status;
    switch (pid) {
    case -1:
        fprintf(stderr,"Fork failed\n");
        exit(EXIT_FAILURE);

    case 0: //child
        //child will run program 1
        if(execvp(program1args[0],&program1args[0]) == -1){
            fprintf(stderr,"Program 1 Failed.\n");
            exit(EXIT_FAILURE);
        }  

    default: //parent
        //parent will run program2
        pid = wait(&child_status);

        if(WEXITSTATUS(child_status) == 0){
            dup2(save_out, STDOUT_FILENO);

            int prog2status = execvp(program2args[0],&program2args[0]);
            if(prog2status == -1) {
                fprintf(stderr,"Program 2 failed.\n");
                exit(EXIT_FAILURE);
            }  
        }  
    }  

}  
like image 769
Frank Avatar asked Feb 13 '13 05:02

Frank


People also ask

How do I redirect a null output?

You can send output to /dev/null, by using command >/dev/null syntax.

Does dup2 close FD?

If fd1 is not a valid file descriptor, dup2() fails and does not close fd2. If a file descriptor does not already exist, dup2() can be used to create one, a duplicate of fd1. F_CLOEXEC is cleared in fd2.

Does dup2 close file?

The dup2() function returns a descriptor with the value fildes2. The descriptor refers to the same file as fildes, and it will close the file that fildes2 was associated with. For more information about the processing which may occur when the file is closed, see close()--Close File or Socket Descriptor.

Why do we redirect to Dev Null?

There will be a lot of files that a regular, non-root user cannot read. This will result in many “Permission denied” errors. These clutter the output and make it harder to spot the results that you're looking for. Since “Permission denied” errors are part of stderr, you can redirect them to “/dev/null.”


1 Answers

Your error is here:

int devNull = open("/dev/null",0);

To use devNull as STDOUT_FILENO, it must be opened for writing:

int devNull = open("/dev/null", O_WRONLY);
like image 100
caf Avatar answered Sep 28 '22 20:09

caf