mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 21:33:09 +00:00
Add status fish-path
Retrieves the fully resolved path to the currently executing fish binary (regardless of PATH). Can be used to ensure that the same fish is launched again from a script. `get_executable_path()` moved from fish binary to libfish, also cleaned up some duplicated (but differing!) definitions of PATH_MAX (which was used by that function) in the process.
This commit is contained in:
parent
c6230ddfde
commit
e212269ab1
6 changed files with 82 additions and 64 deletions
|
@ -12,6 +12,7 @@ status is-no-job-control
|
||||||
status is-full-job-control
|
status is-full-job-control
|
||||||
status is-interactive-job-control
|
status is-interactive-job-control
|
||||||
status filename
|
status filename
|
||||||
|
status fish-path
|
||||||
status function
|
status function
|
||||||
status line-number
|
status line-number
|
||||||
status stack-trace
|
status stack-trace
|
||||||
|
@ -44,6 +45,8 @@ The following operations (sub-commands) are available:
|
||||||
|
|
||||||
- `filename` prints the filename of the currently running script. Also `current-filename`, `-f` or `--current-filename`.
|
- `filename` prints the filename of the currently running script. Also `current-filename`, `-f` or `--current-filename`.
|
||||||
|
|
||||||
|
- `fish-path` prints the absolute path to the currently executing instance of fish.
|
||||||
|
|
||||||
- `function` prints the name of the currently called function if able, when missing displays "Not a
|
- `function` prints the name of the currently called function if able, when missing displays "Not a
|
||||||
function" (or equivalent translated string). Also `current-function`, `-u` or `--current-function`.
|
function" (or equivalent translated string). Also `current-function`, `-u` or `--current-function`.
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ enum status_cmd_t {
|
||||||
STATUS_CURRENT_CMD = 1,
|
STATUS_CURRENT_CMD = 1,
|
||||||
STATUS_FEATURES,
|
STATUS_FEATURES,
|
||||||
STATUS_FILENAME,
|
STATUS_FILENAME,
|
||||||
|
STATUS_FISH_PATH,
|
||||||
STATUS_FUNCTION,
|
STATUS_FUNCTION,
|
||||||
STATUS_IS_BLOCK,
|
STATUS_IS_BLOCK,
|
||||||
STATUS_IS_BREAKPOINT,
|
STATUS_IS_BREAKPOINT,
|
||||||
|
@ -45,6 +46,7 @@ const enum_map<status_cmd_t> status_enum_map[] = {
|
||||||
{STATUS_LINE_NUMBER, L"current-line-number"},
|
{STATUS_LINE_NUMBER, L"current-line-number"},
|
||||||
{STATUS_FEATURES, L"features"},
|
{STATUS_FEATURES, L"features"},
|
||||||
{STATUS_FILENAME, L"filename"},
|
{STATUS_FILENAME, L"filename"},
|
||||||
|
{STATUS_FISH_PATH, L"fish-path"},
|
||||||
{STATUS_FUNCTION, L"function"},
|
{STATUS_FUNCTION, L"function"},
|
||||||
{STATUS_IS_BLOCK, L"is-block"},
|
{STATUS_IS_BLOCK, L"is-block"},
|
||||||
{STATUS_IS_BREAKPOINT, L"is-breakpoint"},
|
{STATUS_IS_BREAKPOINT, L"is-breakpoint"},
|
||||||
|
@ -103,6 +105,7 @@ static const struct woption long_options[] = {{L"help", no_argument, NULL, 'h'},
|
||||||
{L"current-filename", no_argument, NULL, 'f'},
|
{L"current-filename", no_argument, NULL, 'f'},
|
||||||
{L"current-line-number", no_argument, NULL, 'n'},
|
{L"current-line-number", no_argument, NULL, 'n'},
|
||||||
{L"filename", no_argument, NULL, 'f'},
|
{L"filename", no_argument, NULL, 'f'},
|
||||||
|
{L"fish-path", no_argument, NULL, STATUS_FISH_PATH},
|
||||||
{L"is-block", no_argument, NULL, 'b'},
|
{L"is-block", no_argument, NULL, 'b'},
|
||||||
{L"is-command-substitution", no_argument, NULL, 'c'},
|
{L"is-command-substitution", no_argument, NULL, 'c'},
|
||||||
{L"is-full-job-control", no_argument, NULL, STATUS_IS_FULL_JOB_CTRL},
|
{L"is-full-job-control", no_argument, NULL, STATUS_IS_FULL_JOB_CTRL},
|
||||||
|
@ -169,6 +172,12 @@ static int parse_cmd_opts(status_cmd_opts_t &opts, int *optind, //!OCLINT(high
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case STATUS_FISH_PATH: {
|
||||||
|
if (!set_status_cmd(cmd, opts, STATUS_FISH_PATH, streams)) {
|
||||||
|
return STATUS_CMD_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'L': {
|
case 'L': {
|
||||||
opts.level = fish_wcstoi(w.woptarg);
|
opts.level = fish_wcstoi(w.woptarg);
|
||||||
if (opts.level < 0 || errno == ERANGE) {
|
if (opts.level < 0 || errno == ERANGE) {
|
||||||
|
@ -418,6 +427,12 @@ int builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
streams.out.push_back(L'\n');
|
streams.out.push_back(L'\n');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case STATUS_FISH_PATH: {
|
||||||
|
CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
|
||||||
|
streams.out.append(str2wcstring(get_executable_path("fish")).c_str());
|
||||||
|
streams.out.push_back(L'\n');
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
@ -30,6 +30,10 @@
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory> // IWYU pragma: keep
|
#include <memory> // IWYU pragma: keep
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
@ -2248,3 +2252,49 @@ bool valid_func_name(const wcstring &str) {
|
||||||
if (str.find_first_of(L'/') != wcstring::npos) return false;
|
if (str.find_first_of(L'/') != wcstring::npos) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the path to the current executable. This needs to be realpath'd.
|
||||||
|
std::string get_executable_path(const char *argv0) {
|
||||||
|
char buff[PATH_MAX];
|
||||||
|
|
||||||
|
#if __APPLE__
|
||||||
|
// On OS X use it's proprietary API to get the path to the executable.
|
||||||
|
// This is basically grabbing exec_path after argc, argv, envp, ...: for us
|
||||||
|
// https://opensource.apple.com/source/adv_cmds/adv_cmds-163/ps/print.c
|
||||||
|
uint32_t buffSize = sizeof buff;
|
||||||
|
if (_NSGetExecutablePath(buff, &buffSize) == 0) return std::string(buff);
|
||||||
|
#elif __FreeBSD__
|
||||||
|
// FreeBSD does not have /proc by default, but it can be mounted as procfs via the
|
||||||
|
// Linux compatibility layer. Per sysctl(3), passing in a process ID of -1 returns
|
||||||
|
// the value for the current process.
|
||||||
|
size_t buff_size = sizeof buff;
|
||||||
|
int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
|
||||||
|
int result = sysctl(name, sizeof(name) / sizeof(int), buff, &buff_size, nullptr, 0);
|
||||||
|
if (result != 0) {
|
||||||
|
wperror(L"sysctl KERN_PROC_PATHNAME");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return std::string(buff);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// On other unixes, fall back to the Linux-ish /proc/ directory
|
||||||
|
ssize_t len;
|
||||||
|
len = readlink("/proc/self/exe", buff, sizeof buff - 1); // Linux
|
||||||
|
if (len == -1) {
|
||||||
|
len = readlink("/proc/curproc/file", buff, sizeof buff - 1); // other BSDs
|
||||||
|
if (len == -1) {
|
||||||
|
len = readlink("/proc/self/path/a.out", buff, sizeof buff - 1); // Solaris
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (len > 0) {
|
||||||
|
buff[len] = '\0';
|
||||||
|
return std::string(buff);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Just return argv0, which probably won't work (i.e. it's not an absolute path or a path
|
||||||
|
// relative to the working directory, but instead something the caller found via $PATH). We'll
|
||||||
|
// eventually fall back to the compile time paths.
|
||||||
|
return std::string(argv0 ? argv0 : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
13
src/common.h
13
src/common.h
|
@ -106,6 +106,16 @@ static_assert(false, "Neither NAME_MAX nor MAXNAMELEN is defined!");
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// PATH_MAX may not exist.
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
#ifdef MAXPATHLEN
|
||||||
|
#define PATH_MAX MAXPATHLEN
|
||||||
|
#else
|
||||||
|
/// Fallback length of MAXPATHLEN. Hopefully a sane value.
|
||||||
|
#define PATH_MAX 4096
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
enum escape_string_style_t { STRING_STYLE_SCRIPT, STRING_STYLE_URL, STRING_STYLE_VAR };
|
enum escape_string_style_t { STRING_STYLE_SCRIPT, STRING_STYLE_URL, STRING_STYLE_VAR };
|
||||||
|
|
||||||
// Flags for unescape_string functions.
|
// Flags for unescape_string functions.
|
||||||
|
@ -1007,4 +1017,7 @@ struct hash<const wcstring> {
|
||||||
} // namespace std
|
} // namespace std
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// Get the absolute path to the fish executable itself
|
||||||
|
std::string get_executable_path(const char *fallback);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
54
src/fish.cpp
54
src/fish.cpp
|
@ -54,15 +54,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
#include "wutil.h" // IWYU pragma: keep
|
#include "wutil.h" // IWYU pragma: keep
|
||||||
|
|
||||||
#ifdef __FreeBSD__
|
|
||||||
#include <sys/sysctl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// PATH_MAX may not exist.
|
|
||||||
#ifndef PATH_MAX
|
|
||||||
#define PATH_MAX 4096
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// container to hold the options specified within the command line
|
// container to hold the options specified within the command line
|
||||||
class fish_cmd_opts_t {
|
class fish_cmd_opts_t {
|
||||||
public:
|
public:
|
||||||
|
@ -98,51 +89,6 @@ extern "C" {
|
||||||
int _NSGetExecutablePath(char *buf, uint32_t *bufsize);
|
int _NSGetExecutablePath(char *buf, uint32_t *bufsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the path to the current executable. This needs to be realpath'd.
|
|
||||||
static std::string get_executable_path(const char *argv0) {
|
|
||||||
char buff[PATH_MAX];
|
|
||||||
|
|
||||||
#if __APPLE__
|
|
||||||
// On OS X use it's proprietary API to get the path to the executable.
|
|
||||||
// This is basically grabbing exec_path after argc, argv, envp, ...: for us
|
|
||||||
// https://opensource.apple.com/source/adv_cmds/adv_cmds-163/ps/print.c
|
|
||||||
uint32_t buffSize = sizeof buff;
|
|
||||||
if (_NSGetExecutablePath(buff, &buffSize) == 0) return std::string(buff);
|
|
||||||
#elif __FreeBSD__
|
|
||||||
// FreeBSD does not have /proc by default, but it can be mounted as procfs via the
|
|
||||||
// Linux compatibility layer. Per sysctl(3), passing in a process ID of -1 returns
|
|
||||||
// the value for the current process.
|
|
||||||
size_t buff_size = sizeof buff;
|
|
||||||
int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
|
|
||||||
int result = sysctl(name, sizeof(name) / sizeof(int), buff, &buff_size, nullptr, 0);
|
|
||||||
if (result != 0) {
|
|
||||||
wperror(L"sysctl KERN_PROC_PATHNAME");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return std::string(buff);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// On other unixes, fall back to the Linux-ish /proc/ directory
|
|
||||||
ssize_t len;
|
|
||||||
len = readlink("/proc/self/exe", buff, sizeof buff - 1); // Linux
|
|
||||||
if (len == -1) {
|
|
||||||
len = readlink("/proc/curproc/file", buff, sizeof buff - 1); // other BSDs
|
|
||||||
if (len == -1) {
|
|
||||||
len = readlink("/proc/self/path/a.out", buff, sizeof buff - 1); // Solaris
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (len > 0) {
|
|
||||||
buff[len] = '\0';
|
|
||||||
return std::string(buff);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Just return argv0, which probably won't work (i.e. it's not an absolute path or a path
|
|
||||||
// relative to the working directory, but instead something the caller found via $PATH). We'll
|
|
||||||
// eventually fall back to the compile time paths.
|
|
||||||
return std::string(argv0 ? argv0 : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct config_paths_t determine_config_directory_paths(const char *argv0) {
|
static struct config_paths_t determine_config_directory_paths(const char *argv0) {
|
||||||
struct config_paths_t paths;
|
struct config_paths_t paths;
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
|
|
@ -33,15 +33,6 @@ typedef std::string cstring;
|
||||||
|
|
||||||
const file_id_t kInvalidFileID = {(dev_t)-1LL, (ino_t)-1LL, (uint64_t)-1LL, -1, -1, -1, -1};
|
const file_id_t kInvalidFileID = {(dev_t)-1LL, (ino_t)-1LL, (uint64_t)-1LL, -1, -1, -1, -1};
|
||||||
|
|
||||||
#ifndef PATH_MAX
|
|
||||||
#ifdef MAXPATHLEN
|
|
||||||
#define PATH_MAX MAXPATHLEN
|
|
||||||
#else
|
|
||||||
/// Fallback length of MAXPATHLEN. Hopefully a sane value.
|
|
||||||
#define PATH_MAX 4096
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Map used as cache by wgettext.
|
/// Map used as cache by wgettext.
|
||||||
static owning_lock<std::unordered_map<wcstring, wcstring>> wgettext_map;
|
static owning_lock<std::unordered_map<wcstring, wcstring>> wgettext_map;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue