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

#define MAXLINE 256
#define MAX_PASSWORD 10  

#define SUCCESS "Password verified\n"
#define INVALID "Invalid password\n"
#define NO_USER "No such user\n"

int main(void) {
  char user_id[MAXLINE];
  char password[MAXLINE];

  /* The user will type in a user name on one line followed by a password 
     on the next.
     DO NOT add any prompts.  The only output of this program will be one 
	 of the messages defined above.
     Please read the comments in validate carefully
   */

  if(fgets(user_id, MAXLINE, stdin) == NULL) {
      perror("fgets");
      exit(1);
  }
  if(fgets(password, MAXLINE, stdin) == NULL) {
      perror("fgets");
      exit(1);
  }
  
  // TODO
  // Remove newline character from end of user_id

  if (strlen(user_id) > MAX_PASSWORD-1) {  
    printf("%s", NO_USER);
    return 0;
  }  
  if (strlen(password) > MAX_PASSWORD-1) {  
    printf("%s", INVALID);
    return 0;
  }   

  int pipefd[2];
  pid_t pid;
  pipe(pipefd);

  pid = fork();
  if (pid == 0) {
    close(pipefd[0]);
    if (dup2(pipefd[1], STDOUT_FILENO) == -1) {
      perror("dup2");
      exit(1);
    }
    close(pipefd[1]);

    execl("./validate", "validate", user_id, password, NULL);
    perror("execl");
    exit(1);
  } else {
    close(pipefd[1]);
    int status;
    pid_t wpid;

    char buffer[MAXLINE];
    ssize_t n;
    while ((n = read(pipefd[0], buffer, MAXLINE)) > 0) {
      write(STDOUT_FILENO, buffer, n);
    }
    close(pipefd[0]);

    wpid = waitpid(pid, &status, 0);
    if (wpid == -1) {
      perror("waitpid");
      exit(1);
    }

    wpid = waitpid(pid, &status, 0);
    if (WIFEXITED(status)) {
      int exit_status = WEXITSTATUS(status);
      if (exit_status == 0) {
        printf("%s", SUCCESS);
      } else if (exit_status == 2) {
        printf("%s", INVALID);
      } else {
        printf("%s", NO_USER);
      }
    }
    }


  return 0;

}
Your task is to complete checkpasswd.c, which reads a user id and password from stdin, creates a new process to run the validate program, sends it the user id and password, and prints a message to stdout reporting whether the validation is successful.

Your program should use the exit status of the validate program to determine which of the three following messages to print:

"Password verified" if the user id and password match.
"Invalid password" if the user id exists, but the password does not match.
"No such user" if the user id is not recognized
The exact messages are given in the starter code as defined constants.

The only case that should be handled directly in checkpasswd is the case where either the userid or password are too long.  This is to prevent sending the wrong number of bytes to validate.

Note that in the given password file pass.txt, the "killerwhales:swim" has a user id that is too large, and "monkeys:eatcoconuts" has a password that is too long. The examples are expected to fail, but the other cases should work correctly.

You will find the following system calls useful: fork, exec, pipe, dup2, write, wait (along with WIFEXITED, WEXITSTATUS). You may not use popen or pclose in your solution.

Important: execl arguments
Week 7 Video 6 "Running Different Programs" demonstrates a version of execl that takes only two arguments. The signature for execl is:

int execl(const char *path, const char *arg0, ... /*, (char *)NULL */);
In the video, the execl call only passed two arguments (execl("./hello", NULL)), but that shortcut doesn't work on teach.cs. Instead, you need to pass the middle argument (respresenting argv[0]) explicitly: execl("./hello", "hello", NULL).

Let's consider two more examples. If you want to call the executable ./giant with the arguments fee fi fo, you would do it like this: execl("./giant", "giant", "fee", "fi", "fo", NULL); If you want to call ./giant with no arguments you would call it like this: execl("./giant", "giant", NULL);
