Test passing localy but failing on remote for cp

I’m stuck on Stage #(The Software Pro's Best Kept Secret.).

The test passing locally here is the screen shot

Here are my logs:

Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 954 bytes | 954.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)
remote: ------------------------------------------------------------------------
remote:
remote:
remote:      ___            _          ___              __  _
remote:     / __\ ___    __| |  ___   / __\_ __  __ _  / _|| |_  ___  _ __  ___
remote:    / /   / _ \  / _` | / _ \ / /  | '__|/ _` || |_ | __|/ _ \| '__|/ __|
remote:   / /___| (_) || (_| ||  __// /___| |  | (_| ||  _|| |_|  __/| |   \__
remote:   \____/ \___/  \__,_| \___|\____/|_|   \__,_||_|   \__|\___||_|   |___/
remote:
remote:
remote:    Welcome to CodeCrafters! Your commit was received successfully.
remote:
remote: ------------------------------------------------------------------------
remote:
remote: Welcome back! Your first build could take slightly longer, please bear with us.
remote: Subsequent ones will be snappy ⚡
remote:
remote: Streaming build logs...
remote:
remote: [build] Starting build...
remote: [build] If you don't see logs for 60s+, please contact us at hello@codecrafters.io
remote: [build] Step 1 complete.
remote: [build] Step 2 complete.
remote: [build] Step 3 complete.
remote: [build] Step 4 complete.
remote: [build] Step 5 complete.
remote: [build] Step 6 complete.
remote: [build] Step 7 complete.
remote: [build] Step 8 complete.
remote: [build] Step 9 complete.
remote: [build] Step 10 complete.
remote: [build] Step 11 complete.
remote: [build] Step 10 complete.
remote: [build] Step 12 complete.
remote: [build] Step 13 complete.
remote: [build] Step 14 complete.
remote: [build] Step 15 complete.
remote: [build] Step 16 complete.
remote: [build] Step 17 complete.
remote: [build] > All requested packages are currently installed.
remote: [build] > Total install time: 32.1 us
remote: [build] Step 18 complete.
remote: [build] Step 19 complete.
remote: [build] Step 20 complete.
remote: [build] Step 21 complete.
remote: [build] Step 22 complete.
remote: [build] Step 23 complete.
remote: [build] Step 24 complete.
remote: [build] Step 25 complete.
remote: [build] Step 27 complete.
remote: [build] Step 26 complete.
remote: [build] Build successful.
remote:
remote:
remote: Running tests on your code. Logs should appear shortly...
remote:
remote: [compile] -- Running vcpkg install
remote: [compile] All requested packages are currently installed.
remote: [compile] Total install time: 93.2 us
remote: [compile] -- Running vcpkg install - done
remote: [compile] -- The C compiler identification is GNU 14.2.0
remote: [compile] -- The CXX compiler identification is GNU 14.2.0
remote: [compile] -- Detecting C compiler ABI info
remote: [compile] -- Detecting C compiler ABI info - done
remote: [compile] -- Check for working C compiler: /usr/bin/cc - skipped
remote: [compile] -- Detecting C compile features
remote: [compile] -- Detecting C compile features - done
remote: [compile] -- Detecting CXX compiler ABI info
remote: [compile] -- Detecting CXX compiler ABI info - done
remote: [compile] -- Check for working CXX compiler: /usr/local/bin/c++ - skipped
remote: [compile] -- Detecting CXX compile features
remote: [compile] -- Detecting CXX compile features - done
remote: [compile] -- Configuring done (0.7s)
remote: [compile] -- Generating done (0.0s)
remote: [compile] -- Build files have been written to: /app/build
remote: [compile] [ 50%] Building C object CMakeFiles/shell.dir/src/main.c.o
remote: [compile] [100%] Linking C executable shell
remote: [compile] [100%] Built target shell
remote: [compile] Moved ./.codecrafters/run.sh → ./your_program.sh
remote: [compile] Compilation successful.
remote:
remote: Debug = true
remote:
remote: [tester::#MG5] Running tests for Stage #MG5 (The type builtin: executable files)
remote: [tester::#MG5] [setup] export PATH=/tmp/bar:$PATH
remote: [tester::#MG5] [setup] export PATH=/tmp/baz:$PATH
remote: [tester::#MG5] [setup] PATH is now: /tmp/baz:/tmp/bar:/vcpkg:/cmake/bin:...
remote: [tester::#MG5] [setup] Available executables:
remote: [tester::#MG5] [setup] - my_exe
remote: [tester::#MG5] Running ./your_program.sh
remote: [your-program] $ type cat
remote: [your-program] cat is /usr/bin/cat
remote: [tester::#MG5] ✓ Received expected response
remote: [your-program] $ type cp
remote: [your-program] cp: not found
remote: [tester::#MG5] Output does not match expected value
remote: [tester::#MG5] Expected: "cp is /usr/bin/cp"
remote: [tester::#MG5] Received: "cp: not found"
remote: [your-program] $
remote: [tester::#MG5] Assertion failed.
remote: [tester::#MG5] Test failed
remote:
remote: Try our CLI to run tests faster without Git: https://codecrafters.io/cli
remote:
remote: View our article on debugging test failures: https://codecrafters.io/debug
remote:
To https://git.codecrafters.io/c65fb99ee6f91785
   2327cac..5bbf61d  master -> master

And here’s a snippet of my code:

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

#define TOKEN_BUFFER_SIZE 100

char **parse_input(char *input) {
  int buf_size = TOKEN_BUFFER_SIZE, position = 0;
  char **tokens = malloc(sizeof(char *) * buf_size);
  char *token;

  if (tokens == NULL) {
    perror("allocation error\n");
    exit(EXIT_FAILURE);
  }

  token = strtok(input, " ");
  while (token != NULL) {
    tokens[position] = token;
    position++;

    if (position >= buf_size) {
      buf_size += TOKEN_BUFFER_SIZE;
      tokens = realloc(tokens, sizeof(char *) * buf_size);
      if (tokens == NULL) {
        perror("allocation error\n");
        exit(EXIT_FAILURE);
      }
    }

    token = strtok(NULL, " ");
  }

  tokens[position] = NULL;
  return tokens;
}

typedef struct Path {
  char **paths;
  int length;
} Path_t;

Path_t *parse_path(char *input) {
  int buf_size = TOKEN_BUFFER_SIZE, position = 0;
  char **paths = malloc(sizeof(char *) * buf_size);
  char *path;

  if (paths == NULL) {
    perror("allocation error\n");
    exit(EXIT_FAILURE);
  }

  path = strtok(input, ":");
  while (path != NULL) {
    paths[position] = path;
    position++;

    if (position >= buf_size) {
      buf_size += TOKEN_BUFFER_SIZE;
      paths = realloc(paths, sizeof(char *) * buf_size);
      if (paths == NULL) {
        perror("allocation error\n");
        exit(EXIT_FAILURE);
      }
    }

    path = strtok(NULL, ":");
  }

  paths[position] = NULL;
  Path_t *p = malloc(sizeof(Path_t));
  p->paths = paths;
  p->length = position;
  return p;
}

int launch_command(char **args) {
  pid_t pid, wpid;
  int status;

  pid = fork();
  if (pid == 0) {
    if (execvp(args[0], args) == -1) {
      fprintf(stderr, "%s: command not found\n", args[0]);
    }
    exit(EXIT_FAILURE);
  } else if (pid < 0) {
    perror("error\n");
  } else {
    do {
      wpid = waitpid(pid, &status, WUNTRACED);
    } while (!WIFEXITED(status) && !WIFSIGNALED(status));
  }
}

// Shell built in
const char *shell_builtin[] = {"cd", "echo", "type", "exit"};

int is_shell_builtin(char *cmd) {

  for (int i = 0; i < 5; i++) {
    if (strcmp(cmd, shell_builtin[i]) == 0) {
      return 1;
    }
  }

  return 0;
}

char *is_in_path(char *arg) {
  char *PATH = getenv("PATH");
  if (PATH == NULL) {
    return 0;
  }

  Path_t *path = parse_path(PATH);
  for (int i = 0; i < path->length; i++) {
    size_t len = strlen(path->paths[i]) + strlen(arg) + 1;
    char *file = malloc(len * sizeof(char *));
    snprintf(file, len + 1, "%s/%s", path->paths[i], arg);
    if (access(file, F_OK) == 0) {
      return file;
    }
  }
  return NULL;
}

// Build in declarations
int echo(char **args);
int sh_exit(char **args);
int type(char **args);
int cd(char **args);

int (*builtin_func[])(char **) = {&cd, &echo, &type, &sh_exit};

int cd(char **args) {
  if (args[1] == NULL) {
    fprintf(stderr, "sh: expected argument to cd\n");
  } else {
    if (chdir(args[1]) != 0) {
      perror("error\n");
    }
  }

  return 1;
}

int echo(char **args) {
  if (args[1] == NULL) {
    fprintf(stderr, "sh: expected argument to echo\n");
  } else {
    int i = 1;
    while (args[i] != NULL) {
      fprintf(stdout, "%s ", args[i]);
      i++;
    }
    fprintf(stderr, "\n");
  }

  return 0;
}

int sh_exit(char **args) {
  if (args[1] == NULL) {
    exit(EXIT_SUCCESS);
  } else {
    exit(atoi(args[1]));
  }
}

char *path;
int type(char **args) {
  if (args[1] == NULL) {
    fprintf(stderr, "sh: expected argument to type\n");
  } else if (is_shell_builtin(args[1])) {
    fprintf(stdout, "%s is a shell builtin\n", args[1]);
  } else if ((path = is_in_path(args[1])) != NULL) {
    fprintf(stdout, "%s is %s \n", args[1], path);
  } else {
    fprintf(stdout, "%s: not found\n", args[1]);
  }
  return 1;
}

int exce(char **args) {

  if (strcmp(args[0], "exit") == 0) {
    return sh_exit(args);
  }

  for (int i = 0; i < 5; i++) {
    if (strcmp(args[0], shell_builtin[i]) == 0) {
      return (*builtin_func[i])(args);
    }
  }
  return launch_command(args);
}

int main(int argc, char *argv[]) {
  int status;
  while (true) {
    // Flush after every printf
    setbuf(stdout, NULL);

    // Uncomment this block to pass the first stage
    printf("$ ");

    // Wait for user input
    char input[100];
    fgets(input, 100, stdin);
    input[strcspn(input, "\r\n")] = 0;

    char **tokens = parse_input(input);
    if (tokens == NULL) {
      return 1;
    }

    status = exce(tokens);
  }

  return 0;
}

Hey @Mofiqul, could you upload your code to GitHub and share the link? It will be much easier to debug if I can run it directly.

Yah sure. here is the source code

@Mofiqul Yes, the code works locally, but only for the first time:

I added a log in is_in_path:

Turns out PATH was modified somewhere:

It’s modified by strtok, which replaces each delimiter with a null terminator \0 :

To fix this, you can make a copy of the PATH/input string with strdup before tokenizing it.

That did the trick. Thank you so much

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.