0

Line number #15 { printf("This goes to the terminal\n"); } is not getting printed anywhere not in the terminal nor in the file.

//inputs   argc = 3 :- ./executable_file  output_file  command
    int main(int argc, char **argv)
    {
        if(argc < 3)
        {
            return 0;
        }
        int stdout_copy = dup(1);
        int fd = open(argv[1], O_CREAT | O_RDWR | O_TRUNC, 0644);
        if (fd < 0)
        {
            printf("ERROR\n");
            return 0;
        }
        printf("This goes to the standard output(terminal).\n");
        printf("Now the standard output will go to \"%s\" file  .\n", argv[1]);
        dup2(fd, 1);
        printf("This output goes to \"%s\"\n",argv[1]);
        close(fd);
        execvp(argv[2],argv+2);
        dup2(stdout_copy,1);
        printf("This goes to the terminal\n");
        return 0;
    }

Apologies for the Previous Question : I'm really sorry, it was my mistake in analysing it. And special thanks for all answers and hints.

kapa_
  • 3
  • 3
  • 1
    Please [edit] your question and show the command you use to call the program and the expected and actual output for both `stdout` and the output file. – Bodo Sep 21 '20 at 12:33
  • 1
    The line `printf("This goes to the terminal\n");` will be executed only if `execvp` fails, i.e. if it cannot execute the specified program. If `execvp` is successful it will replace the program running in the current process with the specified program and will never return. – Bodo Sep 21 '20 at 12:38
  • 2
    It is a good idea to use `fflush(stdout)` to empty buffers when interpreting standard I/O and file descriptor I/O, and before using any of the `exec*()` family of calls. Try running your program with the output piped to `cat`, for example. – Jonathan Leffler Sep 21 '20 at 12:47
  • As ryker suggested in his answer, which is now deleted, the normal naming of the arguments is `int main(int argc, char **argv)` with the meaning **arg**ument **c**ount and **arg**ument **v**ector. Although the usual naming helps to correctly understand your program, it will not change the behavior, provided that you rename **all** occurrences of `argc` to `argv`. A mistake in your program is that you access the argument vector without checking the argument count. Errors or undefined behavior will occur when you don't specify at least two command line arguments. – Bodo Sep 21 '20 at 12:49
  • Note that the conventional signature for the main function is `int main(int argc, char **argv)`. You have reversed the names. That is aconventional but not formally wrong. It confuses anyone reading your code though. The name `argc` is an abbreviation for the argument count; `argv` is an abbreviation for the argument vector, or array of argument strings. – Jonathan Leffler Sep 21 '20 at 12:52
  • The only difference I can see between the two versions of the program is that the output of the executed command (in case of successful `execvp`) goes to `stdout` instead of the output file if you use `dup2` to restore `stdout` before executing the command. – Bodo Sep 21 '20 at 12:54
  • kapa_ - It would help to come up with a definitive approach to helping if you include the actual command line arguments you use when seeing the behavior you have described. – ryyker Sep 21 '20 at 12:59

1 Answers1

1

problem in writing to terminal after using execvp and dup2 syscalls

Neither:

    execvp(argc[2],argc+2);
    dup2(stdout_copy,1);
    printf("This goes to the terminal\n");

Or:

    dup2(stdout_copy,1);
    execvp(argc[2],argc+2);
    printf("This goes to the terminal\n");

...will output to stdout if the call to execvp(argc[2],argc+2); succeeds.
However, both will output to stdout if it fails.
(Unless command line arguments are incorrect, dup2() likely has nothing to do with failure to output to stdout. See additional content below for how to check this.)

Read all about it here: execvp.
In a nutshell, execvp() replaces the current process with a new process. If it is successful the current process is no longer what you are viewing on the terminal. Only when it is not successful will the commands following it be executed.

The following suggestions are not precisely on-topic, but important nonetheless...

Change:

int main(int argv, char **argc)

To:

int main(int argc, char **argv)  //or  int main(int argc, char *argv[]), either are fine.

This will be the foundation of seeing normal behavior. Anything else is very confusing to future maintainers of your code, and to people trying to understand what you are doing here.
These names are easily remembered by keeping in mind that argc is used for the count of command line arguments, and argv is the vector that is use to store them.

Also, your code shows no indications that you are checking/validating these arguments, but given the nature of your program, they should be validated before going on. For example:

//verify required number of command line arguments was entered
if(argc <!= 3)//requires at least one additional command line argument
{
    printf("Usage: prog.exe [path_filename]\nInclude path_filename and try again.\nProgram will exit.");
    return 0;
}
//check if file exists before going on
if( access( argv[1], F_OK ) != -1 ) 
{
     // file exists
} else {
     // file doesn't exist
}
//do same for argv[2]

(2nd example to check file in Linux environment is from here)

BTW, Knowing the command line arguments that were passed into the program, would help to provide a more definitive answer here. Their syntax and content, and whether or not the files that they reference exist, determine how the call to execvp will behave.

Suggestions

  • It is generally always look at the return values of functions that have them. But because of the unique behavior of execvp If is successful it does not return, and if it fails it will always return -1. So in this case pay special attention to the value of errno for error indications, again all of which are covered in the link above.

  • As mentioned in comments (in two places.) it is a good idea to use fflush(stdout) to empty buffers when interpreting standard I/O and file descriptor I/O, and before using any of the exec*() family of calls.

  • Take time to read the man pages for the functions - shell commands that are used. It will save time, and guide you during debugging sessions.

ryyker
  • 22,849
  • 3
  • 43
  • 87
  • 1
    Although this is the usual naming, renaming the variables will not change the behavior of the program. – Bodo Sep 21 '20 at 12:32
  • 1
    @Bodo - If a person is learning C, and following example code from somewhere, then following naming convention all the way through will certainly affect normal behavior. Bugs are more easily introduced by mixing these two very idiomatic names around. – ryyker Sep 21 '20 at 12:33
  • 1
    Of course the suggestion to adhere to common conventions is useful, but as the wrong naming is used consistently in the program, it does not help to answer the question. – Bodo Sep 21 '20 at 12:40
  • 1
    There is no point in looking at the return vyof `execvp()`; it is always `-1`. If it returns, it failed; if it succeeds, it doesn't return. There is value in inspecting `errno`. – Jonathan Leffler Sep 21 '20 at 13:01
  • 1
    Hint: `fflush(stdout)` or have random bizarre behavior. – Joshua Sep 21 '20 at 17:21
  • @Joshua - Thank you. Edited. – ryyker Sep 21 '20 at 17:55