|
|
|
@ -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.
|
|
|
|
|
*/
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
debug(4, L"File open on fd %d", c.fd);
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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 */);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|