mirror of
https://github.com/fish-shell/fish-shell
synced 2024-11-15 09:27:38 +00:00
Detect at startup whether config and data paths are remote
This is in preparation for changing the locking regime of history.
This commit is contained in:
parent
541e1d2fad
commit
d1fd3d5825
3 changed files with 53 additions and 3 deletions
|
@ -415,7 +415,7 @@ void env_init(const struct config_paths_t *paths, bool do_uvars, bool default_pa
|
|||
init_input();
|
||||
|
||||
// Complain about invalid config paths.
|
||||
path_emit_config_directory_errors(vars);
|
||||
path_emit_config_directory_messages(vars);
|
||||
|
||||
if (do_uvars) {
|
||||
// Set up universal variables. The empty string means to use the default path.
|
||||
|
|
52
src/path.cpp
52
src/path.cpp
|
@ -6,7 +6,12 @@
|
|||
#include "path.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#if defined(__linux__)
|
||||
#include <sys/statfs.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstring>
|
||||
|
@ -100,6 +105,42 @@ bool path_is_executable(const std::string &path) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/// \return 1 if the path is remote, 0 if local, -1 if unknown.
|
||||
static int path_is_remote(const wcstring &path) {
|
||||
std::string narrow = wcs2string(path);
|
||||
#if defined(__linux__)
|
||||
struct statfs buf {};
|
||||
if (statfs(narrow.c_str(), &buf) < 0) {
|
||||
return -1;
|
||||
}
|
||||
// Linux has constants for these like NFS_SUPER_MAGIC, SMB_SUPER_MAGIC, CIFS_MAGIC_NUMBER but
|
||||
// these are in varying headers. Simply hard code them.
|
||||
// NOTE: The cast is necessary for 32-bit systems because of the 4-byte CIFS_MAGIC_NUMBER
|
||||
switch (static_cast<unsigned int>(buf.f_type)) {
|
||||
case 0x6969: // NFS_SUPER_MAGIC
|
||||
case 0x517B: // SMB_SUPER_MAGIC
|
||||
case 0xFE534D42U: // SMB2_MAGIC_NUMBER - not in the manpage
|
||||
case 0xFF534D42U: // CIFS_MAGIC_NUMBER
|
||||
return 1;
|
||||
default:
|
||||
// Other FSes are assumed local.
|
||||
return 0;
|
||||
}
|
||||
#elif defined(ST_LOCAL)
|
||||
// ST_LOCAL is a flag to statvfs, which is itself standardized.
|
||||
// In practice the only system to use this path is NetBSD.
|
||||
struct statvfs buf {};
|
||||
if (statvfs(narrow.c_str(), &buf) < 0) return -1;
|
||||
return (buf.f_flag & ST_LOCAL) ? 0 : 1;
|
||||
#elif defined(MNT_LOCAL)
|
||||
struct statfs buf {};
|
||||
if (statfs(narrow.c_str(), &buf) < 0) return -1;
|
||||
return (buf.f_flags & MNT_LOCAL) ? 0 : 1;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
wcstring_list_t path_get_paths(const wcstring &cmd, const environment_t &vars) {
|
||||
FLOGF(path, L"path_get_paths('%ls')", cmd.c_str());
|
||||
wcstring_list_t paths;
|
||||
|
@ -293,6 +334,7 @@ static int create_directory(const wcstring &d) {
|
|||
struct base_directory_t {
|
||||
wcstring path{}; /// the path where we attempted to create the directory.
|
||||
int err{0}; /// the error code if creating the directory failed, or 0 on success.
|
||||
int is_remote{-1}; /// 1 if the directory is remote (e.g. NFS), 0 if local, -1 if unknown.
|
||||
bool used_xdg{false}; /// whether an XDG variable was used in resolving the directory.
|
||||
|
||||
bool success() const { return err == 0; }
|
||||
|
@ -326,6 +368,8 @@ static base_directory_t make_base_directory(const wcstring &xdg_var,
|
|||
result.err = errno;
|
||||
} else {
|
||||
result.err = 0;
|
||||
// Need to append a trailing slash to check the contents of the directory, not its parent.
|
||||
result.is_remote = path_is_remote(result.path + L'/');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -340,12 +384,15 @@ static const base_directory_t &get_config_directory() {
|
|||
return s_dir;
|
||||
}
|
||||
|
||||
void path_emit_config_directory_errors(env_stack_t &vars) {
|
||||
void path_emit_config_directory_messages(env_stack_t &vars) {
|
||||
const auto &data = get_data_directory();
|
||||
if (!data.success()) {
|
||||
maybe_issue_path_warning(L"data", _(L"Your history will not be saved."), data.used_xdg,
|
||||
L"XDG_DATA_HOME", data.path, data.err, vars);
|
||||
}
|
||||
if (data.is_remote > 0) {
|
||||
FLOG(path, "data path appears to be on a network volume");
|
||||
}
|
||||
|
||||
const auto &config = get_config_directory();
|
||||
if (!config.success()) {
|
||||
|
@ -353,6 +400,9 @@ void path_emit_config_directory_errors(env_stack_t &vars) {
|
|||
config.used_xdg, L"XDG_CONFIG_HOME", config.path, config.err,
|
||||
vars);
|
||||
}
|
||||
if (config.is_remote > 0) {
|
||||
FLOG(path, "config path appears to be on a network volume");
|
||||
}
|
||||
}
|
||||
|
||||
bool path_get_config(wcstring &path) {
|
||||
|
|
|
@ -32,7 +32,7 @@ bool path_get_data(wcstring &path);
|
|||
/// Emit any errors if config directories are missing.
|
||||
/// Use the given environment stack to ensure this only occurs once.
|
||||
class env_stack_t;
|
||||
void path_emit_config_directory_errors(env_stack_t &vars);
|
||||
void path_emit_config_directory_messages(env_stack_t &vars);
|
||||
|
||||
/// Finds the full path of an executable.
|
||||
///
|
||||
|
|
Loading…
Reference in a new issue