⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 io.c

📁 xen 3.2.2 源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  Copyright (C) International Business Machines  Corp., 2005 *  Author(s): Anthony Liguori <aliguori@us.ibm.com> * *  Xen Console Daemon * *  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; under version 2 of the License. *  *  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, write to the Free Software *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#define _GNU_SOURCE#include "utils.h"#include "io.h"#include <xs.h>#include <xen/io/console.h>#include <xenctrl.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <sys/select.h>#include <fcntl.h>#include <unistd.h>#include <termios.h>#include <stdarg.h>#include <sys/mman.h>#include <sys/time.h>#include <assert.h>#if defined(__NetBSD__) || defined(__OpenBSD__)#include <util.h>#elif defined(__linux__) || defined(__Linux__)#include <pty.h>#endif#if defined(__sun__)#include <stropts.h>#endif#define MAX(a, b) (((a) > (b)) ? (a) : (b))#define MIN(a, b) (((a) < (b)) ? (a) : (b))/* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */#define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)/* How many events are allowed in each time period */#define RATE_LIMIT_ALLOWANCE 30/* Duration of each time period in ms */#define RATE_LIMIT_PERIOD 200extern int log_reload;extern int log_guest;extern int log_hv;extern int log_time_hv;extern int log_time_guest;extern char *log_dir;static int log_time_hv_needts = 1;static int log_time_guest_needts = 1;static int log_hv_fd = -1;static evtchn_port_or_error_t log_hv_evtchn = -1;static int xc_handle = -1;static int xce_handle = -1;struct buffer {	char *data;	size_t consumed;	size_t size;	size_t capacity;	size_t max_capacity;};struct domain {	int domid;	int master_fd;	int slave_fd;	int log_fd;	bool is_dead;	struct buffer buffer;	struct domain *next;	char *conspath;	char *serialpath;	int use_consolepath;	int ring_ref;	evtchn_port_or_error_t local_port;	evtchn_port_or_error_t remote_port;	int xce_handle;	struct xencons_interface *interface;	int event_count;	long long next_period;};static struct domain *dom_head;static int write_all(int fd, const char* buf, size_t len){	while (len) {		ssize_t ret = write(fd, buf, len);		if (ret == -1 && errno == EINTR)			continue;		if (ret <= 0)			return -1;		len -= ret;		buf += ret;	}	return 0;}static int write_with_timestamp(int fd, const char *data, size_t sz,				int *needts){	char ts[32];	time_t now = time(NULL);	const struct tm *tmnow = localtime(&now);	size_t tslen = strftime(ts, sizeof(ts), "[%Y-%m-%d %H:%M:%S] ", tmnow);	const char *last_byte = data + sz - 1;	while (data <= last_byte) {		const char *nl = memchr(data, '\n', sz);		int found_nl = (nl != NULL);		if (!found_nl)			nl = last_byte;		if ((*needts && write_all(fd, ts, tslen))		    || write_all(fd, data, nl + 1 - data))			return -1;		*needts = found_nl;		data = nl + 1;		if (found_nl) {			// If we printed a newline, strip all \r following it			while (data <= last_byte && *data == '\r')				data++;		}	}	return 0;}static void buffer_append(struct domain *dom){	struct buffer *buffer = &dom->buffer;	XENCONS_RING_IDX cons, prod, size;	struct xencons_interface *intf = dom->interface;	cons = intf->out_cons;	prod = intf->out_prod;	mb();	size = prod - cons;	if ((size == 0) || (size > sizeof(intf->out)))		return;	if ((buffer->capacity - buffer->size) < size) {		buffer->capacity += (size + 1024);		buffer->data = realloc(buffer->data, buffer->capacity);		if (buffer->data == NULL) {			dolog(LOG_ERR, "Memory allocation failed");			exit(ENOMEM);		}	}	while (cons != prod)		buffer->data[buffer->size++] = intf->out[			MASK_XENCONS_IDX(cons++, intf->out)];	mb();	intf->out_cons = cons;	xc_evtchn_notify(dom->xce_handle, dom->local_port);	/* Get the data to the logfile as early as possible because if	 * no one is listening on the console pty then it will fill up	 * and handle_tty_write will stop being called.	 */	if (dom->log_fd != -1) {		int logret;		if (log_time_guest) {			logret = write_with_timestamp(				dom->log_fd,				buffer->data + buffer->size - size,				size, &log_time_guest_needts);		} else {			logret = write_all(				dom->log_fd,				buffer->data + buffer->size - size,				size);		}		if (logret < 0)			dolog(LOG_ERR, "Write to log failed "			      "on domain %d: %d (%s)\n",			      dom->domid, errno, strerror(errno));	}	if (buffer->max_capacity &&	    buffer->size > buffer->max_capacity) {		/* Discard the middle of the data. */		size_t over = buffer->size - buffer->max_capacity;		char *maxpos = buffer->data + buffer->max_capacity;		memmove(maxpos - over, maxpos, over);		buffer->data = realloc(buffer->data, buffer->max_capacity);		buffer->size = buffer->capacity = buffer->max_capacity;		if (buffer->consumed > buffer->max_capacity - over)			buffer->consumed = buffer->max_capacity - over;	}}static bool buffer_empty(struct buffer *buffer){	return buffer->size == 0;}static void buffer_advance(struct buffer *buffer, size_t len){	buffer->consumed += len;	if (buffer->consumed == buffer->size) {		buffer->consumed = 0;		buffer->size = 0;	}}static bool domain_is_valid(int domid){	bool ret;	xc_dominfo_t info;	ret = (xc_domain_getinfo(xc, domid, 1, &info) == 1 &&	       info.domid == domid);			return ret;}static int create_hv_log(void){	char logfile[PATH_MAX];	int fd;	snprintf(logfile, PATH_MAX-1, "%s/hypervisor.log", log_dir);	logfile[PATH_MAX-1] = '\0';	fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644);	if (fd == -1)		dolog(LOG_ERR, "Failed to open log %s: %d (%s)",		      logfile, errno, strerror(errno));	if (fd != -1 && log_time_hv) {		if (write_with_timestamp(fd, "Logfile Opened",					 strlen("Logfile Opened"),					 &log_time_hv_needts) < 0) {			dolog(LOG_ERR, "Failed to log opening timestamp "				       "in %s: %d (%s)", logfile, errno,				       strerror(errno));			return -1;		}	}	return fd;}static int create_domain_log(struct domain *dom){	char logfile[PATH_MAX];	char *namepath, *data, *s;	int fd;	unsigned int len;	namepath = xs_get_domain_path(xs, dom->domid);	s = realloc(namepath, strlen(namepath) + 6);	if (s == NULL) {		free(namepath);		return -1;	}	namepath = s;	strcat(namepath, "/name");	data = xs_read(xs, XBT_NULL, namepath, &len);	if (!data)		return -1;	if (!len) {		free(data);		return -1;	}	snprintf(logfile, PATH_MAX-1, "%s/guest-%s.log", log_dir, data);	free(data);	logfile[PATH_MAX-1] = '\0';	fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644);	if (fd == -1)		dolog(LOG_ERR, "Failed to open log %s: %d (%s)",		      logfile, errno, strerror(errno));	if (fd != -1 && log_time_guest) {		if (write_with_timestamp(fd, "Logfile Opened",					 strlen("Logfile Opened"),					 &log_time_guest_needts) < 0) {			dolog(LOG_ERR, "Failed to log opening timestamp "				       "in %s: %d (%s)", logfile, errno,				       strerror(errno));			return -1;		}	}	return fd;}static void domain_close_tty(struct domain *dom){	if (dom->master_fd != -1) {		close(dom->master_fd);		dom->master_fd = -1;	}	if (dom->slave_fd != -1) {		close(dom->slave_fd);		dom->slave_fd = -1;	}}#ifdef __sun__static int openpty(int *amaster, int *aslave, char *name,		   struct termios *termp, struct winsize *winp){	const char *slave;	int mfd = -1, sfd = -1;	*amaster = *aslave = -1;	mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);	if (mfd < 0)		goto err;	if (grantpt(mfd) == -1 || unlockpt(mfd) == -1)		goto err;	if ((slave = ptsname(mfd)) == NULL)		goto err;	if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1)		goto err;	if (ioctl(sfd, I_PUSH, "ptem") == -1)		goto err;	if (amaster)		*amaster = mfd;	if (aslave)		*aslave = sfd;	if (winp)		ioctl(sfd, TIOCSWINSZ, winp);	if (termp)		tcsetattr(sfd, TCSAFLUSH, termp);	assert(name == NULL);	return 0;err:	if (sfd != -1)		close(sfd);	close(mfd);	return -1;}void cfmakeraw(struct termios *termios_p){	termios_p->c_iflag &=	    ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);	termios_p->c_oflag &= ~OPOST;	termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);	termios_p->c_cflag &= ~(CSIZE|PARENB);	termios_p->c_cflag |= CS8;	termios_p->c_cc[VMIN] = 0;	termios_p->c_cc[VTIME] = 0;}#endif /* __sun__ */static int domain_create_tty(struct domain *dom){	const char *slave;	char *path;	int err;	bool success;	char *data;	unsigned int len;	struct termios term;	assert(dom->slave_fd == -1);	assert(dom->master_fd == -1);	cfmakeraw(&term);	if (openpty(&dom->master_fd, &dom->slave_fd, NULL, &term, NULL) < 0) {		err = errno;		dolog(LOG_ERR, "Failed to create tty for domain-%d "		      "(errno = %i, %s)",		      dom->domid, err, strerror(err));		return 0;	}	if ((slave = ptsname(dom->master_fd)) == NULL) {		err = errno;		dolog(LOG_ERR, "Failed to get slave name for domain-%d "		      "(errno = %i, %s)",		      dom->domid, err, strerror(err));		goto out;	}	if (dom->use_consolepath) {		success = asprintf(&path, "%s/limit", dom->conspath) !=			-1;		if (!success)			goto out;		data = xs_read(xs, XBT_NULL, path, &len);		if (data) {			dom->buffer.max_capacity = strtoul(data, 0, 0);			free(data);		}		free(path);	}	success = asprintf(&path, "%s/limit", dom->serialpath) != -1;	if (!success)		goto out;	data = xs_read(xs, XBT_NULL, path, &len);	if (data) {		dom->buffer.max_capacity = strtoul(data, 0, 0);		free(data);	}	free(path);	success = asprintf(&path, "%s/tty", dom->serialpath) != -1;	if (!success)		goto out;	success = xs_write(xs, XBT_NULL, path, slave, strlen(slave));	free(path);	if (!success)		goto out;	if (dom->use_consolepath) {		success = (asprintf(&path, "%s/tty", dom->conspath) != -1);		if (!success)			goto out;		success = xs_write(xs, XBT_NULL, path, slave, strlen(slave));		free(path);		if (!success)			goto out;	}	if (fcntl(dom->master_fd, F_SETFL, O_NONBLOCK) == -1)		goto out;	return 1;out:	domain_close_tty(dom);	return 0;} /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */int xs_gather(struct xs_handle *xs, const char *dir, ...){	va_list ap;	const char *name;	char *path;	int ret = 0;	va_start(ap, dir);	while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {		const char *fmt = va_arg(ap, char *);		void *result = va_arg(ap, void *);		char *p;		if (asprintf(&path, "%s/%s", dir, name) == -1) {			ret = ENOMEM;			break;		}		p = xs_read(xs, XBT_NULL, path, NULL);		free(path);		if (p == NULL) {			ret = ENOENT;			break;		}		if (fmt) {			if (sscanf(p, fmt, result) == 0)				ret = EINVAL;			free(p);		} else			*(char **)result = p;	}	va_end(ap);	return ret;}static int domain_create_ring(struct domain *dom){	int err, remote_port, ring_ref, rc;	char *type, path[PATH_MAX];	err = xs_gather(xs, dom->serialpath,			"ring-ref", "%u", &ring_ref,			"port", "%i", &remote_port,			NULL);	if (err) {		err = xs_gather(xs, dom->conspath,				"ring-ref", "%u", &ring_ref,				"port", "%i", &remote_port,				NULL);		if (err)			goto out;		dom->use_consolepath = 1;	} else		dom->use_consolepath = 0;	sprintf(path, "%s/type", dom->use_consolepath ? dom->conspath: dom->serialpath);	type = xs_read(xs, XBT_NULL, path, NULL);	if (type && strcmp(type, "xenconsoled") != 0) {		free(type);		return 0;	}	free(type);	if ((ring_ref == dom->ring_ref) && (remote_port == dom->remote_port))		goto out;	if (ring_ref != dom->ring_ref) {		if (dom->interface != NULL)			munmap(dom->interface, getpagesize());		dom->interface = xc_map_foreign_range(			xc, dom->domid, getpagesize(),			PROT_READ|PROT_WRITE,			(unsigned long)ring_ref);		if (dom->interface == NULL) {			err = EINVAL;			goto out;		}		dom->ring_ref = ring_ref;	}	dom->local_port = -1;	dom->remote_port = -1;	if (dom->xce_handle != -1)		xc_evtchn_close(dom->xce_handle);	/* Opening evtchn independently for each console is a bit	 * wasteful, but that's how the code is structured... */	dom->xce_handle = xc_evtchn_open();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -