0

This program does two things: 1) Duplicates the action of shell 2) Record user input to a tmp.log file

The problem here is that in my child process, printf("ABC"); does nothing. Outputting the log file works fine, but it just doesn't print.

Why does this behave like this?

I know execvp is supposed to replace the current process but that doesn't explain why it would execute the output but not the print. I saw the below link but this doesn't answer my question. exevp skips over all code until wait call in c

#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
#include  <sys/types.h>
#include <wordexp.h>

void execute(char *user_input)
{
    pid_t pid;        
    int state_loc; 
    if( (pid = fork()) == -1){
      printf("fork failed\n");
      exit(1);
    }
    else if(pid == 0){

      FILE *f;
      //open the file and append. Create if not there.
      f = fopen("tmp.log", "a+"); 
      if (f == NULL) { printf("Something is wrong");}

      struct tm *p;
      struct tm buf;
      char timestring[100];
      time_t ltime = time(NULL);
      if (NULL != (p=localtime_r(&ltime, &buf))){
        strftime(timestring, sizeof(timestring),"** %c: ", p);
        fprintf(f, "%s %s \n", timestring, user_input);
      }
      fclose(f);      

      char* separator = " ";
      char* argv[64];
      int argc = 0;
      char* tmp;
      argv[argc] = strtok_r(user_input, separator, &tmp);
      while( argv[argc] != NULL){
        argc+=1;
        argv[argc] = strtok_r(NULL, separator, &tmp);
      }

      printf("ABC"); //why doesn't this print??

      execvp(argv[0],argv);
    }
    else{          
      wait(&state_loc);
    }
}


int main ()
{
  while(1)
  {
    char user_input[1024];
    printf("recsh>> ");
    //empty the buffer right scanf
    scanf("%[^\n]", user_input);
    //calls each character in the user input, repeat until it reaches the terminating \n
    while( getchar() != '\n'); 
    if(strcmp(user_input, "exit") == 0){
      printf("Exiting\n");
      break;
    }
    else{
      execute(user_input);
    }
  }
  return 0;
}
Leonard
  • 2,978
  • 6
  • 21
  • 42
  • @ignacio it still doesn’t print before fclose. Like even at the first line inside child – Leonard May 20 '18 at 16:07
  • You should almost never write things like `printf("Some words without a new line");`. The output is confusing, since the next line just runs on, and it does not automatically flush the output buffer, so the output will at least be delayed. If you are too lazy to put the `\n` in the string, you could use the preferred interface for output without an interpolated value, `puts("Some words automatically terminated with a newline");`. See [man puts](http://man7.org/linux/man-pages/man3/puts.3.html). – rici May 20 '18 at 17:56
  • @ignacio: `stdout` is not closed by `execvp`. But it's not fflush'd either. – rici May 20 '18 at 18:08

1 Answers1

1

That call to printf is executed in the child just before it calls execvp.

Since stdout is line-buffered by default and the text printed does not constitute a line (since there is no new line character), it is left in the output buffer. That output buffer vanishes along with the rest of the original executable when the image is replaced by execvp.

Moral: always terminate your output with a newline character (\n).

rici
  • 234,347
  • 28
  • 237
  • 341