mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 12:53:13 +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-interactive-job-control
|
||||
status filename
|
||||
status fish-path
|
||||
status function
|
||||
status line-number
|
||||
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`.
|
||||
|
||||
- `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" (or equivalent translated string). Also `current-function`, `-u` or `--current-function`.
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ enum status_cmd_t {
|
|||
STATUS_CURRENT_CMD = 1,
|
||||
STATUS_FEATURES,
|
||||
STATUS_FILENAME,
|
||||
STATUS_FISH_PATH,
|
||||
STATUS_FUNCTION,
|
||||
STATUS_IS_BLOCK,
|
||||
STATUS_IS_BREAKPOINT,
|
||||
|
@ -45,6 +46,7 @@ const enum_map<status_cmd_t> status_enum_map[] = {
|
|||
{STATUS_LINE_NUMBER, L"current-line-number"},
|
||||
{STATUS_FEATURES, L"features"},
|
||||
{STATUS_FILENAME, L"filename"},
|
||||
{STATUS_FISH_PATH, L"fish-path"},
|
||||
{STATUS_FUNCTION, L"function"},
|
||||
{STATUS_IS_BLOCK, L"is-block"},
|
||||
{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-line-number", no_argument, NULL, 'n'},
|
||||
{L"filename", no_argument, NULL, 'f'},
|
||||
{L"fish-path", no_argument, NULL, STATUS_FISH_PATH},
|
||||
{L"is-block", no_argument, NULL, 'b'},
|
||||
{L"is-command-substitution", no_argument, NULL, 'c'},
|
||||
{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;
|
||||
}
|
||||
case STATUS_FISH_PATH: {
|
||||
if (!set_status_cmd(cmd, opts, STATUS_FISH_PATH, streams)) {
|
||||
return STATUS_CMD_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'L': {
|
||||
opts.level = fish_wcstoi(w.woptarg);
|
||||
if (opts.level < 0 || errno == ERANGE) {
|
||||
|
@ -417,7 +426,13 @@ int builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
streams.out.append(program_name);
|
||||
streams.out.push_back(L'\n');
|
||||
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;
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory> // IWYU pragma: keep
|
||||
#include <type_traits>
|
||||
|
@ -2248,3 +2252,49 @@ bool valid_func_name(const wcstring &str) {
|
|||
if (str.find_first_of(L'/') != wcstring::npos) return false;
|
||||
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
|
||||
|
||||
// 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 };
|
||||
|
||||
// Flags for unescape_string functions.
|
||||
|
@ -1007,4 +1017,7 @@ struct hash<const wcstring> {
|
|||
} // namespace std
|
||||
#endif
|
||||
|
||||
/// Get the absolute path to the fish executable itself
|
||||
std::string get_executable_path(const char *fallback);
|
||||
|
||||
#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 "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
|
||||
class fish_cmd_opts_t {
|
||||
public:
|
||||
|
@ -98,51 +89,6 @@ extern "C" {
|
|||
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) {
|
||||
struct config_paths_t paths;
|
||||
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};
|
||||
|
||||
#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.
|
||||
static owning_lock<std::unordered_map<wcstring, wcstring>> wgettext_map;
|
||||
|
||||
|
|
Loading…
Reference in a new issue