mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
The dom0_domid variable is misnamed and conflates purposes. If we have xenstored running in a Linux domain that is not dom0, this variable controls the lookup of /proc/xen/xsd_kva and the event channel. Rename to store_domid to better show its purpose. One implication of this change is that the xenstore domain is not privileged by virtue of considering store_domid as privileged. domain_is_unprivileged() removes the dom0_domid/store_domid check, so xenstore domain is no longer considered privileged. onearg_domain() is updated to return EINVAL for store_domid or priv_domid to maintain the ability to call XS_RESUME. xenbus_master_domid() is removed with store_domid being used instead. Add a description of the -m/--master-domid options while doing this. Signed-off-by: Jason Andryuk <jason.andryuk@amd.com> Reviewed-by: Juergen Gross <jgross@suse.com>
439 lines
8.7 KiB
C
439 lines
8.7 KiB
C
/*
|
|
Simple prototype Xen Store Daemon providing simple tree-like database.
|
|
Copyright (C) 2005 Rusty Russell IBM Corporation
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <syslog.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#if defined(HAVE_SYSTEMD)
|
|
#include <xen-sd-notify.h>
|
|
#endif
|
|
#include <xen-tools/xenstore-common.h>
|
|
|
|
#include "utils.h"
|
|
#include "core.h"
|
|
#include "osdep.h"
|
|
#include "talloc.h"
|
|
|
|
static int reopen_log_pipe0_pollfd_idx = -1;
|
|
static int reopen_log_pipe[2];
|
|
|
|
static int sock_pollfd_idx = -1;
|
|
static int sock = -1;
|
|
|
|
static void write_pidfile(const char *pidfile)
|
|
{
|
|
char buf[100];
|
|
int len;
|
|
int fd;
|
|
|
|
fd = open(pidfile, O_RDWR | O_CREAT, 0600);
|
|
if (fd == -1)
|
|
barf_perror("Opening pid file %s", pidfile);
|
|
|
|
/* We exit silently if daemon already running. */
|
|
if (lockf(fd, F_TLOCK, 0) == -1)
|
|
exit(0);
|
|
|
|
len = snprintf(buf, sizeof(buf), "%ld\n", (long)getpid());
|
|
if (write(fd, buf, len) != len)
|
|
barf_perror("Writing pid file %s", pidfile);
|
|
|
|
close(fd);
|
|
}
|
|
|
|
/* Stevens. */
|
|
static void daemonize(void)
|
|
{
|
|
pid_t pid;
|
|
|
|
/* Separate from our parent via fork, so init inherits us. */
|
|
if ((pid = fork()) < 0)
|
|
barf_perror("Failed to fork daemon");
|
|
if (pid != 0)
|
|
exit(0);
|
|
|
|
/* Session leader so ^C doesn't whack us. */
|
|
setsid();
|
|
|
|
/* Let session leader exit so child cannot regain CTTY */
|
|
if ((pid = fork()) < 0)
|
|
barf_perror("Failed to fork daemon");
|
|
if (pid != 0)
|
|
exit(0);
|
|
|
|
/* Move off any mount points we might be in. */
|
|
if (chdir("/") == -1)
|
|
barf_perror("Failed to chdir");
|
|
|
|
/* Discard our parent's old-fashioned umask prejudices. */
|
|
umask(0);
|
|
}
|
|
|
|
/*
|
|
* Signal handler for SIGHUP, which requests that the trace log is reopened
|
|
* (in the main loop). A single byte is written to reopen_log_pipe, to awaken
|
|
* the poll() in the main loop.
|
|
*/
|
|
static void trigger_reopen_log(int signal __attribute__((unused)))
|
|
{
|
|
char c = 'A';
|
|
int dummy;
|
|
|
|
dummy = write(reopen_log_pipe[1], &c, 1);
|
|
}
|
|
|
|
void finish_daemonize(void)
|
|
{
|
|
int devnull = open("/dev/null", O_RDWR);
|
|
if (devnull == -1)
|
|
barf_perror("Could not open /dev/null\n");
|
|
dup2(devnull, STDIN_FILENO);
|
|
dup2(devnull, STDOUT_FILENO);
|
|
dup2(devnull, STDERR_FILENO);
|
|
close(devnull);
|
|
}
|
|
|
|
static void init_pipe(void)
|
|
{
|
|
int flags;
|
|
unsigned int i;
|
|
|
|
if (pipe(reopen_log_pipe)) {
|
|
barf_perror("pipe");
|
|
}
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
flags = fcntl(reopen_log_pipe[i], F_GETFD);
|
|
if (flags < 0)
|
|
barf_perror("pipe get flags");
|
|
flags |= FD_CLOEXEC;
|
|
if (fcntl(reopen_log_pipe[i], F_SETFD, flags) < 0)
|
|
barf_perror("pipe set flags");
|
|
}
|
|
}
|
|
|
|
void unmap_xenbus(void *interface)
|
|
{
|
|
munmap(interface, getpagesize());
|
|
}
|
|
|
|
static evtchn_port_t get_xenbus_evtchn(void)
|
|
{
|
|
int fd;
|
|
int rc;
|
|
evtchn_port_t port;
|
|
char str[20];
|
|
|
|
fd = open(XENSTORED_PORT_DEV, O_RDONLY);
|
|
if (fd == -1)
|
|
return -1;
|
|
|
|
rc = read(fd, str, sizeof(str) - 1);
|
|
if (rc == -1)
|
|
{
|
|
int err = errno;
|
|
close(fd);
|
|
errno = err;
|
|
return -1;
|
|
}
|
|
|
|
str[rc] = '\0';
|
|
port = strtoul(str, NULL, 0);
|
|
|
|
close(fd);
|
|
return port;
|
|
}
|
|
|
|
/*
|
|
* dom0 xenstored uses get_xenbus_evtchn() to lookup with XENSTORED_PORT_DEV.
|
|
*
|
|
* Any other existing domains from dom0less/Hyperlaunch will have
|
|
* the event channel in the xenstore page, so lookup here isn't necessary.
|
|
*/
|
|
evtchn_port_t get_domain_evtchn(unsigned int domid)
|
|
{
|
|
if (domid == store_domid)
|
|
return get_xenbus_evtchn();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void *xenbus_map(void)
|
|
{
|
|
int fd;
|
|
void *addr;
|
|
|
|
fd = open(XENSTORED_KVA_DEV, O_RDWR);
|
|
if (fd == -1)
|
|
return NULL;
|
|
|
|
addr = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE,
|
|
MAP_SHARED, fd, 0);
|
|
|
|
if (addr == MAP_FAILED)
|
|
addr = NULL;
|
|
|
|
close(fd);
|
|
|
|
return addr;
|
|
}
|
|
|
|
static int writefd(struct connection *conn, const void *data, unsigned int len)
|
|
{
|
|
int rc;
|
|
|
|
while ((rc = write(conn->fd, data, len)) < 0) {
|
|
if (errno == EAGAIN) {
|
|
rc = 0;
|
|
break;
|
|
}
|
|
if (errno != EINTR)
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int readfd(struct connection *conn, void *data, unsigned int len)
|
|
{
|
|
int rc;
|
|
|
|
while ((rc = read(conn->fd, data, len)) < 0) {
|
|
if (errno == EAGAIN) {
|
|
rc = 0;
|
|
break;
|
|
}
|
|
if (errno != EINTR)
|
|
break;
|
|
}
|
|
|
|
/* Reading zero length means we're done with this connection. */
|
|
if ((rc == 0) && (len != 0)) {
|
|
errno = EBADF;
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static bool socket_can_process(struct connection *conn, int mask)
|
|
{
|
|
if (conn->pollfd_idx == -1)
|
|
return false;
|
|
|
|
if (poll_fds[conn->pollfd_idx].revents & ~(POLLIN | POLLOUT)) {
|
|
talloc_free(conn);
|
|
return false;
|
|
}
|
|
|
|
return (poll_fds[conn->pollfd_idx].revents & mask);
|
|
}
|
|
|
|
static bool socket_can_write(struct connection *conn)
|
|
{
|
|
return socket_can_process(conn, POLLOUT);
|
|
}
|
|
|
|
static bool socket_can_read(struct connection *conn)
|
|
{
|
|
return socket_can_process(conn, POLLIN);
|
|
}
|
|
|
|
static const struct interface_funcs socket_funcs = {
|
|
.write = writefd,
|
|
.read = readfd,
|
|
.can_write = socket_can_write,
|
|
.can_read = socket_can_read,
|
|
};
|
|
|
|
static void accept_connection(int sock)
|
|
{
|
|
int fd;
|
|
struct connection *conn;
|
|
|
|
fd = accept(sock, NULL, NULL);
|
|
if (fd < 0)
|
|
return;
|
|
|
|
conn = new_connection(&socket_funcs);
|
|
if (conn) {
|
|
conn->fd = fd;
|
|
conn->id = store_domid;
|
|
} else
|
|
close(fd);
|
|
}
|
|
|
|
static void destroy_fds(void)
|
|
{
|
|
if (sock >= 0)
|
|
close(sock);
|
|
}
|
|
|
|
static void init_sockets(void)
|
|
{
|
|
struct sockaddr_un addr;
|
|
const char *soc_str = xenstore_daemon_path();
|
|
|
|
if (!soc_str)
|
|
barf_perror("Failed to obtain xs domain socket");
|
|
|
|
/* Create sockets for them to listen to. */
|
|
atexit(destroy_fds);
|
|
sock = socket(PF_UNIX, SOCK_STREAM, 0);
|
|
if (sock < 0)
|
|
barf_perror("Could not create socket");
|
|
|
|
/* FIXME: Be more sophisticated, don't mug running daemon. */
|
|
unlink(soc_str);
|
|
|
|
addr.sun_family = AF_UNIX;
|
|
|
|
if (strlen(soc_str) >= sizeof(addr.sun_path))
|
|
barf_perror("socket string '%s' too long", soc_str);
|
|
strcpy(addr.sun_path, soc_str);
|
|
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0)
|
|
barf_perror("Could not bind socket to %s", soc_str);
|
|
|
|
if (chmod(soc_str, 0600) != 0)
|
|
barf_perror("Could not chmod sockets");
|
|
|
|
if (listen(sock, 1) != 0)
|
|
barf_perror("Could not listen on sockets");
|
|
}
|
|
|
|
|
|
struct connection *add_socket_connection(int fd)
|
|
{
|
|
struct connection *conn;
|
|
|
|
conn = new_connection(&socket_funcs);
|
|
if (!conn)
|
|
barf("error restoring connection");
|
|
conn->fd = fd;
|
|
|
|
return conn;
|
|
}
|
|
|
|
void early_init(bool live_update, bool dofork, const char *pidfile)
|
|
{
|
|
reopen_log();
|
|
|
|
/* Make sure xenstored directories exist. */
|
|
/* Errors ignored here, will be reported when we open files */
|
|
mkdir(xenstore_daemon_rundir(), 0755);
|
|
mkdir(XENSTORE_LIB_DIR, 0755);
|
|
|
|
if (dofork) {
|
|
openlog("xenstored", 0, LOG_DAEMON);
|
|
if (!live_update)
|
|
daemonize();
|
|
}
|
|
|
|
if (pidfile)
|
|
write_pidfile(pidfile);
|
|
|
|
/* Don't kill us with SIGPIPE. */
|
|
signal(SIGPIPE, SIG_IGN);
|
|
signal(SIGHUP, trigger_reopen_log);
|
|
|
|
if (!live_update)
|
|
init_sockets();
|
|
|
|
init_pipe();
|
|
}
|
|
|
|
void set_special_fds(void)
|
|
{
|
|
if (reopen_log_pipe[0] != -1)
|
|
reopen_log_pipe0_pollfd_idx =
|
|
set_fd(reopen_log_pipe[0], POLLIN|POLLPRI);
|
|
|
|
if (sock != -1)
|
|
sock_pollfd_idx = set_fd(sock, POLLIN|POLLPRI);
|
|
}
|
|
|
|
void handle_special_fds(void)
|
|
{
|
|
if (reopen_log_pipe0_pollfd_idx != -1) {
|
|
if (poll_fds[reopen_log_pipe0_pollfd_idx].revents & ~POLLIN) {
|
|
close(reopen_log_pipe[0]);
|
|
close(reopen_log_pipe[1]);
|
|
init_pipe();
|
|
} else if (poll_fds[reopen_log_pipe0_pollfd_idx].revents &
|
|
POLLIN) {
|
|
char c;
|
|
|
|
if (read(reopen_log_pipe[0], &c, 1) != 1)
|
|
barf_perror("read failed");
|
|
reopen_log();
|
|
}
|
|
reopen_log_pipe0_pollfd_idx = -1;
|
|
}
|
|
|
|
if (sock_pollfd_idx != -1) {
|
|
if (poll_fds[sock_pollfd_idx].revents & ~POLLIN) {
|
|
barf_perror("sock poll failed");
|
|
} else if (poll_fds[sock_pollfd_idx].revents & POLLIN) {
|
|
accept_connection(sock);
|
|
sock_pollfd_idx = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void late_init(bool live_update)
|
|
{
|
|
#if defined(HAVE_SYSTEMD)
|
|
if (!live_update) {
|
|
sd_notify(1, "READY=1");
|
|
fprintf(stderr, "xenstored is ready\n");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int get_socket_fd(void)
|
|
{
|
|
return sock;
|
|
}
|
|
|
|
void set_socket_fd(int fd)
|
|
{
|
|
sock = fd;
|
|
}
|
|
|
|
xenevtchn_handle *evtchn_fdopen(int fd)
|
|
{
|
|
return xenevtchn_fdopen(NULL, fd, 0);
|
|
}
|
|
|
|
int evtchn_rebind(int port)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
const char *xenstore_rundir(void)
|
|
{
|
|
return xenstore_daemon_rundir();
|
|
}
|