Add simple exec with env and path parsing

This commit is contained in:
savalet
2025-02-12 17:30:16 +01:00
parent 1fed88555a
commit 4078e4c688
5 changed files with 244 additions and 83 deletions

104
src/env.c
View File

@@ -16,79 +16,61 @@
#include "u_mem.h"
#include "u_str.h"
size_t count_env_entries(char **env)
void debug_env_entries(env_t *env)
{
size_t result = 0;
for (; *env != NULL; env++)
result++;
return result;
for (size_t i = 0; i < env->sz; i++)
U_DEBUG("Env entry [%lu] [%s]\n", i, env->env[i]);
}
bool ensure_buff_av_capacity(buff_t *buff, size_t requested)
char *get_env_value(env_t *env, char const *key)
{
char *new_str;
size_t endsize = ENV_BUFF_CAP;
for (size_t i = 0; i < env->sz; i++)
if (u_strncmp(env->env[i], key, u_strlen(key)) == 0)
return env->env[i] + u_strlen(key) + 1;
return NULL;
}
if ((buff->sz + requested) < buff->cap)
static __attribute__((nonnull))
bool ensure_env_capacity(env_t *env)
{
char **new_ptr;
if (env->sz < env->cap)
return true;
for (; endsize < buff->sz + requested; endsize <<= 1);
if (endsize > buff->cap) {
new_str = u_realloc(buff->str, (sizeof *buff->str) * buff->sz,
(sizeof *buff->str) * endsize);
if (new_str == NULL)
return false;
buff->str = new_str;
buff->cap = endsize;
}
new_ptr = (char **)u_realloc((void *)env->env, sizeof *env->env * env->sz,
sizeof *env->env * env->cap << 1);
if (!new_ptr)
return false;
env->cap <<= 1;
env->env = new_ptr;
return true;
}
static
bool parse_env_populate(char **env, buff_t *env_values,
env_entry_t *env_entries)
void env_bzero(char **env, size_t sz)
{
size_t env_size = 0;
size_t i = 0;
for (size_t i = 0; i < sz; i++)
env[i] = NULL;
}
env_t parse_env(char **env)
{
env_t new_env = { 0, .cap = BASE_ENV_CAP };
new_env.env = (char **)malloc(sizeof(char *) * new_env.cap);
if (!new_env.env)
return (env_t){ 0, .env = NULL };
env_bzero(new_env.env, new_env.sz);
for (; *env != NULL; env++) {
env_size = u_strlen(*env);
if (!ensure_buff_av_capacity(env_values, env_size))
return false;
env_entries[i].ptr = u_memcpy(env_values->str + env_values->sz, *env,
env_size);
env_entries[i].size = env_size;
env_values->sz += env_size;
i++;
if (!ensure_env_capacity(&new_env))
return (free((void *)new_env.env), (env_t){ 0 });
new_env.env[new_env.sz] = u_strdup(*env);
if (new_env.env[new_env.sz] == NULL)
return (free((void *)new_env.env), (env_t){ 0 });
new_env.sz++;
}
return true;
}
void debug_env_entries(env_entry_t *env_entries, size_t env_size)
{
size_t keylen __attribute__((unused));
for (size_t i = 0; i < env_size; i++) {
keylen = u_strcspn(env_entries[i].ptr, '=') + 1;
U_DEBUG("Env entry [%01lu] key [%.*s] value [%.*s]\n", i,
(int)keylen - 1, env_entries[i].ptr,
(int)(env_entries[i].size - keylen),
env_entries[i].ptr + keylen);
}
}
bool parse_env(char **env, buff_t *env_values, env_entry_t *env_entries)
{
if (env_values == NULL || env_entries == NULL)
return false;
u_bzero((char *)env_values, sizeof(buff_t));
env_values->str = malloc(sizeof *env_values->str * ENV_BUFF_CAP);
if (env_values->str == NULL)
return false;
env_values->cap = ENV_BUFF_CAP;
u_bzero(env_values->str, sizeof *env_values->str * env_values->cap);
parse_env_populate(env, env_values, env_entries);
env_values->str[env_values->sz] = '\0';
U_DEBUG("Parsed %zu env entries (%zu)\n",
count_env_entries(env), env_values->sz);
return true;
if (!ensure_env_capacity(&new_env))
return (free((void *)new_env.env), (env_t){ 0 });
new_env.env[new_env.sz] = NULL;
return new_env;
}

View File

@@ -7,17 +7,18 @@
#ifndef ENV_H
#define ENV_H
#include "u_str.h"
#define ENV_BUFF_CAP 128
#include <stddef.h>
#define BASE_ENV_CAP 128
typedef struct {
char *ptr;
size_t size;
} env_entry_t;
size_t sz;
size_t cap;
char **env;
} env_t;
// Debug
void debug_env_entries(env_entry_t *env_entries, size_t env_size);
void debug_env_entries(env_t *env);
bool parse_env(char **env, buff_t *env_values, env_entry_t *env_entries);
size_t count_env_entries(char **env);
env_t parse_env(char **env);
char *get_env_value(env_t *env, char const *key);
#endif

154
src/exec.c Normal file
View File

