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

1

14

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);
            }  
        }  
    }  

}  
Gomez answered 13/2, 2013 at 5:11 Comment(2)
char then[4]; strcpy(then, "then"); is a buffer overflow. Why don't you just use if(0 == strcmp(argv[x], "then")) or if(0 == strncmp(argv[x], "then", 4)) instead?Avocet
I think I tried that the first time I implemented it and ran into some sort of error. I'll remember this and refer back to it next time I come across the same thing. Thank you! Not used to C yet so any input like this is great.Gomez
O
20

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);
Overalls answered 13/2, 2013 at 5:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.