From 9766cc07dcb5964d26fe9e8fd6b1a41b860cea84 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 4 Nov 2020 10:28:15 +0100 Subject: [PATCH] Don't rely on PATH_MAX when calling getcwd References: https://github.com/emersion/mrsh/issues/167 --- builtin/cd.c | 9 +++++---- include/shell/path.h | 2 ++ shell/entry.c | 8 +++++--- shell/path.c | 19 +++++++++++++++++++ 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/builtin/cd.c b/builtin/cd.c index ca97b93..77a3ebe 100644 --- a/builtin/cd.c +++ b/builtin/cd.c @@ -9,6 +9,7 @@ #include "builtin.h" #include "mrsh_getopt.h" #include "mrsh_limit.h" +#include "shell/path.h" static const char cd_usage[] = "usage: cd [-L|-P] [-|directory]\n"; @@ -19,14 +20,14 @@ static int cd(struct mrsh_state *state, const char *path) { fprintf(stderr, "cd: %s\n", strerror(errno)); return 1; } - char cwd[PATH_MAX]; - if (getcwd(cwd, PATH_MAX) == NULL) { - fprintf(stderr, "cd: Cannot set new PWD as the path " - "is too long\n"); + char *cwd = current_working_dir(); + if (cwd == NULL) { + perror("current_working_dir failed"); return 1; } mrsh_env_set(state, "OLDPWD", oldPWD, MRSH_VAR_ATTRIB_NONE); mrsh_env_set(state, "PWD", cwd, MRSH_VAR_ATTRIB_EXPORT); + free(cwd); return 0; } diff --git a/include/shell/path.h b/include/shell/path.h index 932563b..14cf490 100644 --- a/include/shell/path.h +++ b/include/shell/path.h @@ -12,5 +12,7 @@ */ char *expand_path(struct mrsh_state *state, const char *file, bool exec, bool default_path); +/* Like getcwd, but returns allocated memory */ +char *current_working_dir(void); #endif diff --git a/shell/entry.c b/shell/entry.c index 2ef81a7..75f19e8 100644 --- a/shell/entry.c +++ b/shell/entry.c @@ -9,6 +9,7 @@ #include #include "builtin.h" #include "parser.h" +#include "shell/path.h" #include "shell/trap.h" #include "mrsh_limit.h" @@ -98,13 +99,14 @@ bool mrsh_populate_env(struct mrsh_state *state, char **environ) { // TODO check if path is well-formed, has . or .., and handle symbolic links const char *pwd = mrsh_env_get(state, "PWD", NULL); if (pwd == NULL || strlen(pwd) >= PATH_MAX) { - char cwd[PATH_MAX]; - if (getcwd(cwd, PATH_MAX) == NULL) { - perror("getcwd"); + char *cwd = current_working_dir(); + if (cwd == NULL) { + perror("current_working_dir failed"); return false; } mrsh_env_set(state, "PWD", cwd, MRSH_VAR_ATTRIB_EXPORT | MRSH_VAR_ATTRIB_READONLY); + free(cwd); } else { mrsh_env_set(state, "PWD", pwd, MRSH_VAR_ATTRIB_EXPORT | MRSH_VAR_ATTRIB_READONLY); diff --git a/shell/path.c b/shell/path.c index f361211..2d6ad72 100644 --- a/shell/path.c +++ b/shell/path.c @@ -1,4 +1,6 @@ #define _POSIX_C_SOURCE 200809L +#include +#include #include #include #include @@ -64,3 +66,20 @@ next: free(pathe); return NULL; } + +char *current_working_dir(void) { + // POSIX doesn't provide a way to query the CWD size + struct mrsh_buffer buf = {0}; + if (mrsh_buffer_reserve(&buf, 256) == NULL) { + return NULL; + } + while (getcwd(buf.data, buf.cap) == NULL) { + if (errno != ERANGE) { + return NULL; + } + if (mrsh_buffer_reserve(&buf, buf.cap * 2) == NULL) { + return NULL; + } + } + return mrsh_buffer_steal(&buf); +} -- 2.45.2