/** When fishd isn't started, this function is provided to env_universal as a callback, it tries to start up fishd. It's implementation is a bit of a hack, since it evaluates a bit of shellscript, and it might be used at times when that might not be the best idea. */ static void start_fishd() { struct passwd *pw = getpwuid(getuid()); debug(3, L"Spawning new copy of fishd"); if (!pw) { debug(0, _(L"Could not get user information")); return; } wcstring cmd = format_string(FISHD_CMD, pw->pw_name); /* Prefer the fishd in __fish_bin_dir, if exists */ const env_var_t bin_dir = env_get_string(L"__fish_bin_dir"); if (! bin_dir.missing_or_empty()) { wcstring path = bin_dir + L"/fishd"; if (waccess(path, X_OK) == 0) { /* The path command just looks like 'fishd', so insert the bin path to make it absolute */ cmd.insert(0, bin_dir + L"/"); } } parser_t &parser = parser_t::principal_parser(); parser.eval(cmd, io_chain_t(), TOP); }
/// Make sure the PATH variable contains something. static void setup_path() { const env_var_t path = env_get_string(L"PATH"); if (path.missing_or_empty()) { const wchar_t *value = L"/usr/bin" ARRAY_SEP_STR L"/bin"; env_set(L"PATH", value, ENV_GLOBAL | ENV_EXPORT); } }
bool autoload_t::can_load(const wcstring &cmd, const env_vars_snapshot_t &vars) { const env_var_t path_var = vars.get(env_var_name); if (path_var.missing_or_empty()) return false; std::vector<wcstring> path_list; tokenize_variable_array(path_var, path_list); return this->locate_file_and_maybe_load_it(cmd, false, false, path_list); }
static void path_create(wcstring &path, const wcstring &xdg_var, const wcstring &which_dir, const wcstring &custom_error_msg) { bool path_done = false; bool using_xdg = false; int saved_errno = 0; // The vars we fetch must be exported. Allowing them to be universal doesn't make sense and // allowing that creates a lock inversion that deadlocks the shell since we're called before // uvars are available. const env_var_t xdg_dir = env_get_string(xdg_var, ENV_GLOBAL | ENV_EXPORT); if (!xdg_dir.missing_or_empty()) { using_xdg = true; path = xdg_dir + L"/fish"; if (create_directory(path) != -1) { path_done = true; } else { saved_errno = errno; } } else { const env_var_t home = env_get_string(L"HOME", ENV_GLOBAL | ENV_EXPORT); if (!home.missing_or_empty()) { path = home + (which_dir == L"config" ? L"/.config/fish" : L"/.local/share/fish"); if (create_directory(path) != -1) { path_done = true; } else { saved_errno = errno; } } } if (!path_done) { maybe_issue_path_warning(which_dir, custom_error_msg, using_xdg, xdg_var, path, saved_errno); path.clear(); } return; }
/** Call env_set. If this is a path variable, e.g. PATH, validate the elements. On error, print a description of the problem to stderr. */ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope) { size_t i; int retcode = 0; const wchar_t *val_str=NULL; if (is_path_variable(key)) { /* Fix for https://github.com/fish-shell/fish-shell/issues/199 . Return success if any path setting succeeds. */ bool any_success = false; /* Don't bother validating (or complaining about) values that are already present */ wcstring_list_t existing_values; const env_var_t existing_variable = env_get_string(key, scope); if (! existing_variable.missing_or_empty()) tokenize_variable_array(existing_variable, existing_values); for (i=0; i< val.size() ; i++) { const wcstring &dir = val.at(i); if (list_contains_string(existing_values, dir)) { any_success = true; continue; } bool show_perror = false; int show_hint = 0; bool error = false; struct stat buff; if (wstat(dir, &buff)) { error = true; show_perror = true; } if (!(S_ISDIR(buff.st_mode))) { error = true; } if (!error) { any_success = true; } else { append_format(stderr_buffer, _(BUILTIN_SET_PATH_ERROR), L"set", dir.c_str(), key); const wchar_t *colon = wcschr(dir.c_str(), L':'); if (colon && *(colon+1)) { show_hint = 1; } } if (show_perror) { builtin_wperror(L"set"); } if (show_hint) { append_format(stderr_buffer, _(BUILTIN_SET_PATH_HINT), L"set", key, key, wcschr(dir.c_str(), L':')+1); } } /* Fail at setting the path if we tried to set it to something non-empty, but it wound up empty. */ if (! val.empty() && ! any_success) { return 1; } } wcstring sb; if (! val.empty()) { for (i=0; i< val.size() ; i++) { sb.append(val[i]); if (i<val.size() - 1) { sb.append(ARRAY_SEP_STR); } } val_str = sb.c_str(); } switch (env_set(key, val_str, scope | ENV_USER)) { case ENV_PERM: { append_format(stderr_buffer, _(L"%ls: Tried to change the read-only variable '%ls'\n"), L"set", key); retcode=1; break; } case ENV_SCOPE: { append_format(stderr_buffer, _(L"%ls: Tried to set the special variable '%ls' with the wrong scope\n"), L"set", key); retcode=1; break; } case ENV_INVALID: { append_format(stderr_buffer, _(L"%ls: Tried to set the special variable '%ls' to an invalid value\n"), L"set", key); retcode=1; break; } } return retcode; }
bool path_get_cdpath_string(const wcstring &dir_str, wcstring &result, const env_var_t &cdpath) { wchar_t *res = 0; int err = ENOENT; bool success = false; const wchar_t *const dir = dir_str.c_str(); if (dir[0] == L'/'|| (wcsncmp(dir, L"./", 2)==0)) { struct stat buf; if (wstat(dir, &buf) == 0) { if (S_ISDIR(buf.st_mode)) { result = dir_str; success = true; } else { err = ENOTDIR; } } } else { wcstring path = L"."; // Respect CDPATH env_var_t cdpath = env_get_string(L"CDPATH"); if (! cdpath.missing_or_empty()) { path = cdpath.c_str(); } wcstokenizer tokenizer(path, ARRAY_SEP_STR); wcstring next_path; while (tokenizer.next(next_path)) { expand_tilde(next_path); if (next_path.size() == 0) continue; wcstring whole_path = next_path; append_path_component(whole_path, dir); struct stat buf; if (wstat(whole_path, &buf) == 0) { if (S_ISDIR(buf.st_mode)) { result = whole_path; success = true; break; } else { err = ENOTDIR; } } else { if (lwstat(whole_path, &buf) == 0) { err = EROTTEN; } } } } if (!success) { errno = err; } return res; }
/** Call env_set. If this is a path variable, e.g. PATH, validate the elements. On error, print a description of the problem to stderr. */ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope, io_streams_t &streams) { size_t i; int retcode = 0; const wchar_t *val_str=NULL; if (is_path_variable(key)) { /* Fix for https://github.com/fish-shell/fish-shell/issues/199 . Return success if any path setting succeeds. */ bool any_success = false; /* Don't bother validating (or complaining about) values that are already present. When determining already-present values, use ENV_DEFAULT instead of the passed-in scope because in: set -l PATH stuff $PATH where we are temporarily shadowing a variable, we want to compare against the shadowed value, not the (missing) local value. Also don't bother to complain about relative paths, which don't start with /. */ wcstring_list_t existing_values; const env_var_t existing_variable = env_get_string(key, ENV_DEFAULT); if (! existing_variable.missing_or_empty()) tokenize_variable_array(existing_variable, existing_values); for (i=0; i< val.size() ; i++) { const wcstring &dir = val.at(i); if (!string_prefixes_string(L"/", dir) || list_contains_string(existing_values, dir)) { any_success = true; continue; } bool show_perror = false; int show_hint = 0; bool error = false; struct stat buff; if (wstat(dir, &buff)) { error = true; show_perror = true; } if (!(S_ISDIR(buff.st_mode))) { error = true; } if (!error) { any_success = true; } else { streams.err.append_format(_(BUILTIN_SET_PATH_ERROR), L"set", dir.c_str(), key); const wchar_t *colon = wcschr(dir.c_str(), L':'); if (colon && *(colon+1)) { show_hint = 1; } } if (show_perror) { builtin_wperror(L"set", streams); } if (show_hint) { streams.err.append_format(_(BUILTIN_SET_PATH_HINT), L"set", key, key, wcschr(dir.c_str(), L':')+1); } } /* Fail at setting the path if we tried to set it to something non-empty, but it wound up empty. */ if (! val.empty() && ! any_success) { return 1; } } wcstring sb; if (! val.empty()) { for (i=0; i< val.size() ; i++) { sb.append(val[i]); if (i<val.size() - 1) { sb.append(ARRAY_SEP_STR); } } val_str = sb.c_str(); } switch (env_set(key, val_str, scope | ENV_USER)) { case ENV_PERM: { streams.err.append_format(_(L"%ls: Tried to change the read-only variable '%ls'\n"), L"set", key); retcode=1; break; } case ENV_SCOPE: { streams.err.append_format(_(L"%ls: Tried to set the special variable '%ls' with the wrong scope\n"), L"set", key); retcode=1; break; } case ENV_INVALID: { streams.err.append_format(_(L"%ls: Tried to set the special variable '%ls' to an invalid value\n"), L"set", key); retcode=1; break; } } return retcode; }