diff --git a/include/vstr.h b/include/vstr.h new file mode 100644 index 0000000..9c68d7e --- /dev/null +++ b/include/vstr.h @@ -0,0 +1,35 @@ +#ifndef VSTR_INCLUDED +#define VSTR_INCLUDED + +#include +#include +#include + +struct Vstr { + size_t len; // String len + char *buf; // String data +}; +typedef struct Vstr Vstr; + +#define Vstr_Fmt "%.*s" +#define Vstr_Arg(vstr) (int) (vstr).len, (vstr).buf +#define VSTR(cstr) vstr_n(cstr, sizeof(cstr) - 1) +#define VSTR_NULL vstr_n(NULL, 0) + +size_t pack_vstr(unsigned char *buffer, Vstr *vstr); +void unpack_vstr(unsigned char *buffer, Vstr *vstr); +size_t pack_vstr_array(unsigned char *buffer, Vstr *array, size_t count); +Vstr *unpack_vstr_array(unsigned char *buffer, size_t *count); +Vstr vstr_s(const char *s); +Vstr vstr_n(const char *s, size_t n); +bool vstr_cmp(const Vstr v1, const Vstr v2); +const char *vstr_str(const Vstr haystack, const Vstr needle); +Vstr vstr_after_delim(const Vstr v, const char *delims); +Vstr vstr_before_delim(const Vstr v, const char *delims); +Vstr vstr_substr(Vstr v, size_t start, size_t stop); +Vstr vstr_trim(Vstr v); +Vstr vstr_trim_left(Vstr v); +Vstr vstr_trim_right(Vstr v); + + +#endif diff --git a/src/vstr.c b/src/vstr.c new file mode 100644 index 0000000..8d5bde2 --- /dev/null +++ b/src/vstr.c @@ -0,0 +1,215 @@ +#include "../include/vstr.h" +#include + +size_t pack_vstr(unsigned char *buffer, Vstr *vstr) { + size_t offset = 0; + + // Pack the length of the string first (size_t) + buffer[offset++] = (vstr->len >> 56) & 0xFF; + buffer[offset++] = (vstr->len >> 48) & 0xFF; + buffer[offset++] = (vstr->len >> 40) & 0xFF; + buffer[offset++] = (vstr->len >> 32) & 0xFF; + buffer[offset++] = (vstr->len >> 24) & 0xFF; + buffer[offset++] = (vstr->len >> 16) & 0xFF; + buffer[offset++] = (vstr->len >> 8) & 0xFF; + buffer[offset++] = vstr->len & 0xFF; + + // Pack the string data + memcpy(&buffer[offset], vstr->buf, vstr->len); + offset += vstr->len; + + return offset; // Return the total packed size +} +void unpack_vstr(unsigned char *buffer, Vstr *vstr) { + unsigned int offset = 0; + + // Unpack the length of the string (size_t) + vstr->len = 0; + for (int i = 0; i < 8; i++) { + vstr->len = (vstr->len << 8) | buffer[offset++]; + } + + // Allocate memory for the string and copy it from the buffer + vstr->buf = (char *)malloc(vstr->len + 1); // +1 for null terminator + if (vstr->buf != NULL) { + memcpy(vstr->buf, &buffer[offset], vstr->len); + vstr->buf[vstr->len] = '\0'; // Null-terminate the string + } else { + vstr->len = 0; // If memory allocation fails, set len to 0 + } +} +size_t pack_vstr_array(unsigned char *buffer, Vstr *array, size_t count) { + size_t offset = 0; + + // Pack the number of elements in the array + buffer[offset++] = (count >> 56) & 0xFF; + buffer[offset++] = (count >> 48) & 0xFF; + buffer[offset++] = (count >> 40) & 0xFF; + buffer[offset++] = (count >> 32) & 0xFF; + buffer[offset++] = (count >> 24) & 0xFF; + buffer[offset++] = (count >> 16) & 0xFF; + buffer[offset++] = (count >> 8) & 0xFF; + buffer[offset++] = count & 0xFF; + + // Pack each Vstr in the array + for (size_t i = 0; i < count; i++) { + // Pack the length of the string + buffer[offset++] = (array[i].len >> 56) & 0xFF; + buffer[offset++] = (array[i].len >> 48) & 0xFF; + buffer[offset++] = (array[i].len >> 40) & 0xFF; + buffer[offset++] = (array[i].len >> 32) & 0xFF; + buffer[offset++] = (array[i].len >> 24) & 0xFF; + buffer[offset++] = (array[i].len >> 16) & 0xFF; + buffer[offset++] = (array[i].len >> 8) & 0xFF; + buffer[offset++] = array[i].len & 0xFF; + + // Pack the string data + memcpy(&buffer[offset], array[i].buf, array[i].len); + offset += array[i].len; + } + + return offset; // Return the total packed size +} +Vstr *unpack_vstr_array(unsigned char *buffer, size_t *count) { + size_t offset = 0; + + // Unpack the number of elements in the array + *count = 0; + for (int i = 0; i < 8; i++) { + *count = (*count << 8) | buffer[offset++]; + } + + // Allocate memory for the Vstr array + Vstr *array = malloc(*count * sizeof(Vstr)); + if (!array) return NULL; // Memory allocation failure + + // Unpack each Vstr in the array + for (size_t i = 0; i < *count; i++) { + // Unpack the length of the string + array[i].len = 0; + for (int j = 0; j < 8; j++) { + array[i].len = (array[i].len << 8) | buffer[offset++]; + } + + // Allocate memory for the string + array[i].buf = malloc(array[i].len + 1); // +1 for null terminator + if (!array[i].buf) { + // Free previously allocated memory in case of failure + for (size_t k = 0; k < i; k++) { + free(array[k].buf); + } + free(array); + return NULL; + } + + // Copy the string data + memcpy(array[i].buf, &buffer[offset], array[i].len); + array[i].buf[array[i].len] = '\0'; // Null-terminate the string + offset += array[i].len; + } + + return array; +} + +Vstr vstr_s(const char *s){ + Vstr v = {s == NULL ? 0 : strlen(s), (char *)s}; + return v; +} +Vstr vstr_n(const char *s, size_t n){ + Vstr v = {n,(char *)s}; + return v; +} +bool vstr_cmp(const Vstr v1, const Vstr v2){ + size_t i = 0; + while (i < v1.len && i < v2.len) { + int c1 = v1.buf[i]; + int c2 = v2.buf[i]; + if (c1 < c2) return false; + if (c1 > c2) return true; + i++; + } + if (i < v1.len) return true; + if (i < v2.len) return false; + return false; +} +const char *vstr_str(const Vstr haystack, const Vstr needle){ + size_t i; + if (needle.len > haystack.len) return NULL; + if (needle.len == 0) return haystack.buf; + for (i = 0; i <= haystack.len - needle.len; i++) { + if (memcmp(haystack.buf + i, needle.buf, needle.len) == 0) { + return haystack.buf + i; + } + } + return NULL; +} +Vstr vstr_after_delim(const Vstr v, const char *delims) { + // Handle NULL pointer or empty string view + if (v.buf == NULL || delims == NULL) { + return vstr_n(NULL, 0); + } + + size_t i = 0; + while (i < v.len) { + // Check if the current character is a delimiter + for (size_t j = 0; delims[j] != '\0'; j++) { + if (v.buf[i] == delims[j]) { + Vstr result = vstr_n(v.buf+i+1, v.len-i-1); + return result; + } + } + i++; + } + + // Return the whole string if no delimiter was found + Vstr result = vstr_n(v.buf, i); + return result; +} +Vstr vstr_before_delim(const Vstr v, const char *delims) { + // Handle NULL pointer or empty string view + if (v.buf == NULL || delims == NULL) { + return vstr_n(NULL, 0); + } + + size_t i = 0; + while (i < v.len) { + // Check if the current character is a delimiter + for (size_t j = 0; delims[j] != '\0'; j++) { + if (v.buf[i] == delims[j]) { + Vstr result = vstr_n(v.buf, i); + return result; + } + } + i++; + } + + // Return the whole string if no delimiter was found + Vstr result = vstr_n(v.buf, i); + return result; +} +Vstr vstr_substr(Vstr v, size_t start, size_t stop) { + if (start >= v.len || stop > v.len || start >= stop) { + // Return an empty Vstr if indices are out of bounds or invalid + return vstr_n(NULL, 0); + } + size_t sub_len = stop - start; + return vstr_n(v.buf + start, sub_len); +} + +static bool is_space(int c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f'; +} +Vstr vstr_trim(Vstr v){ + while (v.len > 0 && is_space((int) *v.buf)) v.buf++, v.len--; + while (v.len > 0 && is_space((int) *(v.buf + v.len - 1))) v.len--; + return v; +} +Vstr vstr_trim_left(Vstr v){ + while (v.len > 0 && is_space((int) *v.buf)) v.buf++, v.len--; + return v; +} +Vstr vstr_trim_right(Vstr v){ + while (v.len > 0 && is_space((int) *(v.buf + v.len - 1))) v.len--; + return v; +} + diff --git a/tests/02_execute.c b/tests/02_execute.c index a56c760..8a200a2 100644 --- a/tests/02_execute.c +++ b/tests/02_execute.c @@ -1,8 +1,15 @@ #include "../include/exectd.h" int main() { - char *argv[] = {"/bin/ping", "-c","3","myrepos.dev", NULL}; // Example arguments - char *envp[] = {NULL}; // Example environment variables - int status = execute_job("/bin/ping", argv, envp); + // Arguments for the ls command + char *argv[] = {"ls", "-l", "-a", NULL}; + + // Custom environment variables + char *envp[] = { + "MY_ENV_VAR=example", + "PATH=/usr/bin:/bin", // Ensure PATH is set for executable lookup + NULL + }; + int status = execute_job("/bin/ls", argv, envp); if (status != 0) { // Handle error printf("my_execve returned error code: %d\n", status); diff --git a/tests/03_shell.c b/tests/03_shell.c index 27b5d9d..5568c3d 100644 --- a/tests/03_shell.c +++ b/tests/03_shell.c @@ -1,10 +1,19 @@ #include "../include/exectd.h" int main() { - char *argv[] = {"/bin/ping", "-c","3","myrepos.dev", NULL}; // Example arguments - char *envp[] = {NULL}; // Example environment variables + + // Arguments for the ls command + char *argv[] = {"ls", "-l", "-a", NULL}; + + // Custom environment variables + char *envp[] = { + "MY_ENV_VAR=example", + "PATH=/usr/bin:/bin", // Ensure PATH is set for executable lookup + NULL + }; + int fd = ext_open("tests/bin/stdout_dup", O_WRONLY | O_CREAT); int fd2 = ext_open("tests/bin/stderr_dup", O_WRONLY | O_CREAT); - int status = shell_job("/bin/ping", argv, envp, fd, fd2); + int status = shell_job("/bin/ls", argv, envp, fd, fd2); if (status != 0) { // Handle error printf("Shell job returned error code: %d\n", status); diff --git a/tests/04_packed.c b/tests/04_packed.c new file mode 100644 index 0000000..fae10de --- /dev/null +++ b/tests/04_packed.c @@ -0,0 +1,114 @@ +#include "../include/exectd.h" +#include "../include/vstr.h" + +#include +size_t pack_execvpe_args(unsigned char *buffer, const char *file, char *const argv[], char *const envp[]) { + unsigned char *start = buffer; + + // Pack the `file` string + Vstr file_vstr = vstr_s(file); + buffer += pack_vstr(buffer, &file_vstr); + + // Pack `argv` + size_t argv_count = 0; + while (argv && argv[argv_count]) argv_count++; + memcpy(buffer, &argv_count, sizeof(size_t)); + buffer += sizeof(size_t); + + for (size_t i = 0; i < argv_count; i++) { + Vstr arg_vstr = vstr_s(argv[i]); + buffer += pack_vstr(buffer, &arg_vstr); + } + + // Pack `envp` + size_t envp_count = 0; + while (envp && envp[envp_count]) envp_count++; + memcpy(buffer, &envp_count, sizeof(size_t)); + buffer += sizeof(size_t); + + for (size_t i = 0; i < envp_count; i++) { + Vstr env_vstr = vstr_s(envp[i]); + buffer += pack_vstr(buffer, &env_vstr); + } + + return buffer - start; // Total packed size +} + +void unpack_execvpe_args(unsigned char *buffer, char **file, char ***argv, char ***envp) { + // Unpack `file` + Vstr file_vstr; + unpack_vstr(buffer, &file_vstr); + buffer += sizeof(size_t) + file_vstr.len; + *file = strndup(file_vstr.buf, file_vstr.len); + free(file_vstr.buf); + // Unpack `argv` + size_t argv_count; + memcpy(&argv_count, buffer, sizeof(size_t)); + buffer += sizeof(size_t); + *argv = malloc((argv_count + 1) * sizeof(char *)); + for (size_t i = 0; i < argv_count; i++) { + Vstr arg_vstr; + unpack_vstr(buffer, &arg_vstr); + buffer += sizeof(size_t) + arg_vstr.len; + (*argv)[i] = strndup(arg_vstr.buf, arg_vstr.len); + free(arg_vstr.buf); + } + (*argv)[argv_count] = NULL; + + // Unpack `envp` + size_t envp_count; + memcpy(&envp_count, buffer, sizeof(size_t)); + buffer += sizeof(size_t); + *envp = malloc((envp_count + 1) * sizeof(char *)); + for (size_t i = 0; i < envp_count; i++) { + Vstr env_vstr; + unpack_vstr(buffer, &env_vstr); + buffer += sizeof(size_t) + env_vstr.len; + (*envp)[i] = strndup(env_vstr.buf, env_vstr.len); + free(env_vstr.buf); + } + (*envp)[envp_count] = NULL; +} +int main(void) { + // Original arguments + const char *file = "/bin/ls"; + // Arguments for the ls command + char *argv[] = {"ls", "-l", "-a", NULL}; + + // Custom environment variables + char *envp[] = { + "MY_ENV_VAR=example", + "PATH=/usr/bin:/bin", // Ensure PATH is set for executable lookup + NULL + }; + // Buffer for packing + unsigned char buffer[1024]; // Adjust size as needed + size_t packed_size; + + // Pack the arguments + packed_size = pack_execvpe_args(buffer, file, argv, envp); + (void)packed_size; + // Unpack the arguments + char *unpacked_file; + char **unpacked_argv; + char **unpacked_envp; + unpack_execvpe_args(buffer, &unpacked_file, &unpacked_argv, &unpacked_envp); + + // Call execute_job with unpacked arguments + int status = execute_job(unpacked_file, unpacked_argv, unpacked_envp); + + // Free unpacked arguments + free(unpacked_file); + for (char **arg = unpacked_argv; *arg; ++arg) free(*arg); + free(unpacked_argv); + for (char **env = unpacked_envp; *env; ++env) free(*env); + free(unpacked_envp); + + // Check execution status + if (status != 0) { + printf("execute_job returned error code: %d\n", status); + } + printf("Job finished with %d \n",status); + // Code here will run after the child process has finished + return 0; +}