2005-10-04 15:11:39 +00:00
|
|
|
#ifndef FISH_ENV_UNIVERSAL_COMMON_H
|
|
|
|
#define FISH_ENV_UNIVERSAL_COMMON_H
|
2016-12-26 04:53:59 +00:00
|
|
|
#include "config.h" // IWYU pragma: keep
|
2005-09-20 13:26:39 +00:00
|
|
|
|
2015-07-25 15:14:25 +00:00
|
|
|
#include <pthread.h>
|
2016-04-29 01:55:41 +00:00
|
|
|
#include <stdio.h>
|
2017-02-14 04:37:27 +00:00
|
|
|
|
2016-04-21 06:00:54 +00:00
|
|
|
#include <memory>
|
2017-08-19 20:29:52 +00:00
|
|
|
#include <unordered_set>
|
2015-07-25 15:14:25 +00:00
|
|
|
#include <vector>
|
2016-04-21 06:00:54 +00:00
|
|
|
|
2015-07-25 15:14:25 +00:00
|
|
|
#include "common.h"
|
2014-04-25 23:09:26 +00:00
|
|
|
#include "env.h"
|
2016-04-29 01:55:41 +00:00
|
|
|
#include "wutil.h"
|
|
|
|
|
|
|
|
/// Callback data, reflecting a change in universal variables.
|
|
|
|
struct callback_data_t {
|
2018-10-20 20:16:14 +00:00
|
|
|
// The name of the variable.
|
2014-06-16 00:30:50 +00:00
|
|
|
wcstring key;
|
2016-04-29 01:55:41 +00:00
|
|
|
|
2018-10-20 20:16:14 +00:00
|
|
|
// The value of the variable, or none if it is erased.
|
|
|
|
maybe_t<wcstring> val;
|
|
|
|
|
|
|
|
/// Construct from a key and maybe a value.
|
|
|
|
callback_data_t(wcstring k, maybe_t<wcstring> v) : key(std::move(k)), val(std::move(v)) {}
|
|
|
|
|
|
|
|
/// \return whether this callback represents an erased variable.
|
|
|
|
bool is_erase() const { return !val.has_value(); }
|
2014-06-16 00:30:50 +00:00
|
|
|
};
|
2014-04-29 18:28:00 +00:00
|
|
|
|
2019-06-09 20:48:07 +00:00
|
|
|
typedef std::vector<callback_data_t> callback_data_list_t;
|
2015-07-25 15:14:25 +00:00
|
|
|
|
2018-10-20 21:38:49 +00:00
|
|
|
// List of fish universal variable formats.
|
|
|
|
// This is exposed for testing.
|
|
|
|
enum class uvar_format_t { fish_2_x, fish_3_0, future };
|
|
|
|
|
2018-03-09 21:02:32 +00:00
|
|
|
bool get_hostname_identifier(wcstring &result);
|
2016-04-29 01:55:41 +00:00
|
|
|
/// Class representing universal variables.
|
|
|
|
class env_universal_t {
|
2018-04-02 00:43:12 +00:00
|
|
|
// The table of variables. Note this is sorted; this ensures that the output file is in sorted
|
|
|
|
// order.
|
|
|
|
var_table_t vars;
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
// Keys that have been modified, and need to be written. A value here that is not present in
|
|
|
|
// vars indicates a deleted value.
|
2017-08-19 23:27:24 +00:00
|
|
|
std::unordered_set<wcstring> modified;
|
2016-04-29 01:55:41 +00:00
|
|
|
|
2019-05-31 07:42:27 +00:00
|
|
|
std::string narrow_vars_path;
|
2016-04-29 01:55:41 +00:00
|
|
|
// Path that we save to. If empty, use the default.
|
2019-05-31 07:42:27 +00:00
|
|
|
wcstring explicit_vars_path;
|
|
|
|
|
2019-06-09 20:48:07 +00:00
|
|
|
// A generation count which is incremented every time an exported variable is modified.
|
|
|
|
uint64_t export_generation{1};
|
|
|
|
|
2018-10-21 07:31:30 +00:00
|
|
|
// Whether it's OK to save. This may be set to false if we discover that a future version of
|
|
|
|
// fish wrote the uvars contents.
|
|
|
|
bool ok_to_save{true};
|
|
|
|
|
2018-12-31 02:15:49 +00:00
|
|
|
mutable std::mutex lock;
|
2019-05-31 07:42:27 +00:00
|
|
|
bool load_from_path(const std::string &path, callback_data_list_t &callbacks);
|
2017-07-14 17:45:31 +00:00
|
|
|
bool load_from_path(const wcstring &path, callback_data_list_t &callbacks);
|
|
|
|
void load_from_fd(int fd, callback_data_list_t &callbacks);
|
2016-04-29 01:55:41 +00:00
|
|
|
|
2019-06-09 20:48:07 +00:00
|
|
|
void set_internal(const wcstring &key, const env_var_t &var);
|
2019-11-19 00:54:36 +00:00
|
|
|
bool remove_internal(const wcstring &key);
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
// Functions concerned with saving.
|
2019-05-31 07:42:27 +00:00
|
|
|
bool open_and_acquire_lock(const std::string &path, int *out_fd);
|
2014-04-27 20:34:51 +00:00
|
|
|
bool open_temporary_file(const wcstring &directory, wcstring *out_path, int *out_fd);
|
2014-06-09 19:57:44 +00:00
|
|
|
bool write_to_fd(int fd, const wcstring &path);
|
2014-04-27 20:34:51 +00:00
|
|
|
bool move_new_vars_file_into_place(const wcstring &src, const wcstring &dst);
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
// File id from which we last read.
|
2018-04-02 00:43:12 +00:00
|
|
|
file_id_t last_read_file = kInvalidFileID;
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
// Given a variable table, generate callbacks representing the difference between our vars and
|
2019-06-09 20:48:07 +00:00
|
|
|
// the new vars. Also update our exports generation count as necessary.
|
|
|
|
void generate_callbacks_and_update_exports(const var_table_t &new_vars,
|
|
|
|
callback_data_list_t &callbacks);
|
2016-04-29 01:55:41 +00:00
|
|
|
|
2017-08-09 18:11:58 +00:00
|
|
|
// Given a variable table, copy unmodified values into self. May destructively modify
|
2016-04-29 01:55:41 +00:00
|
|
|
// vars_to_acquire.
|
2017-08-09 18:11:58 +00:00
|
|
|
void acquire_variables(var_table_t &vars_to_acquire);
|
2016-04-29 01:55:41 +00:00
|
|
|
|
2019-11-19 00:54:36 +00:00
|
|
|
static bool populate_1_variable(const wchar_t *input, env_var_t::env_var_flags_t flags,
|
2018-10-21 00:20:49 +00:00
|
|
|
var_table_t *vars, wcstring *storage);
|
|
|
|
|
2018-10-20 21:38:49 +00:00
|
|
|
static void parse_message_2x_internal(const wcstring &msg, var_table_t *vars,
|
|
|
|
wcstring *storage);
|
|
|
|
static void parse_message_30_internal(const wcstring &msg, var_table_t *vars,
|
|
|
|
wcstring *storage);
|
2018-10-21 07:31:30 +00:00
|
|
|
static uvar_format_t read_message_internal(int fd, var_table_t *vars);
|
|
|
|
|
|
|
|
bool save(const wcstring &directory, const wcstring &vars_path);
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
public:
|
2018-02-19 02:39:03 +00:00
|
|
|
explicit env_universal_t(wcstring path);
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
// Get the value of the variable with the specified name.
|
2017-08-28 07:25:41 +00:00
|
|
|
maybe_t<env_var_t> get(const wcstring &name) const;
|
2016-04-29 01:55:41 +00:00
|
|
|
|
2018-10-22 07:49:09 +00:00
|
|
|
// \return flags from the variable with the given name.
|
|
|
|
maybe_t<env_var_t::env_var_flags_t> get_flags(const wcstring &name) const;
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
// Sets a variable.
|
2018-10-22 07:49:09 +00:00
|
|
|
void set(const wcstring &key, env_var_t var);
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
// Removes a variable. Returns true if it was found, false if not.
|
2019-11-19 00:54:36 +00:00
|
|
|
bool remove(const wcstring &key);
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
// Gets variable names.
|
2014-04-25 23:09:26 +00:00
|
|
|
wcstring_list_t get_names(bool show_exported, bool show_unexported) const;
|
2016-04-29 01:55:41 +00:00
|
|
|
|
2019-10-17 10:41:13 +00:00
|
|
|
/// Get a view on the universal variable table.
|
|
|
|
const var_table_t &get_table() const { return vars; }
|
|
|
|
|
2018-04-02 00:43:12 +00:00
|
|
|
/// Loads variables at the correct path, optionally migrating from a legacy path.
|
|
|
|
bool initialize(callback_data_list_t &callbacks);
|
2014-04-26 18:41:34 +00:00
|
|
|
|
2016-04-29 01:55:41 +00:00
|
|
|
/// Reads and writes variables at the correct path. Returns true if modified variables were
|
|
|
|
/// written.
|
2017-07-14 17:45:31 +00:00
|
|
|
bool sync(callback_data_list_t &callbacks);
|
2018-10-20 21:38:49 +00:00
|
|
|
|
|
|
|
/// Populate a variable table \p out_vars from a \p s string.
|
|
|
|
/// This is exposed for testing only.
|
2018-10-21 07:31:30 +00:00
|
|
|
/// \return the format of the file that we read.
|
|
|
|
static uvar_format_t populate_variables(const std::string &s, var_table_t *out_vars);
|
2018-10-20 21:38:49 +00:00
|
|
|
|
|
|
|
/// Guess a file format. Exposed for testing only.
|
|
|
|
static uvar_format_t format_for_contents(const std::string &s);
|
2018-10-20 22:55:46 +00:00
|
|
|
|
|
|
|
/// Serialize a variable list. Exposed for testing only.
|
|
|
|
static std::string serialize_with_vars(const var_table_t &vars);
|
2018-10-21 07:31:30 +00:00
|
|
|
|
|
|
|
/// Exposed for testing only.
|
|
|
|
bool is_ok_to_save() const { return ok_to_save; }
|
2019-06-09 20:48:07 +00:00
|
|
|
|
|
|
|
/// Access the export generation.
|
|
|
|
uint64_t get_export_generation() const;
|
2014-04-25 23:09:26 +00:00
|
|
|
};
|
|
|
|
|
2016-04-29 01:55:41 +00:00
|
|
|
/// The "universal notifier" is an object responsible for broadcasting and receiving universal
|
|
|
|
/// variable change notifications. These notifications do not contain the change, but merely
|
|
|
|
/// indicate that the uvar file has changed. It is up to the uvar subsystem to re-read the file.
|
|
|
|
///
|
|
|
|
/// We support a few notificatins strategies. Not all strategies are supported on all platforms.
|
|
|
|
///
|
|
|
|
/// Notifiers may request polling, and/or provide a file descriptor to be watched for readability in
|
|
|
|
/// select().
|
|
|
|
///
|
|
|
|
/// To request polling, the notifier overrides usec_delay_between_polls() to return a positive
|
|
|
|
/// value. That value will be used as the timeout in select(). When select returns, the loop invokes
|
|
|
|
/// poll(). poll() should return true to indicate that the file may have changed.
|
|
|
|
///
|
|
|
|
/// To provide a file descriptor, the notifier overrides notification_fd() to return a non-negative
|
|
|
|
/// fd. This will be added to the "read" file descriptor list in select(). If the fd is readable,
|
|
|
|
/// notification_fd_became_readable() will be called; that function should be overridden to return
|
|
|
|
/// true if the file may have changed.
|
|
|
|
class universal_notifier_t {
|
|
|
|
public:
|
|
|
|
enum notifier_strategy_t {
|
|
|
|
// Use a value in shared memory. Simple, but requires polling and therefore semi-frequent
|
|
|
|
// wakeups.
|
2014-04-29 21:14:50 +00:00
|
|
|
strategy_shmem_polling,
|
2016-12-26 04:53:59 +00:00
|
|
|
// Strategy that uses notify(3). Simple and efficient, but OS X/macOS only.
|
|
|
|
strategy_notifyd,
|
2016-04-29 01:55:41 +00:00
|
|
|
// Strategy that uses a named pipe. Somewhat complex, but portable and doesn't require
|
|
|
|
// polling most of the time.
|
2014-05-04 22:06:40 +00:00
|
|
|
strategy_named_pipe,
|
2014-04-29 21:14:50 +00:00
|
|
|
};
|
|
|
|
|
2016-04-29 01:55:41 +00:00
|
|
|
protected:
|
2014-04-29 21:14:50 +00:00
|
|
|
universal_notifier_t();
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
// No copying.
|
2014-04-29 21:14:50 +00:00
|
|
|
universal_notifier_t &operator=(const universal_notifier_t &);
|
|
|
|
universal_notifier_t(const universal_notifier_t &x);
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
public:
|
2016-12-26 04:53:59 +00:00
|
|
|
static notifier_strategy_t resolve_default_strategy();
|
2014-04-29 21:14:50 +00:00
|
|
|
virtual ~universal_notifier_t();
|
2016-04-29 01:55:41 +00:00
|
|
|
|
2017-01-22 00:56:45 +00:00
|
|
|
// Factory constructor.
|
2017-01-27 04:00:43 +00:00
|
|
|
static std::unique_ptr<universal_notifier_t> new_notifier_for_strategy(
|
2019-11-19 02:34:50 +00:00
|
|
|
notifier_strategy_t strat, const wchar_t *test_path = nullptr);
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
// Default instance. Other instances are possible for testing.
|
2014-04-29 21:14:50 +00:00
|
|
|
static universal_notifier_t &default_notifier();
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
// Does a fast poll(). Returns true if changed.
|
2014-04-29 21:14:50 +00:00
|
|
|
virtual bool poll();
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
// Triggers a notification.
|
2014-04-29 21:14:50 +00:00
|
|
|
virtual void post_notification();
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
// Recommended delay between polls. A value of 0 means no polling required (so no timeout).
|
2014-04-30 00:03:00 +00:00
|
|
|
virtual unsigned long usec_delay_between_polls() const;
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
// Returns the fd from which to watch for events, or -1 if none.
|
2018-08-09 23:46:11 +00:00
|
|
|
virtual int notification_fd() const;
|
2016-04-29 01:55:41 +00:00
|
|
|
|
|
|
|
// The notification_fd is readable; drain it. Returns true if a notification is considered to
|
|
|
|
// have been posted.
|
2014-05-06 06:33:05 +00:00
|
|
|
virtual bool notification_fd_became_readable(int fd);
|
2014-04-29 21:14:50 +00:00
|
|
|
};
|
|
|
|
|
2018-09-28 15:14:27 +00:00
|
|
|
wcstring get_runtime_path();
|
|
|
|
|
2016-04-29 01:55:41 +00:00
|
|
|
// Environment variable for requesting a particular universal notifier. See
|
|
|
|
// fetch_default_strategy_from_environment for names.
|
2014-05-07 21:22:05 +00:00
|
|
|
#define UNIVERSAL_NOTIFIER_ENV_NAME "fish_universal_notifier"
|
|
|
|
|
2005-09-20 13:26:39 +00:00
|
|
|
#endif
|