@@ -0,0 +1,154 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include "common.h"
#include "debug.h"
#include "env.h"
#include "exec.h"
#include "u_mem.h"
#include "u_str.h"
static
const builtins_t BUILTINS[] = {
{ "exit", (void (*)(uint64_t))&exit }
};
static
const size_t BUILTINS_SZ = sizeof BUILTINS / sizeof *BUILTINS;
static
char *build_full_path(const char *token, const char *binary)
{
size_t len_token = u_strlen(token);
size_t len_bin = u_strlen(binary);
char *full_path = malloc(len_token + len_bin + 2);
if (!full_path)
return NULL;
u_strcpy(full_path, token);
full_path[len_token] = '/';
u_strcpy(full_path + len_token + 1, binary);
full_path[len_token + len_bin + 1] = '\0';
return full_path;
}
static
char *find_binary(const char *path_env, const char *binary)
{
static char *saveptr = NULL;
static char *path = NULL;
char *token;
char *full_path;
if (path_env) {
path = u_strdup(path_env);
if (!path)
return NULL;
token = strtok_r(path, ":", &saveptr);
} else
token = strtok_r(NULL, ":", &saveptr);
if (!token)
return free(path), u_strdup(binary);
full_path = build_full_path(token, binary);
if (!full_path)
return NULL;
return access(full_path, X_OK) == 0 ? full_path : (free(full_path),
find_binary(NULL, binary));
}
static
int count_args(char *buffer)
{
int count = 0;
char *token;
token = strtok(buffer, " \t\n");
while (token != NULL) {
count++;
token = strtok(NULL, " \t\n");
}
return count;
}
static
void free_args(char **args)
{
char **old_args = args;
for (; *args != NULL; args++)
free(*args);
free((void *)old_args);
}
static
char **parse_args(char *buffer)
{
int i = 0;
int arg_count = count_args(buffer);
char **args = (char **)malloc((arg_count + 1) * sizeof(char *));
char *token;
if (!args)
return NULL;
token = strtok(buffer, " ");
while (token != NULL) {
args[i] = (char *)malloc(u_strlen(token) + 1);
u_bzero(args[i], u_strlen(token) + 1);
if (args[i] == NULL)
return (free((void *)args), NULL);
u_strcpy(args[i], token);
i++;
token = strtok(NULL, " ");
}
args[i] = NULL;
return args;
}
static
int launch_bin(char *full_bin_path, char **args, char **env)
{
int status;
pid_t pid = fork();
if (pid == 0) {
if (execve(full_bin_path, args, env) < 0) {
WRITE_CONST(STDERR_FILENO, "Command not found.\n");
exit(127);
}
}
waitpid(pid, &status, 0);
return status;
}
int execute(char *buffer, env_t *env)
{
char *path = NULL;
char *full_bin_path;
char **args = parse_args(buffer);
if (!args)
return RETURN_FAILURE;
for (size_t i = 0; i < BUILTINS_SZ; i++)
if (u_strcmp(buffer, BUILTINS[i].name) == 0)
BUILTINS[i].ptr(0);
buffer[u_strlen(buffer) - 1] = '\0';
path = get_env_value(env, "PATH");
full_bin_path = find_binary(path, args[0]);
U_DEBUG("Found bin [%s]\n", full_bin_path);
if (full_bin_path == NULL)
return (free_args(args), RETURN_FAILURE);
launch_bin(full_bin_path, args, NULL);
free(full_bin_path);
free_args(args);
return 0;
}

26
src/exec.h Normal file
View File

@@ -0,0 +1,26 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef EXEC_H
#define EXEC_H
#include <stdint.h>
#include "env.h"
typedef struct {
char const *name;
void (*ptr)(uint64_t a);
} builtins_t;
typedef struct {
char **args;
size_t count;
size_t cap;
} args_t;
int execute(char *buffer, env_t *env);
#endif /* EXEC_H */

View File

@@ -5,7 +5,6 @@
** _
*/
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -14,41 +13,40 @@
#include "common.h"
#include "debug.h"
#include "env.h"
#include "exec.h"
#include "shell.h"
#include "u_str.h"
static
int shell_loop(void)
int shell_loop(env_t *env)
{
int is_a_tty = isatty(STDIN_FILENO);
char *buffer = NULL;
size_t buffer_sz;
signal(SIGINT, SIG_IGN);
while (true) {
if (is_a_tty)
WRITE_CONST(STDOUT_FILENO, SHELL_PROMPT);
if (getline(&buffer, &buffer_sz, stdin) == -1)
break;
U_DEBUG("Buffer [%.*s]\n", u_strlen(buffer) - 1, buffer);
if (u_strlen(buffer) < 2)
continue;
if (!u_str_is_alnum(buffer))
continue;
U_DEBUG("Buffer [%.*s]\n", u_strlen(buffer) - 1, buffer);
execute(buffer, env);
}
WRITE_CONST(STDOUT_FILENO, "exit\n");
free(buffer);
return RETURN_SUCCESS;
}
int shell(char **env)
int shell(char **env_ptr)
{
buff_t env_values = { 0 };
env_entry_t *env_entries = NULL;
size_t env_size = count_env_entries(env);
env_t env = parse_env(env_ptr);
env_values.str = malloc(ENV_BUFF_CAP);
if (env_values.str == NULL)
if (!env.env)
return RETURN_FAILURE;
env_entries = malloc(sizeof *env_entries * env_size);
parse_env(env, &env_values, env_entries);
U_DEBUG_CALL(debug_env_entries, env_entries, env_size);
return shell_loop();
U_DEBUG_CALL(debug_env_entries, &env);
return shell_loop(&env);
}