mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-14 05:53:59 +00:00
Beginning steps towards teaching the universal variable system to read
the fishd file directly, instead of fetching it through fishd
This commit is contained in:
parent
bf14668b2a
commit
6a94b51cba
4 changed files with 400 additions and 179 deletions
|
@ -277,11 +277,21 @@ static void reconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void env_universal_read_from_file()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void env_universal_init(wchar_t * p,
|
void env_universal_init(wchar_t * p,
|
||||||
wchar_t *u,
|
wchar_t *u,
|
||||||
void (*sf)(),
|
void (*sf)(),
|
||||||
void (*cb)(fish_message_type_t type, const wchar_t *name, const wchar_t *val))
|
void (*cb)(fish_message_type_t type, const wchar_t *name, const wchar_t *val))
|
||||||
|
{
|
||||||
|
if (! synchronizes_via_fishd())
|
||||||
|
{
|
||||||
|
env_universal_read_from_file();
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
path=p;
|
path=p;
|
||||||
user=u;
|
user=u;
|
||||||
|
@ -297,6 +307,7 @@ void env_universal_init(wchar_t * p,
|
||||||
env_universal_barrier();
|
env_universal_barrier();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void env_universal_destroy()
|
void env_universal_destroy()
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -41,6 +42,7 @@
|
||||||
#include "wutil.h"
|
#include "wutil.h"
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
#include "env_universal_common.h"
|
#include "env_universal_common.h"
|
||||||
|
#include "path.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Non-wide version of the set command
|
Non-wide version of the set command
|
||||||
|
@ -87,9 +89,6 @@
|
||||||
*/
|
*/
|
||||||
#define ENV_UNIVERSAL_EOF 0x102
|
#define ENV_UNIVERSAL_EOF 0x102
|
||||||
|
|
||||||
static void parse_message(wchar_t *msg,
|
|
||||||
connection_t *src);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The table of all universal variables
|
The table of all universal variables
|
||||||
*/
|
*/
|
||||||
|
@ -130,6 +129,11 @@ void env_universal_common_init(void (*cb)(fish_message_type_t type, const wchar_
|
||||||
callback = cb;
|
callback = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void read_message(connection_t *conn)
|
||||||
|
{
|
||||||
|
return s_env_universal_var.read_message(conn);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Read one byte of date form the specified connection
|
Read one byte of date form the specified connection
|
||||||
*/
|
*/
|
||||||
|
@ -172,84 +176,6 @@ static int read_byte(connection_t *src)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void read_message(connection_t *src)
|
|
||||||
{
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
|
|
||||||
int ib = read_byte(src);
|
|
||||||
char b;
|
|
||||||
|
|
||||||
switch (ib)
|
|
||||||
{
|
|
||||||
case ENV_UNIVERSAL_AGAIN:
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ENV_UNIVERSAL_ERROR:
|
|
||||||
{
|
|
||||||
debug(2, L"Read error on fd %d, set killme flag", src->fd);
|
|
||||||
if (debug_level > 2)
|
|
||||||
wperror(L"read");
|
|
||||||
src->killme = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ENV_UNIVERSAL_EOF:
|
|
||||||
{
|
|
||||||
src->killme = 1;
|
|
||||||
debug(3, L"Fd %d has reached eof, set killme flag", src->fd);
|
|
||||||
if (! src->input.empty())
|
|
||||||
{
|
|
||||||
char c = 0;
|
|
||||||
src->input.push_back(c);
|
|
||||||
debug(1,
|
|
||||||
L"Universal variable connection closed while reading command. Partial command recieved: '%s'",
|
|
||||||
&src->input.at(0));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b = (char)ib;
|
|
||||||
|
|
||||||
if (b == '\n')
|
|
||||||
{
|
|
||||||
wchar_t *msg;
|
|
||||||
|
|
||||||
b = 0;
|
|
||||||
src->input.push_back(b);
|
|
||||||
|
|
||||||
msg = utf2wcs(&src->input.at(0));
|
|
||||||
|
|
||||||
/*
|
|
||||||
Before calling parse_message, we must empty reset
|
|
||||||
everything, since the callback function could
|
|
||||||
potentially call read_message.
|
|
||||||
*/
|
|
||||||
src->input.clear();
|
|
||||||
|
|
||||||
if (msg)
|
|
||||||
{
|
|
||||||
parse_message(msg, src);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
debug(0, _(L"Could not convert message '%s' to wide character string"), &src->input.at(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
free(msg);
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
src->input.push_back(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Remove variable with specified name
|
Remove variable with specified name
|
||||||
*/
|
*/
|
||||||
|
@ -286,89 +212,6 @@ void env_universal_common_set(const wchar_t *key, const wchar_t *val, bool expor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Parse message msg
|
|
||||||
*/
|
|
||||||
static void parse_message(wchar_t *msg,
|
|
||||||
connection_t *src)
|
|
||||||
{
|
|
||||||
// debug( 3, L"parse_message( %ls );", msg );
|
|
||||||
|
|
||||||
if (msg[0] == L'#')
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (match(msg, SET_STR) || match(msg, SET_EXPORT_STR))
|
|
||||||
{
|
|
||||||
wchar_t *name, *tmp;
|
|
||||||
bool exportv = match(msg, SET_EXPORT_STR);
|
|
||||||
|
|
||||||
name = msg+(exportv?wcslen(SET_EXPORT_STR):wcslen(SET_STR));
|
|
||||||
while (wcschr(L"\t ", *name))
|
|
||||||
name++;
|
|
||||||
|
|
||||||
tmp = wcschr(name, L':');
|
|
||||||
if (tmp)
|
|
||||||
{
|
|
||||||
const wcstring key(name, tmp - name);
|
|
||||||
|
|
||||||
wcstring val;
|
|
||||||
if (unescape_string(tmp + 1, &val, 0))
|
|
||||||
{
|
|
||||||
env_universal_common_set(key.c_str(), val.c_str(), exportv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
debug(1, PARSE_ERR, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (match(msg, ERASE_STR))
|
|
||||||
{
|
|
||||||
wchar_t *name, *tmp;
|
|
||||||
|
|
||||||
name = msg+wcslen(ERASE_STR);
|
|
||||||
while (wcschr(L"\t ", *name))
|
|
||||||
name++;
|
|
||||||
|
|
||||||
tmp = name;
|
|
||||||
while (iswalnum(*tmp) || *tmp == L'_')
|
|
||||||
tmp++;
|
|
||||||
|
|
||||||
*tmp = 0;
|
|
||||||
|
|
||||||
if (!wcslen(name))
|
|
||||||
{
|
|
||||||
debug(1, PARSE_ERR, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
env_universal_common_remove(name);
|
|
||||||
|
|
||||||
if (callback)
|
|
||||||
{
|
|
||||||
callback(ERASE, name, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (match(msg, BARRIER_STR))
|
|
||||||
{
|
|
||||||
message_t *msg = create_message(BARRIER_REPLY, 0, 0);
|
|
||||||
msg->count = 1;
|
|
||||||
src->unsent.push(msg);
|
|
||||||
try_send_all(src);
|
|
||||||
}
|
|
||||||
else if (match(msg, BARRIER_REPLY_STR))
|
|
||||||
{
|
|
||||||
if (callback)
|
|
||||||
{
|
|
||||||
callback(BARRIER_REPLY, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
debug(1, PARSE_ERR, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Attempt to send the specified message to the specified file descriptor
|
Attempt to send the specified message to the specified file descriptor
|
||||||
|
|
||||||
|
@ -630,7 +473,7 @@ void connection_destroy(connection_t *c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
env_universal_t::env_universal_t()
|
env_universal_t::env_universal_t() : tried_renaming(false)
|
||||||
{
|
{
|
||||||
VOMIT_ON_FAILURE(pthread_mutex_init(&lock, NULL));
|
VOMIT_ON_FAILURE(pthread_mutex_init(&lock, NULL));
|
||||||
}
|
}
|
||||||
|
@ -662,20 +505,33 @@ bool env_universal_t::get_export(const wcstring &name) const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void env_universal_t::set(const wcstring &key, const wcstring &val, bool exportv)
|
|
||||||
|
void env_universal_t::set_internal(const wcstring &key, const wcstring &val, bool exportv)
|
||||||
{
|
{
|
||||||
scoped_lock locker(lock);
|
ASSERT_IS_LOCKED(lock);
|
||||||
var_entry_t *entry = &vars[key];
|
var_entry_t *entry = &vars[key];
|
||||||
entry->val = val;
|
entry->val = val;
|
||||||
entry->exportv = exportv;
|
entry->exportv = exportv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void env_universal_t::remove(const wcstring &key)
|
void env_universal_t::set(const wcstring &key, const wcstring &val, bool exportv)
|
||||||
|
{
|
||||||
|
scoped_lock locker(lock);
|
||||||
|
this->set_internal(key, val, exportv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void env_universal_t::remove_internal(const wcstring &key)
|
||||||
{
|
{
|
||||||
scoped_lock locker(lock);
|
scoped_lock locker(lock);
|
||||||
vars.erase(key);
|
vars.erase(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void env_universal_t::remove(const wcstring &key)
|
||||||
|
{
|
||||||
|
ASSERT_IS_LOCKED(lock);
|
||||||
|
this->remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
wcstring_list_t env_universal_t::get_names(bool show_exported, bool show_unexported) const
|
wcstring_list_t env_universal_t::get_names(bool show_exported, bool show_unexported) const
|
||||||
{
|
{
|
||||||
wcstring_list_t result;
|
wcstring_list_t result;
|
||||||
|
@ -708,6 +564,341 @@ void env_universal_t::enqueue_all(connection_t *c) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool env_universal_t::load_from_path(const wcstring &path)
|
||||||
|
{
|
||||||
|
ASSERT_IS_LOCKED(lock);
|
||||||
|
/* OK to not use CLO_EXEC here because fishd is single threaded */
|
||||||
|
bool result = false;
|
||||||
|
int fd = wopen_cloexec(path, O_RDONLY | O_CLOEXEC, 0600);
|
||||||
|
if (fd >= 0)
|
||||||
|
{
|
||||||
|
/* Success */
|
||||||
|
result = true;
|
||||||
|
connection_t c(fd);
|
||||||
|
/* Read from the file */
|
||||||
|
this->read_message(&c);
|
||||||
|
connection_destroy(&c);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get environment variable value.
|
||||||
|
*/
|
||||||
|
static env_var_t fishd_env_get(const char *key)
|
||||||
|
{
|
||||||
|
const char *env = getenv(key);
|
||||||
|
if (env != NULL)
|
||||||
|
{
|
||||||
|
return env_var_t(str2wcstring(env));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const wcstring wkey = str2wcstring(key);
|
||||||
|
return env_universal_common_get(wkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static wcstring fishd_get_config()
|
||||||
|
{
|
||||||
|
bool done = false;
|
||||||
|
wcstring result;
|
||||||
|
|
||||||
|
env_var_t xdg_dir = fishd_env_get("XDG_CONFIG_HOME");
|
||||||
|
if (! xdg_dir.missing_or_empty())
|
||||||
|
{
|
||||||
|
result = xdg_dir;
|
||||||
|
append_path_component(result, L"/fish");
|
||||||
|
if (!create_directory(result))
|
||||||
|
{
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
env_var_t home = fishd_env_get("HOME");
|
||||||
|
if (! home.missing_or_empty())
|
||||||
|
{
|
||||||
|
result = home;
|
||||||
|
append_path_component(result, L"/.config/fish");
|
||||||
|
if (!create_directory(result))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! done)
|
||||||
|
{
|
||||||
|
/* Bad juju */
|
||||||
|
debug(0, _(L"Unable to create a configuration directory for fish. Your personal settings will not be saved. Please set the $XDG_CONFIG_HOME variable to a directory where the current user has write access."));
|
||||||
|
result.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string get_variables_file_path(const std::string &dir, const std::string &identifier);
|
||||||
|
bool env_universal_t::load()
|
||||||
|
{
|
||||||
|
scoped_lock locker(lock);
|
||||||
|
wcstring wdir = fishd_get_config();
|
||||||
|
const std::string dir = wcs2string(wdir);
|
||||||
|
if (dir.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const std::string machine_id = get_machine_identifier();
|
||||||
|
const std::string machine_id_path = get_variables_file_path(dir, machine_id);
|
||||||
|
|
||||||
|
const wcstring path = str2wcstring(machine_id_path);
|
||||||
|
bool success = load_from_path(path);
|
||||||
|
if (! success && ! tried_renaming && errno == ENOENT)
|
||||||
|
{
|
||||||
|
/* We failed to load, because the file was not found. Older fish used the hostname only. Try *moving* the filename based on the hostname into place; if that succeeds try again. Silently "upgraded." */
|
||||||
|
tried_renaming = true;
|
||||||
|
std::string hostname_id;
|
||||||
|
if (get_hostname_identifier(&hostname_id) && hostname_id != machine_id)
|
||||||
|
{
|
||||||
|
std::string hostname_path = get_variables_file_path(dir, hostname_id);
|
||||||
|
if (0 == rename(hostname_path.c_str(), machine_id_path.c_str()))
|
||||||
|
{
|
||||||
|
/* We renamed - try again */
|
||||||
|
success = load_from_path(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool env_universal_t::save()
|
||||||
|
{
|
||||||
|
/* Writes variables */
|
||||||
|
scoped_lock locker(lock);
|
||||||
|
wcstring wdir = fishd_get_config();
|
||||||
|
const std::string dir = wcs2string(wdir);
|
||||||
|
if (dir.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const std::string machine_id = get_machine_identifier();
|
||||||
|
const std::string machine_id_path = get_variables_file_path(dir, machine_id);
|
||||||
|
|
||||||
|
const wcstring path = str2wcstring(machine_id_path);
|
||||||
|
return save_to_path(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool env_universal_t::save_to_path(const wcstring &path)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void env_universal_t::read_message(connection_t *src)
|
||||||
|
{
|
||||||
|
scoped_lock locker(lock);
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
|
||||||
|
int ib = read_byte(src);
|
||||||
|
char b;
|
||||||
|
|
||||||
|
switch (ib)
|
||||||
|
{
|
||||||
|
case ENV_UNIVERSAL_AGAIN:
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ENV_UNIVERSAL_ERROR:
|
||||||
|
{
|
||||||
|
debug(2, L"Read error on fd %d, set killme flag", src->fd);
|
||||||
|
if (debug_level > 2)
|
||||||
|
wperror(L"read");
|
||||||
|
src->killme = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ENV_UNIVERSAL_EOF:
|
||||||
|
{
|
||||||
|
src->killme = 1;
|
||||||
|
debug(3, L"Fd %d has reached eof, set killme flag", src->fd);
|
||||||
|
if (! src->input.empty())
|
||||||
|
{
|
||||||
|
char c = 0;
|
||||||
|
src->input.push_back(c);
|
||||||
|
debug(1,
|
||||||
|
L"Universal variable connection closed while reading command. Partial command recieved: '%s'",
|
||||||
|
&src->input.at(0));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b = (char)ib;
|
||||||
|
|
||||||
|
if (b == '\n')
|
||||||
|
{
|
||||||
|
wchar_t *msg;
|
||||||
|
|
||||||
|
b = 0;
|
||||||
|
src->input.push_back(b);
|
||||||
|
|
||||||
|
msg = utf2wcs(&src->input.at(0));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Before calling parse_message, we must empty reset
|
||||||
|
everything, since the callback function could
|
||||||
|
potentially call read_message.
|
||||||
|
*/
|
||||||
|
src->input.clear();
|
||||||
|
|
||||||
|
if (msg)
|
||||||
|
{
|
||||||
|
this->parse_message_internal(msg, src);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug(0, _(L"Could not convert message '%s' to wide character string"), &src->input.at(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
free(msg);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
src->input.push_back(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Parse message msg
|
||||||
|
*/
|
||||||
|
void env_universal_t::parse_message_internal(wchar_t *msg, connection_t *src)
|
||||||
|
{
|
||||||
|
ASSERT_IS_LOCKED(lock);
|
||||||
|
|
||||||
|
// debug( 3, L"parse_message( %ls );", msg );
|
||||||
|
|
||||||
|
if (msg[0] == L'#')
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (match(msg, SET_STR) || match(msg, SET_EXPORT_STR))
|
||||||
|
{
|
||||||
|
wchar_t *name, *tmp;
|
||||||
|
bool exportv = match(msg, SET_EXPORT_STR);
|
||||||
|
|
||||||
|
name = msg+(exportv?wcslen(SET_EXPORT_STR):wcslen(SET_STR));
|
||||||
|
while (wcschr(L"\t ", *name))
|
||||||
|
name++;
|
||||||
|
|
||||||
|
tmp = wcschr(name, L':');
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
const wcstring key(name, tmp - name);
|
||||||
|
|
||||||
|
wcstring val;
|
||||||
|
if (unescape_string(tmp + 1, &val, 0))
|
||||||
|
{
|
||||||
|
this->set_internal(key, val, exportv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug(1, PARSE_ERR, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (match(msg, ERASE_STR))
|
||||||
|
{
|
||||||
|
wchar_t *name, *tmp;
|
||||||
|
|
||||||
|
name = msg+wcslen(ERASE_STR);
|
||||||
|
while (wcschr(L"\t ", *name))
|
||||||
|
name++;
|
||||||
|
|
||||||
|
tmp = name;
|
||||||
|
while (iswalnum(*tmp) || *tmp == L'_')
|
||||||
|
tmp++;
|
||||||
|
|
||||||
|
*tmp = 0;
|
||||||
|
|
||||||
|
if (!wcslen(name))
|
||||||
|
{
|
||||||
|
debug(1, PARSE_ERR, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->remove_internal(name);
|
||||||
|
|
||||||
|
#warning We're locked when this is invoked - bad news!
|
||||||
|
if (callback)
|
||||||
|
{
|
||||||
|
callback(ERASE, name, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (match(msg, BARRIER_STR))
|
||||||
|
{
|
||||||
|
message_t *msg = create_message(BARRIER_REPLY, 0, 0);
|
||||||
|
msg->count = 1;
|
||||||
|
src->unsent.push(msg);
|
||||||
|
try_send_all(src);
|
||||||
|
}
|
||||||
|
else if (match(msg, BARRIER_REPLY_STR))
|
||||||
|
{
|
||||||
|
if (callback)
|
||||||
|
{
|
||||||
|
callback(BARRIER_REPLY, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug(1, PARSE_ERR, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static std::string get_variables_file_path(const std::string &dir, const std::string &identifier)
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
name.append(dir);
|
||||||
|
name.append("/");
|
||||||
|
name.append("fishd.");
|
||||||
|
name.append(identifier);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Small not about not editing ~/.fishd manually. Inserted at the top of all .fishd files.
|
||||||
|
*/
|
||||||
|
#define SAVE_MSG "# This file is automatically generated by the fish.\n# Do NOT edit it directly, your changes will be overwritten.\n"
|
||||||
|
|
||||||
|
static bool load_or_save_variables_at_path(bool save, const std::string &path)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
/* OK to not use CLO_EXEC here because fishd is single threaded */
|
||||||
|
int fd = open(path.c_str(), save?(O_CREAT | O_TRUNC | O_WRONLY):O_RDONLY, 0600);
|
||||||
|
if (fd >= 0)
|
||||||
|
{
|
||||||
|
/* Success */
|
||||||
|
result = true;
|
||||||
|
connection_t c(fd);
|
||||||
|
|
||||||
|
if (save)
|
||||||
|
{
|
||||||
|
/* Save to the file */
|
||||||
|
write_loop(c.fd, SAVE_MSG, strlen(SAVE_MSG));
|
||||||
|
enqueue_all(&c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Read from the file */
|
||||||
|
read_message(&c);
|
||||||
|
}
|
||||||
|
|
||||||
|
connection_destroy(&c);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -205,6 +205,15 @@ class env_universal_t
|
||||||
{
|
{
|
||||||
var_table_t vars;
|
var_table_t vars;
|
||||||
mutable pthread_mutex_t lock;
|
mutable pthread_mutex_t lock;
|
||||||
|
bool tried_renaming;
|
||||||
|
bool load_from_path(const wcstring &path);
|
||||||
|
bool save_to_path(const wcstring &path);
|
||||||
|
|
||||||
|
void parse_message_internal(wchar_t *msg, connection_t *src);
|
||||||
|
|
||||||
|
void set_internal(const wcstring &key, const wcstring &val, bool exportv);
|
||||||
|
void remove_internal(const wcstring &name);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
env_universal_t();
|
env_universal_t();
|
||||||
~env_universal_t();
|
~env_universal_t();
|
||||||
|
@ -226,6 +235,15 @@ public:
|
||||||
|
|
||||||
/* Writes variables to the connection */
|
/* Writes variables to the connection */
|
||||||
void enqueue_all(connection_t *c) const;
|
void enqueue_all(connection_t *c) const;
|
||||||
|
|
||||||
|
/** Loads variables at the correct path */
|
||||||
|
bool load();
|
||||||
|
|
||||||
|
/** Writes variables at the correct path */
|
||||||
|
bool save();
|
||||||
|
|
||||||
|
/* Internal use */
|
||||||
|
void read_message(connection_t *src);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string get_machine_identifier();
|
std::string get_machine_identifier();
|
||||||
|
|
|
@ -700,6 +700,7 @@ static std::string get_variables_file_path(const std::string &dir, const std::st
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool load_or_save_variables(bool save)
|
static bool load_or_save_variables(bool save)
|
||||||
{
|
{
|
||||||
const wcstring wdir = fishd_get_config();
|
const wcstring wdir = fishd_get_config();
|
||||||
|
|
Loading…
Reference in a new issue