aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2013-01-08 02:39:22 -0800
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2013-01-08 02:39:22 -0800
commit552d8f394e7aa11f44fff479a69e93b81a9b2376 (patch)
treecef188b7b140f28bc54b0fd9a3ee39f0cf1b6fd5
parentf8e01628b2352d551d99e7e005653bc1ae20485b (diff)
Make fishd base its variable files on the MAC address instead of hostname
-rw-r--r--builtin_test.cpp8
-rw-r--r--common.cpp5
-rw-r--r--configure.ac1
-rw-r--r--env_universal_common.cpp2
-rw-r--r--fish_tests.cpp18
-rw-r--r--fishd.cpp227
-rw-r--r--osx/config.h3
-rw-r--r--reader.cpp2
8 files changed, 207 insertions, 59 deletions
diff --git a/builtin_test.cpp b/builtin_test.cpp
index 79251252..a130ab99 100644
--- a/builtin_test.cpp
+++ b/builtin_test.cpp
@@ -580,7 +580,7 @@ expression *test_parser::parse_args(const wcstring_list_t &args, wcstring &err)
append_format(err, L"test: unexpected argument at index %lu: '%ls'\n", (unsigned long)result->range.end, args.at(result->range.end).c_str());
}
errored = true;
-
+
delete result;
result = NULL;
}
@@ -802,14 +802,14 @@ int builtin_test(parser_t &parser, wchar_t **argv)
/* The first argument should be the name of the command ('test') */
if (! argv[0])
return BUILTIN_TEST_FAIL;
-
+
/* Whether we are invoked with bracket '[' or not */
const bool is_bracket = ! wcscmp(argv[0], L"[");
size_t argc = 0;
while (argv[argc + 1])
argc++;
-
+
/* If we're bracket, the last argument ought to be ]; we ignore it. Note that argc is the number of arguments after the command name; thus argv[argc] is the last argument. */
if (is_bracket)
{
@@ -825,7 +825,7 @@ int builtin_test(parser_t &parser, wchar_t **argv)
}
}
-
+
/* Collect the arguments into a list */
const wcstring_list_t args(argv + 1, argv + 1 + argc);
diff --git a/common.cpp b/common.cpp
index 352074e7..e3b65e36 100644
--- a/common.cpp
+++ b/common.cpp
@@ -163,9 +163,8 @@ int fgetws2(wcstring *s, FILE *f)
}
/**
- Converts the narrow character string \c in into it's wide
- equivalent, stored in \c out. \c out must have enough space to fit
- the entire string.
+ Converts the narrow character string \c in into its wide
+ equivalent, and return it
The string may contain embedded nulls.
diff --git a/configure.ac b/configure.ac
index 262f5b3b..6ff37652 100644
--- a/configure.ac
+++ b/configure.ac
@@ -720,6 +720,7 @@ AC_CHECK_FUNCS( wcsdup wcsndup wcslen wcscasecmp wcsncasecmp fwprintf )
AC_CHECK_FUNCS( futimes wcwidth wcswidth wcstok fputwc fgetwc )
AC_CHECK_FUNCS( wcstol wcslcat wcslcpy lrand48_r killpg gettext )
AC_CHECK_FUNCS( dcgettext backtrace backtrace_symbols sysconf )
+AC_CHECK_FUNCS( getifaddrs )
#
# The Makefile also needs to know if we have gettext, so it knows if
diff --git a/env_universal_common.cpp b/env_universal_common.cpp
index 0a8bcfaa..4f419bfe 100644
--- a/env_universal_common.cpp
+++ b/env_universal_common.cpp
@@ -276,7 +276,7 @@ start_conversion:
/* FreeBSD has this prototype: size_t iconv (iconv_t, const char **...)
OS X and Linux this one: size_t iconv (iconv_t, char **...)
AFAIK there's no single type that can be passed as both char ** and const char **.
- So we cast the function pointer instead (!)
+ Hence this hack.
*/
nconv = hack_iconv(cd, &in, &in_len, &nout, &out_len);
diff --git a/fish_tests.cpp b/fish_tests.cpp
index 89e77a4f..c35818ad 100644
--- a/fish_tests.cpp
+++ b/fish_tests.cpp
@@ -839,7 +839,7 @@ static bool run_test_test(int expected, const wcstring &str)
copy(istream_iterator<wcstring, wchar_t, std::char_traits<wchar_t> >(iss),
istream_iterator<wstring, wchar_t, std::char_traits<wchar_t> >(),
back_inserter<vector<wcstring> >(lst));
-
+
bool bracket = run_one_test_test(expected, lst, true);
bool nonbracket = run_one_test_test(expected, lst, false);
assert(bracket == nonbracket);
@@ -850,13 +850,13 @@ static void test_test_brackets()
{
// Ensure [ knows it needs a ]
parser_t parser(PARSER_TYPE_GENERAL, true);
-
+
const wchar_t *argv1[] = {L"[", L"foo", NULL};
assert(builtin_test(parser, (wchar_t **)argv1) != 0);
-
+
const wchar_t *argv2[] = {L"[", L"foo", L"]", NULL};
assert(builtin_test(parser, (wchar_t **)argv2) == 0);
-
+
const wchar_t *argv3[] = {L"[", L"foo", L"]", L"bar", NULL};
assert(builtin_test(parser, (wchar_t **)argv3) != 0);
@@ -918,11 +918,11 @@ static void test_test()
/* We didn't properly handle multiple "just strings" either */
assert(run_test_test(0, L"foo"));
assert(run_test_test(0, L"foo -a bar"));
-
+
/* These should be errors */
assert(run_test_test(1, L"foo bar"));
assert(run_test_test(1, L"foo bar baz"));
-
+
/* This crashed */
assert(run_test_test(1, L"1 = 1 -a = 1"));
}
@@ -1029,13 +1029,13 @@ static void test_autosuggestion_combining()
{
say(L"Testing autosuggestion combining");
assert(combine_command_and_autosuggestion(L"alpha", L"alphabeta") == L"alphabeta");
-
+
// when the last token contains no capital letters, we use the case of the autosuggestion
assert(combine_command_and_autosuggestion(L"alpha", L"ALPHABETA") == L"ALPHABETA");
-
+
// when the last token contains capital letters, we use its case
assert(combine_command_and_autosuggestion(L"alPha", L"alphabeTa") == L"alPhabeTa");
-
+
// if autosuggestion is not longer than input, use the input's case
assert(combine_command_and_autosuggestion(L"alpha", L"ALPHAA") == L"ALPHAA");
assert(combine_command_and_autosuggestion(L"alpha", L"ALPHA") == L"alpha");
diff --git a/fishd.cpp b/fishd.cpp
index af5bc306..6cfd02b3 100644
--- a/fishd.cpp
+++ b/fishd.cpp
@@ -52,6 +52,7 @@ time the original barrier request was sent have been received.
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/ioctl.h>
#include <sys/un.h>
#include <pwd.h>
#include <fcntl.h>
@@ -98,6 +99,9 @@ time the original barrier request was sent have been received.
#define MSG_DONTWAIT 0
#endif
+/* Length of a MAC address */
+#define MAC_ADDRESS_MAX_LEN 6
+
/**
Small greeting to show that fishd is running
*/
@@ -109,7 +113,7 @@ time the original barrier request was sent have been received.
#define SAVE_MSG "# This file is automatically generated by the fishd universal variable daemon.\n# Do NOT edit it directly, your changes will be overwritten.\n"
/**
- The name of the save file. The hostname is appended to this.
+ The name of the save file. The machine identifier is appended to this.
*/
#define FILE "fishd."
@@ -223,9 +227,14 @@ static void sprint_rand_digits(char *str, int maxlen)
and ignores errors returned by gettimeofday.
Cast to unsigned so that wrapping occurs on overflow as per ANSI C.
*/
- (void)gettimeofday(&tv, NULL);
- unsigned long long seed = tv.tv_sec + tv.tv_usec * 1000000ULL;
- srand((unsigned int)seed);
+ static bool seeded = false;
+ if (! seeded)
+ {
+ (void)gettimeofday(&tv, NULL);
+ unsigned long long seed = tv.tv_sec + tv.tv_usec * 1000000ULL;
+ srand((unsigned int)seed);
+ seeded = true;
+ }
max = (int)(1 + (maxlen - 1) * (rand() / (RAND_MAX + 1.0)));
for (i = 0; i < max; i++)
{
@@ -235,6 +244,7 @@ static void sprint_rand_digits(char *str, int maxlen)
}
+
/**
Generate a filename unique in an NFS namespace by creating a copy of str and
appending .{hostname}.{pid} to it. If gethostname() fails then a pseudo-
@@ -264,6 +274,118 @@ static std::string gen_unique_nfs_filename(const char *filename)
}
+/* Thanks to Jan Brittenson
+ http://lists.apple.com/archives/xcode-users/2009/May/msg00062.html
+*/
+#ifdef SIOCGIFHWADDR
+
+/* Linux */
+#include <net/if.h>
+static bool get_mac_address(unsigned char macaddr[MAC_ADDRESS_MAX_LEN], const char *interface = "eth0")
+{
+ bool result = false;
+ const int dummy = socket(AF_INET, SOCK_STREAM, 0);
+ if (dummy >= 0)
+ {
+ struct ifreq r;
+ strncpy((char *)r.ifr_name, interface, sizeof r.ifr_name - 1);
+ r.ifr_name[sizeof r.ifr_name - 1] = 0;
+ if (ioctl(dummy, SIOCGIFHWADDR, &r) >= 0)
+ {
+ memcpy(macaddr, r.ifr_hwaddr.sa_data, MAC_ADDRESS_MAX_LEN);
+ result = true;
+ }
+ close(dummy);
+ }
+ return result;
+}
+
+#elif defined(HAVE_GETIFADDRS)
+
+/* OS X and BSD */
+#include <ifaddrs.h>
+#include <net/if_dl.h>
+static bool get_mac_address(unsigned char macaddr[MAC_ADDRESS_MAX_LEN], const char *interface = "en0")
+{
+ // BSD, Mac OS X
+ struct ifaddrs *ifap;
+ bool ok = false;
+
+ if (getifaddrs(&ifap) == 0)
+ {
+ for (const ifaddrs *p = ifap; p; p = p->ifa_next)
+ {
+ if (p->ifa_addr->sa_family == AF_LINK)
+ {
+ if (p->ifa_name && p->ifa_name[0] &&
+ ! strcmp((const char*)p->ifa_name, interface))
+ {
+
+ const sockaddr_dl& sdl = *(sockaddr_dl*)p->ifa_addr;
+
+ size_t alen = sdl.sdl_alen;
+ if (alen > MAC_ADDRESS_MAX_LEN) alen = MAC_ADDRESS_MAX_LEN;
+ memcpy(macaddr, sdl.sdl_data + sdl.sdl_nlen, alen);
+ ok = true;
+ break;
+ }
+ }
+ }
+ freeifaddrs(ifap);
+ }
+ return ok;
+}
+
+#else
+
+/* Unsupported */
+static bool get_mac_address(unsigned char macaddr[MAC_ADDRESS_MAX_LEN])
+{
+ return false;
+}
+
+#endif
+
+/* Function to get an identifier based on the hostname */
+static bool get_hostname_identifier(std::string *result)
+{
+ bool success = false;
+ char hostname[HOSTNAME_LEN + 1] = {};
+ if (gethostname(hostname, HOSTNAME_LEN) == 0)
+ {
+ result->assign(hostname);
+ success = true;
+ }
+ return success;
+}
+
+/* Get a sort of unique machine identifier. Prefer the MAC address; if that fails, fall back to the hostname; if that fails, pick something. */
+static std::string get_machine_identifier(void)
+{
+ std::string result;
+ unsigned char mac_addr[MAC_ADDRESS_MAX_LEN] = {};
+ if (get_mac_address(mac_addr))
+ {
+ result.reserve(2 * MAC_ADDRESS_MAX_LEN);
+ for (size_t i=0; i < MAC_ADDRESS_MAX_LEN; i++)
+ {
+ char buff[3];
+ snprintf(buff, sizeof buff, "%02x", mac_addr[i]);
+ result.append(buff);
+ }
+ }
+ else if (get_hostname_identifier(&result))
+ {
+ /* Hooray */
+ }
+ else
+ {
+ /* Fallback */
+ result.assign("nohost");
+ }
+ return result;
+}
+
/**
The number of milliseconds to wait between polls when attempting to acquire
a lockfile
@@ -661,53 +783,76 @@ static wcstring fishd_get_config()
/**
Load or save all variables
*/
-static void load_or_save(int save)
+static bool load_or_save_variables_at_path(bool save, const std::string &path)
{
- const wcstring wdir = fishd_get_config();
- char hostname[HOSTNAME_LEN];
- connection_t c;
- int fd;
-
- if (wdir.empty())
- return;
-
- std::string dir = wcs2string(wdir);
-
- gethostname(hostname, HOSTNAME_LEN);
-
- std::string name;
- name.append(dir);
- name.append("/");
- name.append(FILE);
- name.append(hostname);
+ bool result = false;
debug(4, L"Open file for %s: '%s'",
save?"saving":"loading",
- name.c_str());
+ path.c_str());
/* OK to not use CLO_EXEC here because fishd is single threaded */
- fd = open(name.c_str(), save?(O_CREAT | O_TRUNC | O_WRONLY):O_RDONLY, 0600);
-
- if (fd == -1)
+ int fd = open(path.c_str(), save?(O_CREAT | O_TRUNC | O_WRONLY):O_RDONLY, 0600);
+ if (fd >= 0)
{
- debug(1, L"Could not open load/save file. No previous saves?");
- wperror(L"open");
- return;
+ /* Success */
+ result = true;
+ connection_t c = {};
+ connection_init(&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);
}
- debug(4, L"File open on fd %d", c.fd);
+ return result;
+}
- connection_init(&c, fd);
- if (save)
- {
+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(FILE);
+ name.append(identifier);
+ return name;
+}
- write_loop(c.fd, SAVE_MSG, strlen(SAVE_MSG));
- enqueue_all(&c);
+static bool load_or_save_variables(bool save)
+{
+ const 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);
+ bool success = load_or_save_variables_at_path(save, machine_id_path);
+ if (! success && ! save && 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." */
+ 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_or_save_variables_at_path(save, machine_id_path);
+ }
+ }
}
- else
- read_message(&c);
-
- connection_destroy(&c);
+ return success;
}
/**
@@ -715,7 +860,7 @@ static void load_or_save(int save)
*/
static void load()
{
- load_or_save(0);
+ load_or_save_variables(false /* load, not save */);
}
/**
@@ -723,7 +868,7 @@ static void load()
*/
static void save()
{
- load_or_save(1);
+ load_or_save_variables(true /* save, not load */);
}
/**
diff --git a/osx/config.h b/osx/config.h
index a72a8825..7206cb38 100644
--- a/osx/config.h
+++ b/osx/config.h
@@ -34,6 +34,9 @@
/* Define to 1 if you have the `fwprintf' function. */
#define HAVE_FWPRINTF 1
+/* Define to 1 if you have the `getifaddrs' function. */
+#define HAVE_GETIFADDRS 1
+
/* Define to 1 if you have the <getopt.h> header file. */
#define HAVE_GETOPT_H 1
diff --git a/reader.cpp b/reader.cpp
index 8b18287e..3a91861a 100644
--- a/reader.cpp
+++ b/reader.cpp
@@ -509,7 +509,7 @@ static void reader_repaint()
// Combine the command and autosuggestion into one string
wcstring full_line = combine_command_and_autosuggestion(data->command_line, data->autosuggestion);
-
+
size_t len = full_line.size();
if (len < 1)
len = 1;