diff --git a/configure.ac b/configure.ac index 7ffe7d8..bdc9aab 100644 --- a/configure.ac +++ b/configure.ac @@ -29,6 +29,7 @@ AC_CHECK_FUNCS([getopt_long]) AC_CHECK_FUNCS([vsnprintf vasprintf strlcat strtoul memrchr]) AC_CHECK_FUNCS([fdatasync]) AC_CHECK_FUNCS([fpathconf sysconf posix_memalign posix_fadvise]) +AC_CHECK_FUNCS([getcwd]) AC_CHECK_FUNCS([nanosleep]) AC_CHECK_FUNCS([setitimer]) AC_CHECK_FUNCS([setproctitle]) @@ -58,7 +59,7 @@ dnl Libraries that may contain key functions. AC_SEARCH_LIBS([clock_gettime],[rt]) dnl Items we can't do without. -AC_CHECK_FUNCS([alarm basename clock_gettime dup2 getcwd memcpy memmove memset mkdir select setlocale strchr strerror strrchr strstr], [], [AC_MSG_ERROR([required function is missing])]) +AC_CHECK_FUNCS([alarm basename clock_gettime dup2 memcpy memmove memset mkdir select setlocale strchr strerror strrchr strstr], [], [AC_MSG_ERROR([required function is missing])]) AC_CHECK_HEADERS([fcntl.h sys/file.h sys/time.h unistd.h], [], [AC_MSG_ERROR([required header file is missing])]) dnl Make sure all the types we use are defined. diff --git a/src/include/pv-internal.h b/src/include/pv-internal.h index b3a7c9f..1884d1c 100644 --- a/src/include/pv-internal.h +++ b/src/include/pv-internal.h @@ -44,7 +44,6 @@ extern "C" { /* Sizes for various statically sized buffers. */ #define PV_SIZEOF_DEFAULT_FORMAT 512 -#define PV_SIZEOF_CWD 4096 #define PV_SIZEOF_LASTWRITTEN_BUFFER 256 #define PV_SIZEOF_PREVLINE_BUFFER 1024 #define PV_FORMAT_ARRAY_MAX 100 @@ -157,7 +156,7 @@ struct pvstate_s { * Program status * ******************/ struct pvprogramstatus_s { - char cwd[PV_SIZEOF_CWD]; /* current working directory for relative path */ + nullable_only_string_t cwd; /* for relative paths in --watchfd */ int current_input_file; /* index of current file being read */ int exit_status; /* exit status to give (0=OK) */ bool terminal_supports_utf8; /* whether the terminal supports UTF-8 */ diff --git a/src/pv/state.c b/src/pv/state.c index 94f56a5..5bc6cd7 100644 --- a/src/pv/state.c +++ b/src/pv/state.c @@ -190,6 +190,7 @@ void pv_state_reset(pvstate_t state) pvstate_t pv_state_alloc(void) { pvstate_t state; + size_t try_size; state = calloc(1, sizeof(*state)); if (NULL == state) @@ -209,19 +210,35 @@ pvstate_t pv_state_alloc(void) pv_state_reset(state); +#ifdef HAVE_GETCWD /* * Get the current working directory, if possible, as a base for * showing relative filenames with --watchfd. + * + * If this fails then --watchfd will fall back to always showing the + * full path. */ - if (NULL == getcwd(state->status.cwd, PV_SIZEOF_CWD - 1)) { - /* failed - will always show full path. */ - state->status.cwd[0] = '\0'; + for (try_size = 32; try_size <= 16384; try_size = try_size * 2) { + bool buffer_too_small; + + /*@-mustfreeonly@ *//* splint mis-detects a memory leak here */ + state->status.cwd = malloc(try_size); + /*@+mustfreeonly@ */ + if (NULL == state->status.cwd) + break; + + buffer_too_small = false; + if (NULL == getcwd(state->status.cwd, try_size)) { + if (errno != ERANGE) + buffer_too_small = true; + free(state->status.cwd); + state->status.cwd = NULL; + } + + if (!buffer_too_small) + break; } - if ('\0' == state->status.cwd[1]) { - /* CWD is root directory - always show full path. */ - state->status.cwd[0] = '\0'; - } - state->status.cwd[PV_SIZEOF_CWD - 1] = '\0'; +#endif /* HAVE_GETCWD */ return state; } @@ -360,6 +377,11 @@ void pv_state_free(pvstate_t state) state->control.output_name = NULL; } + if (NULL != state->status.cwd) { + free(state->status.cwd); + state->status.cwd = NULL; + } + pv_freecontents_display(&(state->display)); pv_freecontents_display(&(state->extra_display)); diff --git a/src/pv/watchpid.c b/src/pv/watchpid.c index e5257dc..40941c6 100644 --- a/src/pv/watchpid.c +++ b/src/pv/watchpid.c @@ -683,9 +683,12 @@ void pv_watchpid_setname(pvstate_t state, pvwatchfd_t info) memset(info->display_name, 0, PV_SIZEOF_DISPLAY_NAME); path_length = strlen(info->file_fdpath); /* flawfinder: ignore */ - cwd_length = strlen(state->status.cwd); /* flawfinder: ignore */ + cwd_length = 0; + if (NULL != state->status.cwd) { + cwd_length = strlen(state->status.cwd); /* flawfinder: ignore */ + } /* flawfinder: both strings are always \0 terminated. */ - if (cwd_length > 0 && path_length > cwd_length) { + if (cwd_length > 0 && path_length > cwd_length && NULL != state->status.cwd) { if (0 == strncmp(info->file_fdpath, state->status.cwd, cwd_length)) { file_fdpath += cwd_length + 1; path_length -= cwd_length + 1;