From 89144534ebea806704e05769942bd3bebf23d8e4 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 24 Jun 2010 15:05:16 -0600 Subject: [PATCH] phyp: reduce scope of driver functions Several phyp functions are not namespace clean, and had no reason to be exported since no one outside the phyp driver needed to use them. Rather than do lots of forward declarations, I was able to topologically sort the file. So, this patch looks huge, but is really just a matter of marking things static and dealing with the compiler fallout. * src/phyp/phyp_driver.h (PHYP_DRIVER_H): Add include guard. (phypCheckSPFreeSapce): Delete unused declaration. (phypGetSystemType, phypGetVIOSPartitionID, phypCapsInit) (phypBuildLpar, phypUUIDTable_WriteFile, phypUUIDTable_ReadFile) (phypUUIDTable_AddLpar, phypUUIDTable_RemLpar, phypUUIDTable_Pull) (phypUUIDTable_Push, phypUUIDTable_Init, phypUUIDTable_Free) (escape_specialcharacters, waitsocket, phypGetLparUUID) (phypGetLparMem, phypGetLparCPU, phypGetLparCPUGeneric) (phypGetRemoteSlot, phypGetBackingDevice, phypDiskType) (openSSHSession): Move declarations to phyp_driver.c and make static. * src/phyp/phyp_driver.c: Rearrange file contents to provide topological sorting of newly-static funtions (no semantic changes other than reduced scope). (phypGetBackingDevice, phypDiskType): Mark unused, for now. --- src/phyp/phyp_driver.c | 2122 ++++++++++++++++++++-------------------- src/phyp/phyp_driver.h | 75 +- 2 files changed, 1075 insertions(+), 1122 deletions(-) diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index dfa31c76ef..0912f905c6 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -66,181 +66,881 @@ virReportErrorHelper(NULL, VIR_FROM_PHYP, code, __FILE__, __FUNCTION__, \ __LINE__, __VA_ARGS__) -static unsigned const int HMC = 0; -static unsigned const int IVM = 127; - /* * URI: phyp://user@[hmc|ivm]/managed_system * */ -static virDrvOpenStatus -phypOpen(virConnectPtr conn, - virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED) +static unsigned const int HMC = 0; +static unsigned const int IVM = 127; + +static int +waitsocket(int socket_fd, LIBSSH2_SESSION * session) { - LIBSSH2_SESSION *session = NULL; - ConnectionData *connection_data = NULL; - char *string = NULL; - size_t len = 0; - int internal_socket; - uuid_tablePtr uuid_table = NULL; - phyp_driverPtr phyp_driver = NULL; - char *char_ptr; - char *managed_system = NULL; + struct timeval timeout; + int rc; + fd_set fd; + fd_set *writefd = NULL; + fd_set *readfd = NULL; + int dir; - if (!conn || !conn->uri) - return VIR_DRV_OPEN_DECLINED; + timeout.tv_sec = 0; + timeout.tv_usec = 1000; - if (conn->uri->scheme == NULL || STRNEQ(conn->uri->scheme, "phyp")) - return VIR_DRV_OPEN_DECLINED; + FD_ZERO(&fd); - if (conn->uri->server == NULL) { - PHYP_ERROR(VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing server name in phyp:// URI")); - return VIR_DRV_OPEN_ERROR; + FD_SET(socket_fd, &fd); + + /* now make sure we wait in the correct direction */ + dir = libssh2_session_block_directions(session); + + if (dir & LIBSSH2_SESSION_BLOCK_INBOUND) + readfd = &fd; + + if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) + writefd = &fd; + + rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout); + + return rc; +} + +/* this function is the layer that manipulates the ssh channel itself + * and executes the commands on the remote machine */ +static char * +phypExec(LIBSSH2_SESSION * session, char *cmd, int *exit_status, + virConnectPtr conn) +{ + LIBSSH2_CHANNEL *channel; + ConnectionData *connection_data = conn->networkPrivateData; + virBuffer tex_ret = VIR_BUFFER_INITIALIZER; + char buffer[0x4000] = { 0 }; + int exitcode; + int bytecount = 0; + int sock = connection_data->sock; + int rc = 0; + + /* Exec non-blocking on the remove host */ + while ((channel = libssh2_channel_open_session(session)) == NULL && + libssh2_session_last_error(session, NULL, NULL, 0) == + LIBSSH2_ERROR_EAGAIN) { + waitsocket(sock, session); } - if (VIR_ALLOC(phyp_driver) < 0) { - virReportOOMError(); - goto failure; + if (channel == NULL) { + goto err; } - if (VIR_ALLOC(uuid_table) < 0) { - virReportOOMError(); - goto failure; + while ((rc = libssh2_channel_exec(channel, cmd)) == + LIBSSH2_ERROR_EAGAIN) { + waitsocket(sock, session); } - if (VIR_ALLOC(connection_data) < 0) { - virReportOOMError(); - goto failure; + if (rc != 0) { + goto err; } - if (conn->uri->path) { - len = strlen(conn->uri->path) + 1; - - if (VIR_ALLOC_N(string, len) < 0) { - virReportOOMError(); - goto failure; + for (;;) { + /* loop until we block */ + do { + rc = libssh2_channel_read(channel, buffer, sizeof(buffer)); + if (rc > 0) { + bytecount += rc; + virBufferVSprintf(&tex_ret, "%s", buffer); + } } + while (rc > 0); - /* need to shift one byte in order to remove the first "/" of URI component */ - if (conn->uri->path[0] == '/') - managed_system = strdup(conn->uri->path + 1); - else - managed_system = strdup(conn->uri->path); - - if (!managed_system) { - virReportOOMError(); - goto failure; - } - - /* here we are handling only the first component of the path, - * so skipping the second: - * */ - char_ptr = strchr(managed_system, '/'); - - if (char_ptr) - *char_ptr = '\0'; - - if (escape_specialcharacters(conn->uri->path, string, len) == -1) { - PHYP_ERROR(VIR_ERR_INTERNAL_ERROR, - "%s", - _("Error parsing 'path'. Invalid characters.")); - goto failure; + /* this is due to blocking that would occur otherwise so we loop on + * this condition */ + if (rc == LIBSSH2_ERROR_EAGAIN) { + waitsocket(sock, session); + } else { + break; } } - if ((session = openSSHSession(conn, auth, &internal_socket)) == NULL) { - PHYP_ERROR(VIR_ERR_INTERNAL_ERROR, - "%s", _("Error while opening SSH session.")); - goto failure; + exitcode = 127; + + while ((rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN) { + waitsocket(sock, session); } - connection_data->session = session; + if (rc == 0) { + exitcode = libssh2_channel_get_exit_status(channel); + } - uuid_table->nlpars = 0; - uuid_table->lpars = NULL; + (*exit_status) = exitcode; + libssh2_channel_free(channel); + channel = NULL; + goto exit; - if (conn->uri->path) - phyp_driver->managed_system = managed_system; + err: + (*exit_status) = SSH_CMD_ERR; + virBufferFreeAndReset(&tex_ret); + return NULL; - phyp_driver->uuid_table = uuid_table; - if ((phyp_driver->caps = phypCapsInit()) == NULL) { + exit: + if (virBufferError(&tex_ret)) { + virBufferFreeAndReset(&tex_ret); virReportOOMError(); - goto failure; + return NULL; } - - conn->privateData = phyp_driver; - conn->networkPrivateData = connection_data; - - if ((phyp_driver->system_type = phypGetSystemType(conn)) == -1) - goto failure; - - if (phypUUIDTable_Init(conn) == -1) - goto failure; - - if (phyp_driver->system_type == HMC) { - if ((phyp_driver->vios_id = phypGetVIOSPartitionID(conn)) == -1) - goto failure; - } - - return VIR_DRV_OPEN_SUCCESS; - - failure: - if (phyp_driver != NULL) { - virCapabilitiesFree(phyp_driver->caps); - VIR_FREE(phyp_driver->managed_system); - VIR_FREE(phyp_driver); - } - - phypUUIDTable_Free(uuid_table); - - if (session != NULL) { - libssh2_session_disconnect(session, "Disconnecting..."); - libssh2_session_free(session); - } - - VIR_FREE(connection_data); - VIR_FREE(string); - - return VIR_DRV_OPEN_ERROR; + return virBufferContentAndReset(&tex_ret); } static int -phypClose(virConnectPtr conn) +phypGetSystemType(virConnectPtr conn) +{ + ConnectionData *connection_data = conn->networkPrivateData; + LIBSSH2_SESSION *session = connection_data->session; + char *cmd = NULL; + char *ret = NULL; + int exit_status = 0; + + if (virAsprintf(&cmd, "lshmc -V") < 0) { + virReportOOMError(); + exit_status = -1; + } + ret = phypExec(session, cmd, &exit_status, conn); + + VIR_FREE(cmd); + VIR_FREE(ret); + return exit_status; +} + +static int +phypGetVIOSPartitionID(virConnectPtr conn) { ConnectionData *connection_data = conn->networkPrivateData; phyp_driverPtr phyp_driver = conn->privateData; LIBSSH2_SESSION *session = connection_data->session; + int system_type = phyp_driver->system_type; + char *cmd = NULL; + char *ret = NULL; + int exit_status = 0; + int id = -1; + char *char_ptr; + char *managed_system = phyp_driver->managed_system; + virBuffer buf = VIR_BUFFER_INITIALIZER; - libssh2_session_disconnect(session, "Disconnecting..."); - libssh2_session_free(session); + virBufferAddLit(&buf, "lssyscfg"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferAddLit(&buf, " -r lpar -F lpar_id,lpar_env|grep " + "vioserver|sed -s 's/,.*$//'"); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + if (virStrToLong_i(ret, &char_ptr, 10, &id) == -1) + goto err; + + VIR_FREE(cmd); + VIR_FREE(ret); + return id; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +static virCapsPtr +phypCapsInit(void) +{ + struct utsname utsname; + virCapsPtr caps; + virCapsGuestPtr guest; + + uname(&utsname); + + if ((caps = virCapabilitiesNew(utsname.machine, 0, 0)) == NULL) + goto no_memory; + + /* Some machines have problematic NUMA toplogy causing + * unexpected failures. We don't want to break the QEMU + * driver in this scenario, so log errors & carry on + */ + if (nodeCapsInitNUMA(caps) < 0) { + virCapabilitiesFreeNUMAInfo(caps); + VIR_WARN0 + ("Failed to query host NUMA topology, disabling NUMA capabilities"); + } + + /* XXX shouldn't 'borrow' KVM's prefix */ + virCapabilitiesSetMacPrefix(caps, (unsigned char[]) { + 0x52, 0x54, 0x00}); + + if ((guest = virCapabilitiesAddGuest(caps, + "linux", + utsname.machine, + sizeof(int) == 4 ? 32 : 8, + NULL, NULL, 0, NULL)) == NULL) + goto no_memory; + + if (virCapabilitiesAddGuestDomain(guest, + "phyp", NULL, NULL, 0, NULL) == NULL) + goto no_memory; + + return caps; + + no_memory: + virCapabilitiesFree(caps); + return NULL; +} + +/* This is a generic function that won't be used directly by + * libvirt api. The function returns the number of domains + * in different states: Running, Not Activated and all: + * + * type: 0 - Running + * 1 - Not Activated + * * - All + * */ +static int +phypNumDomainsGeneric(virConnectPtr conn, unsigned int type) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + int system_type = phyp_driver->system_type; + int exit_status = 0; + int ndom = 0; + char *char_ptr; + char *cmd = NULL; + char *ret = NULL; + char *managed_system = phyp_driver->managed_system; + const char *state; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (type == 0) + state = "|grep Running"; + else if (type == 1) { + if (system_type == HMC) { + state = "|grep \"Not Activated\""; + } else { + state = "|grep \"Open Firmware\""; + } + } else + state = " "; + + virBufferAddLit(&buf, "lssyscfg -r lpar"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferVSprintf(&buf, " -F lpar_id,state %s |grep -c '^[0-9]*'", + state); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + if (virStrToLong_i(ret, &char_ptr, 10, &ndom) == -1) + goto err; + + VIR_FREE(cmd); + VIR_FREE(ret); + return ndom; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +/* This is a generic function that won't be used directly by + * libvirt api. The function returns the ids of domains + * in different states: Running, and all: + * + * type: 0 - Running + * 1 - all + * */ +static int +phypListDomainsGeneric(virConnectPtr conn, int *ids, int nids, + unsigned int type) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + int system_type = phyp_driver->system_type; + char *managed_system = phyp_driver->managed_system; + int exit_status = 0; + int got = 0; + char *char_ptr; + unsigned int i = 0, j = 0; + char id_c[10]; + char *cmd = NULL; + char *ret = NULL; + const char *state; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (type == 0) + state = "|grep Running"; + else + state = " "; + + memset(id_c, 0, 10); + + virBufferAddLit(&buf, "lssyscfg -r lpar"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferVSprintf(&buf, " -F lpar_id,state %s | sed -e 's/,.*$//'", + state); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + /* I need to parse the textual return in order to get the ret */ + if (exit_status < 0 || ret == NULL) + goto err; + else { + while (got < nids) { + if (ret[i] == '\0') + break; + else if (ret[i] == '\n') { + if (virStrToLong_i(id_c, &char_ptr, 10, &ids[got]) == -1) { + VIR_ERROR(_("Cannot parse number from '%s'"), id_c); + goto err; + } + memset(id_c, 0, 10); + j = 0; + got++; + } else { + id_c[j] = ret[i]; + j++; + } + i++; + } + } + + VIR_FREE(cmd); + VIR_FREE(ret); + return got; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +static int +phypUUIDTable_WriteFile(virConnectPtr conn) +{ + phyp_driverPtr phyp_driver = conn->privateData; + uuid_tablePtr uuid_table = phyp_driver->uuid_table; + unsigned int i = 0; + int fd = -1; + char local_file[] = "./uuid_table"; + + if ((fd = creat(local_file, 0755)) == -1) + goto err; + + for (i = 0; i < uuid_table->nlpars; i++) { + if (safewrite(fd, &uuid_table->lpars[i]->id, + sizeof(uuid_table->lpars[i]->id)) != + sizeof(uuid_table->lpars[i]->id)) { + VIR_ERROR0(_("Unable to write information to local file.")); + goto err; + } + + if (safewrite(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN) != + VIR_UUID_BUFLEN) { + VIR_ERROR0(_("Unable to write information to local file.")); + goto err; + } + } + + close(fd); + return 0; + + err: + close(fd); + return -1; +} + +static int +phypUUIDTable_Push(virConnectPtr conn) +{ + ConnectionData *connection_data = conn->networkPrivateData; + LIBSSH2_SESSION *session = connection_data->session; + LIBSSH2_CHANNEL *channel = NULL; + virBuffer username = VIR_BUFFER_INITIALIZER; + struct stat local_fileinfo; + char buffer[1024]; + int rc = 0; + FILE *fd; + size_t nread, sent; + char *ptr; + char local_file[] = "./uuid_table"; + char *remote_file = NULL; + + if (conn->uri->user != NULL) { + virBufferVSprintf(&username, "%s", conn->uri->user); + + if (virBufferError(&username)) { + virBufferFreeAndReset(&username); + virReportOOMError(); + goto err; + } + } + + if (virAsprintf + (&remote_file, "/home/%s/libvirt_uuid_table", + virBufferContentAndReset(&username)) + < 0) { + virReportOOMError(); + goto err; + } + + if (stat(local_file, &local_fileinfo) == -1) { + VIR_WARN0("Unable to stat local file."); + goto err; + } + + if (!(fd = fopen(local_file, "rb"))) { + VIR_WARN0("Unable to open local file."); + goto err; + } + + do { + channel = + libssh2_scp_send(session, remote_file, + 0x1FF & local_fileinfo.st_mode, + (unsigned long) local_fileinfo.st_size); + + if ((!channel) && (libssh2_session_last_errno(session) != + LIBSSH2_ERROR_EAGAIN)) + goto err; + } while (!channel); + + do { + nread = fread(buffer, 1, sizeof(buffer), fd); + if (nread <= 0) { + if (feof(fd)) { + /* end of file */ + break; + } else { + VIR_ERROR(_("Failed to read from %s"), local_file); + goto err; + } + } + ptr = buffer; + sent = 0; + + do { + /* write the same data over and over, until error or completion */ + rc = libssh2_channel_write(channel, ptr, nread); + if (LIBSSH2_ERROR_EAGAIN == rc) { /* must loop around */ + continue; + } else if (rc > 0) { + /* rc indicates how many bytes were written this time */ + sent += rc; + } + ptr += sent; + nread -= sent; + } while (rc > 0 && sent < nread); + } while (1); + + if (channel) { + libssh2_channel_send_eof(channel); + libssh2_channel_wait_eof(channel); + libssh2_channel_wait_closed(channel); + libssh2_channel_free(channel); + channel = NULL; + } + virBufferFreeAndReset(&username); + return 0; + + err: + if (channel) { + libssh2_channel_send_eof(channel); + libssh2_channel_wait_eof(channel); + libssh2_channel_wait_closed(channel); + libssh2_channel_free(channel); + channel = NULL; + } + return -1; +} + +static int +phypUUIDTable_RemLpar(virConnectPtr conn, int id) +{ + phyp_driverPtr phyp_driver = conn->privateData; + uuid_tablePtr uuid_table = phyp_driver->uuid_table; + unsigned int i = 0; + + for (i = 0; i <= uuid_table->nlpars; i++) { + if (uuid_table->lpars[i]->id == id) { + uuid_table->lpars[i]->id = -1; + memset(uuid_table->lpars[i]->uuid, 0, VIR_UUID_BUFLEN); + } + } + + if (phypUUIDTable_WriteFile(conn) == -1) + goto err; + + if (phypUUIDTable_Push(conn) == -1) + goto err; + + return 0; + + err: + return -1; +} + +static int +phypUUIDTable_AddLpar(virConnectPtr conn, unsigned char *uuid, int id) +{ + phyp_driverPtr phyp_driver = conn->privateData; + uuid_tablePtr uuid_table = phyp_driver->uuid_table; + + uuid_table->nlpars++; + unsigned int i = uuid_table->nlpars; + i--; + + if (VIR_REALLOC_N(uuid_table->lpars, uuid_table->nlpars) < 0) { + virReportOOMError(); + goto err; + } + + if (VIR_ALLOC(uuid_table->lpars[i]) < 0) { + virReportOOMError(); + goto err; + } + + uuid_table->lpars[i]->id = id; + memmove(uuid_table->lpars[i]->uuid, uuid, VIR_UUID_BUFLEN); + + if (phypUUIDTable_WriteFile(conn) == -1) + goto err; + + if (phypUUIDTable_Push(conn) == -1) + goto err; + + return 0; + + err: + return -1; +} + +static int +phypUUIDTable_ReadFile(virConnectPtr conn) +{ + phyp_driverPtr phyp_driver = conn->privateData; + uuid_tablePtr uuid_table = phyp_driver->uuid_table; + unsigned int i = 0; + int fd = -1; + char local_file[] = "./uuid_table"; + int rc = 0; + int id; + + if ((fd = open(local_file, O_RDONLY)) == -1) { + VIR_WARN0("Unable to write information to local file."); + goto err; + } + + /* Creating a new data base and writing to local file */ + if (VIR_ALLOC_N(uuid_table->lpars, uuid_table->nlpars) >= 0) { + for (i = 0; i < uuid_table->nlpars; i++) { + + rc = read(fd, &id, sizeof(int)); + if (rc == sizeof(int)) { + if (VIR_ALLOC(uuid_table->lpars[i]) < 0) { + virReportOOMError(); + goto err; + } + uuid_table->lpars[i]->id = id; + } else { + VIR_WARN0 + ("Unable to read from information to local file."); + goto err; + } + + rc = read(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN); + if (rc != VIR_UUID_BUFLEN) { + VIR_WARN0("Unable to read information to local file."); + goto err; + } + } + } else + virReportOOMError(); + + close(fd); + return 0; + + err: + close(fd); + return -1; +} + +static int +phypUUIDTable_Pull(virConnectPtr conn) +{ + ConnectionData *connection_data = conn->networkPrivateData; + LIBSSH2_SESSION *session = connection_data->session; + LIBSSH2_CHANNEL *channel = NULL; + virBuffer username = VIR_BUFFER_INITIALIZER; + struct stat fileinfo; + char buffer[1024]; + int rc = 0; + int fd; + int got = 0; + int amount = 0; + int total = 0; + int sock = 0; + char local_file[] = "./uuid_table"; + char *remote_file = NULL; + + if (conn->uri->user != NULL) { + virBufferVSprintf(&username, "%s", conn->uri->user); + + if (virBufferError(&username)) { + virBufferFreeAndReset(&username); + virReportOOMError(); + goto err; + } + } + + if (virAsprintf + (&remote_file, "/home/%s/libvirt_uuid_table", + virBufferContentAndReset(&username)) + < 0) { + virReportOOMError(); + goto err; + } + + /* Trying to stat the remote file. */ + do { + channel = libssh2_scp_recv(session, remote_file, &fileinfo); + + if (!channel) { + if (libssh2_session_last_errno(session) != + LIBSSH2_ERROR_EAGAIN) { + goto err;; + } else { + waitsocket(sock, session); + } + } + } while (!channel); + + /* Creating a new data base based on remote file */ + if ((fd = creat(local_file, 0755)) == -1) + goto err; + + /* Request a file via SCP */ + while (got < fileinfo.st_size) { + do { + amount = sizeof(buffer); + + if ((fileinfo.st_size - got) < amount) { + amount = fileinfo.st_size - got; + } + + rc = libssh2_channel_read(channel, buffer, amount); + if (rc > 0) { + if (safewrite(fd, buffer, rc) != rc) + VIR_WARN0 + ("Unable to write information to local file."); + + got += rc; + total += rc; + } + } while (rc > 0); + + if ((rc == LIBSSH2_ERROR_EAGAIN) + && (got < fileinfo.st_size)) { + /* this is due to blocking that would occur otherwise + * so we loop on this condition */ + + waitsocket(sock, session); /* now we wait */ + continue; + } + break; + } + close(fd); + goto exit; + + exit: + if (channel) { + libssh2_channel_send_eof(channel); + libssh2_channel_wait_eof(channel); + libssh2_channel_wait_closed(channel); + libssh2_channel_free(channel); + channel = NULL; + } + virBufferFreeAndReset(&username); + return 0; + + err: + if (channel) { + libssh2_channel_send_eof(channel); + libssh2_channel_wait_eof(channel); + libssh2_channel_wait_closed(channel); + libssh2_channel_free(channel); + channel = NULL; + } + return -1; +} + +static int +phypUUIDTable_Init(virConnectPtr conn) +{ + uuid_tablePtr uuid_table; + phyp_driverPtr phyp_driver; + int nids_numdomains = 0; + int nids_listdomains = 0; + int *ids = NULL; + unsigned int i = 0; + + if ((nids_numdomains = phypNumDomainsGeneric(conn, 2)) < 0) + goto err; + + if (VIR_ALLOC_N(ids, nids_numdomains) < 0) { + virReportOOMError(); + goto err; + } + + if ((nids_listdomains = + phypListDomainsGeneric(conn, ids, nids_numdomains, 1)) < 0) + goto err; + + /* exit early if there are no domains */ + if (nids_numdomains == 0 && nids_listdomains == 0) + goto exit; + else if (nids_numdomains != nids_listdomains) { + VIR_ERROR0(_("Unable to determine number of domains.")); + goto err; + } + + phyp_driver = conn->privateData; + uuid_table = phyp_driver->uuid_table; + uuid_table->nlpars = nids_listdomains; + + /* try to get the table from server */ + if (phypUUIDTable_Pull(conn) == -1) { + /* file not found in the server, creating a new one */ + if (VIR_ALLOC_N(uuid_table->lpars, uuid_table->nlpars) >= 0) { + for (i = 0; i < uuid_table->nlpars; i++) { + if (VIR_ALLOC(uuid_table->lpars[i]) < 0) { + virReportOOMError(); + goto err; + } + uuid_table->lpars[i]->id = ids[i]; + + if (virUUIDGenerate(uuid_table->lpars[i]->uuid) < 0) + VIR_WARN("Unable to generate UUID for domain %d", + ids[i]); + } + } else { + virReportOOMError(); + goto err; + } + + if (phypUUIDTable_WriteFile(conn) == -1) + goto err; + + if (phypUUIDTable_Push(conn) == -1) + goto err; + } else { + if (phypUUIDTable_ReadFile(conn) == -1) + goto err; + goto exit; + } + + exit: + VIR_FREE(ids); + return 0; + + err: + VIR_FREE(ids); + return -1; +} + +static void +phypUUIDTable_Free(uuid_tablePtr uuid_table) +{ + int i; + + if (uuid_table == NULL) + return; + + for (i = 0; i < uuid_table->nlpars; i++) + VIR_FREE(uuid_table->lpars[i]); + + VIR_FREE(uuid_table->lpars); + VIR_FREE(uuid_table); +} + +static int +escape_specialcharacters(char *src, char *dst, size_t dstlen) +{ + size_t len = strlen(src); + char temp_buffer[len]; + unsigned int i = 0, j = 0; + if (len == 0) + return -1; + + for (i = 0; i < len; i++) { + switch (src[i]) { + case '&': + case ';': + case '`': + case '@': + case '"': + case '|': + case '*': + case '?': + case '~': + case '<': + case '>': + case '^': + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + case '$': + case '%': + case '#': + case '\\': + case '\n': + case '\r': + case '\t': + continue; + default: + temp_buffer[j] = src[i]; + j++; + } + } + temp_buffer[j] = '\0'; + + if (virStrcpy(dst, temp_buffer, dstlen) == NULL) + return -1; - virCapabilitiesFree(phyp_driver->caps); - phypUUIDTable_Free(phyp_driver->uuid_table); - VIR_FREE(phyp_driver->managed_system); - VIR_FREE(phyp_driver); - VIR_FREE(connection_data); return 0; } - -static int -phypIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED) -{ - /* Phyp uses an SSH tunnel, so is always encrypted */ - return 1; -} - - -static int -phypIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED) -{ - /* Phyp uses an SSH tunnel, so is always secure */ - return 1; -} - - -LIBSSH2_SESSION * +static LIBSSH2_SESSION * openSSHSession(virConnectPtr conn, virConnectAuthPtr auth, int *internal_socket) { @@ -414,108 +1114,170 @@ openSSHSession(virConnectPtr conn, virConnectAuthPtr auth, return session; } -/* this functions is the layer that manipulates the ssh channel itself - * and executes the commands on the remote machine */ -static char * -phypExec(LIBSSH2_SESSION * session, char *cmd, int *exit_status, - virConnectPtr conn) +static virDrvOpenStatus +phypOpen(virConnectPtr conn, + virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED) { - LIBSSH2_CHANNEL *channel; - ConnectionData *connection_data = conn->networkPrivateData; - virBuffer tex_ret = VIR_BUFFER_INITIALIZER; - char buffer[0x4000] = { 0 }; - int exitcode; - int bytecount = 0; - int sock = connection_data->sock; - int rc = 0; + LIBSSH2_SESSION *session = NULL; + ConnectionData *connection_data = NULL; + char *string = NULL; + size_t len = 0; + int internal_socket; + uuid_tablePtr uuid_table = NULL; + phyp_driverPtr phyp_driver = NULL; + char *char_ptr; + char *managed_system = NULL; - /* Exec non-blocking on the remove host */ - while ((channel = libssh2_channel_open_session(session)) == NULL && - libssh2_session_last_error(session, NULL, NULL, 0) == - LIBSSH2_ERROR_EAGAIN) { - waitsocket(sock, session); + if (!conn || !conn->uri) + return VIR_DRV_OPEN_DECLINED; + + if (conn->uri->scheme == NULL || STRNEQ(conn->uri->scheme, "phyp")) + return VIR_DRV_OPEN_DECLINED; + + if (conn->uri->server == NULL) { + PHYP_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing server name in phyp:// URI")); + return VIR_DRV_OPEN_ERROR; } - if (channel == NULL) { - goto err; - } - - while ((rc = libssh2_channel_exec(channel, cmd)) == - LIBSSH2_ERROR_EAGAIN) { - waitsocket(sock, session); - } - - if (rc != 0) { - goto err; - } - - for (;;) { - /* loop until we block */ - do { - rc = libssh2_channel_read(channel, buffer, sizeof(buffer)); - if (rc > 0) { - bytecount += rc; - virBufferVSprintf(&tex_ret, "%s", buffer); - } - } - while (rc > 0); - - /* this is due to blocking that would occur otherwise so we loop on - * this condition */ - if (rc == LIBSSH2_ERROR_EAGAIN) { - waitsocket(sock, session); - } else { - break; - } - } - - exitcode = 127; - - while ((rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN) { - waitsocket(sock, session); - } - - if (rc == 0) { - exitcode = libssh2_channel_get_exit_status(channel); - } - - (*exit_status) = exitcode; - libssh2_channel_free(channel); - channel = NULL; - goto exit; - - err: - (*exit_status) = SSH_CMD_ERR; - virBufferFreeAndReset(&tex_ret); - return NULL; - - exit: - if (virBufferError(&tex_ret)) { - virBufferFreeAndReset(&tex_ret); + if (VIR_ALLOC(phyp_driver) < 0) { virReportOOMError(); - return NULL; + goto failure; } - return virBufferContentAndReset(&tex_ret); + + if (VIR_ALLOC(uuid_table) < 0) { + virReportOOMError(); + goto failure; + } + + if (VIR_ALLOC(connection_data) < 0) { + virReportOOMError(); + goto failure; + } + + if (conn->uri->path) { + len = strlen(conn->uri->path) + 1; + + if (VIR_ALLOC_N(string, len) < 0) { + virReportOOMError(); + goto failure; + } + + /* need to shift one byte in order to remove the first "/" of URI component */ + if (conn->uri->path[0] == '/') + managed_system = strdup(conn->uri->path + 1); + else + managed_system = strdup(conn->uri->path); + + if (!managed_system) { + virReportOOMError(); + goto failure; + } + + /* here we are handling only the first component of the path, + * so skipping the second: + * */ + char_ptr = strchr(managed_system, '/'); + + if (char_ptr) + *char_ptr = '\0'; + + if (escape_specialcharacters(conn->uri->path, string, len) == -1) { + PHYP_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Error parsing 'path'. Invalid characters.")); + goto failure; + } + } + + if ((session = openSSHSession(conn, auth, &internal_socket)) == NULL) { + PHYP_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("Error while opening SSH session.")); + goto failure; + } + + connection_data->session = session; + + uuid_table->nlpars = 0; + uuid_table->lpars = NULL; + + if (conn->uri->path) + phyp_driver->managed_system = managed_system; + + phyp_driver->uuid_table = uuid_table; + if ((phyp_driver->caps = phypCapsInit()) == NULL) { + virReportOOMError(); + goto failure; + } + + conn->privateData = phyp_driver; + conn->networkPrivateData = connection_data; + + if ((phyp_driver->system_type = phypGetSystemType(conn)) == -1) + goto failure; + + if (phypUUIDTable_Init(conn) == -1) + goto failure; + + if (phyp_driver->system_type == HMC) { + if ((phyp_driver->vios_id = phypGetVIOSPartitionID(conn)) == -1) + goto failure; + } + + return VIR_DRV_OPEN_SUCCESS; + + failure: + if (phyp_driver != NULL) { + virCapabilitiesFree(phyp_driver->caps); + VIR_FREE(phyp_driver->managed_system); + VIR_FREE(phyp_driver); + } + + phypUUIDTable_Free(uuid_table); + + if (session != NULL) { + libssh2_session_disconnect(session, "Disconnecting..."); + libssh2_session_free(session); + } + + VIR_FREE(connection_data); + VIR_FREE(string); + + return VIR_DRV_OPEN_ERROR; } -int -phypGetSystemType(virConnectPtr conn) +static int +phypClose(virConnectPtr conn) { ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; LIBSSH2_SESSION *session = connection_data->session; - char *cmd = NULL; - char *ret = NULL; - int exit_status = 0; - if (virAsprintf(&cmd, "lshmc -V") < 0) { - virReportOOMError(); - exit_status = -1; - } - ret = phypExec(session, cmd, &exit_status, conn); + libssh2_session_disconnect(session, "Disconnecting..."); + libssh2_session_free(session); - VIR_FREE(cmd); - VIR_FREE(ret); - return exit_status; + virCapabilitiesFree(phyp_driver->caps); + phypUUIDTable_Free(phyp_driver->uuid_table); + VIR_FREE(phyp_driver->managed_system); + VIR_FREE(phyp_driver); + VIR_FREE(connection_data); + return 0; +} + + +static int +phypIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + /* Phyp uses an SSH tunnel, so is always encrypted */ + return 1; +} + + +static int +phypIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + /* Phyp uses an SSH tunnel, so is always secure */ + return 1; } @@ -611,7 +1373,7 @@ phypGetLparNAME(LIBSSH2_SESSION * session, const char *managed_system, * return: 0 - record found * -1 - not found * */ -int +static int phypGetLparUUID(unsigned char *uuid, int lpar_id, virConnectPtr conn) { phyp_driverPtr phyp_driver = conn->privateData; @@ -634,7 +1396,7 @@ phypGetLparUUID(unsigned char *uuid, int lpar_id, virConnectPtr conn) * 0 - maxmem * 1 - memory * */ -unsigned long +static unsigned long phypGetLparMem(virConnectPtr conn, const char *managed_system, int lpar_id, int type) { @@ -689,22 +1451,7 @@ phypGetLparMem(virConnectPtr conn, const char *managed_system, int lpar_id, } -unsigned long -phypGetLparCPU(virConnectPtr conn, const char *managed_system, int lpar_id) -{ - return phypGetLparCPUGeneric(conn, managed_system, lpar_id, 0); -} - -static int -phypGetLparCPUMAX(virDomainPtr dom) -{ - phyp_driverPtr phyp_driver = dom->conn->privateData; - char *managed_system = phyp_driver->managed_system; - - return phypGetLparCPUGeneric(dom->conn, managed_system, dom->id, 1); -} - -unsigned long +static unsigned long phypGetLparCPUGeneric(virConnectPtr conn, const char *managed_system, int lpar_id, int type) { @@ -755,7 +1502,22 @@ phypGetLparCPUGeneric(virConnectPtr conn, const char *managed_system, return 0; } -int +static unsigned long +phypGetLparCPU(virConnectPtr conn, const char *managed_system, int lpar_id) +{ + return phypGetLparCPUGeneric(conn, managed_system, lpar_id, 0); +} + +static int +phypGetLparCPUMAX(virDomainPtr dom) +{ + phyp_driverPtr phyp_driver = dom->conn->privateData; + char *managed_system = phyp_driver->managed_system; + + return phypGetLparCPUGeneric(dom->conn, managed_system, dom->id, 1); +} + +static int phypGetRemoteSlot(virConnectPtr conn, const char *managed_system, const char *lpar_name) { @@ -805,7 +1567,10 @@ phypGetRemoteSlot(virConnectPtr conn, const char *managed_system, return -1; } -char * +/* XXX - is this needed? */ +static char *phypGetBackingDevice(virConnectPtr, const char *, char *) + ATTRIBUTE_UNUSED; +static char * phypGetBackingDevice(virConnectPtr conn, const char *managed_system, char *lpar_name) { @@ -885,7 +1650,7 @@ phypGetBackingDevice(virConnectPtr conn, const char *managed_system, } -int +static int phypGetLparState(virConnectPtr conn, unsigned int lpar_id) { ConnectionData *connection_data = conn->networkPrivateData; @@ -934,52 +1699,9 @@ phypGetLparState(virConnectPtr conn, unsigned int lpar_id) return state; } -int -phypGetVIOSPartitionID(virConnectPtr conn) -{ - ConnectionData *connection_data = conn->networkPrivateData; - phyp_driverPtr phyp_driver = conn->privateData; - LIBSSH2_SESSION *session = connection_data->session; - int system_type = phyp_driver->system_type; - char *cmd = NULL; - char *ret = NULL; - int exit_status = 0; - int id = -1; - char *char_ptr; - char *managed_system = phyp_driver->managed_system; - virBuffer buf = VIR_BUFFER_INITIALIZER; - - virBufferAddLit(&buf, "lssyscfg"); - if (system_type == HMC) - virBufferVSprintf(&buf, " -m %s", managed_system); - virBufferAddLit(&buf, " -r lpar -F lpar_id,lpar_env|grep " - "vioserver|sed -s 's/,.*$//'"); - if (virBufferError(&buf)) { - virBufferFreeAndReset(&buf); - virReportOOMError(); - return -1; - } - cmd = virBufferContentAndReset(&buf); - - ret = phypExec(session, cmd, &exit_status, conn); - - if (exit_status < 0 || ret == NULL) - goto err; - - if (virStrToLong_i(ret, &char_ptr, 10, &id) == -1) - goto err; - - VIR_FREE(cmd); - VIR_FREE(ret); - return id; - - err: - VIR_FREE(cmd); - VIR_FREE(ret); - return -1; -} - -int +/* XXX - is this needed? */ +static int phypDiskType(virConnectPtr, char *) ATTRIBUTE_UNUSED; +static int phypDiskType(virConnectPtr conn, char *backing_device) { phyp_driverPtr phyp_driver = conn->privateData; @@ -1029,71 +1751,6 @@ phypDiskType(virConnectPtr conn, char *backing_device) return disk_type; } -/* This is a generic function that won't be used directly by - * libvirt api. The function returns the number of domains - * in different states: Running, Not Activated and all: - * - * type: 0 - Running - * 1 - Not Activated - * * - All - * */ -static int -phypNumDomainsGeneric(virConnectPtr conn, unsigned int type) -{ - ConnectionData *connection_data = conn->networkPrivateData; - phyp_driverPtr phyp_driver = conn->privateData; - LIBSSH2_SESSION *session = connection_data->session; - int system_type = phyp_driver->system_type; - int exit_status = 0; - int ndom = 0; - char *char_ptr; - char *cmd = NULL; - char *ret = NULL; - char *managed_system = phyp_driver->managed_system; - const char *state; - virBuffer buf = VIR_BUFFER_INITIALIZER; - - if (type == 0) - state = "|grep Running"; - else if (type == 1) { - if (system_type == HMC) { - state = "|grep \"Not Activated\""; - } else { - state = "|grep \"Open Firmware\""; - } - } else - state = " "; - - virBufferAddLit(&buf, "lssyscfg -r lpar"); - if (system_type == HMC) - virBufferVSprintf(&buf, " -m %s", managed_system); - virBufferVSprintf(&buf, " -F lpar_id,state %s |grep -c '^[0-9]*'", - state); - if (virBufferError(&buf)) { - virBufferFreeAndReset(&buf); - virReportOOMError(); - return -1; - } - cmd = virBufferContentAndReset(&buf); - - ret = phypExec(session, cmd, &exit_status, conn); - - if (exit_status < 0 || ret == NULL) - goto err; - - if (virStrToLong_i(ret, &char_ptr, 10, &ndom) == -1) - goto err; - - VIR_FREE(cmd); - VIR_FREE(ret); - return ndom; - - err: - VIR_FREE(cmd); - VIR_FREE(ret); - return -1; -} - static int phypNumDefinedDomains(virConnectPtr conn) { @@ -1106,86 +1763,6 @@ phypNumDomains(virConnectPtr conn) return phypNumDomainsGeneric(conn, 0); } -/* This is a generic function that won't be used directly by - * libvirt api. The function returns the ids of domains - * in different states: Running, and all: - * - * type: 0 - Running - * 1 - all - * */ -static int -phypListDomainsGeneric(virConnectPtr conn, int *ids, int nids, - unsigned int type) -{ - ConnectionData *connection_data = conn->networkPrivateData; - phyp_driverPtr phyp_driver = conn->privateData; - LIBSSH2_SESSION *session = connection_data->session; - int system_type = phyp_driver->system_type; - char *managed_system = phyp_driver->managed_system; - int exit_status = 0; - int got = 0; - char *char_ptr; - unsigned int i = 0, j = 0; - char id_c[10]; - char *cmd = NULL; - char *ret = NULL; - const char *state; - virBuffer buf = VIR_BUFFER_INITIALIZER; - - if (type == 0) - state = "|grep Running"; - else - state = " "; - - memset(id_c, 0, 10); - - virBufferAddLit(&buf, "lssyscfg -r lpar"); - if (system_type == HMC) - virBufferVSprintf(&buf, " -m %s", managed_system); - virBufferVSprintf(&buf, " -F lpar_id,state %s | sed -e 's/,.*$//'", - state); - if (virBufferError(&buf)) { - virBufferFreeAndReset(&buf); - virReportOOMError(); - return -1; - } - cmd = virBufferContentAndReset(&buf); - - ret = phypExec(session, cmd, &exit_status, conn); - - /* I need to parse the textual return in order to get the ret */ - if (exit_status < 0 || ret == NULL) - goto err; - else { - while (got < nids) { - if (ret[i] == '\0') - break; - else if (ret[i] == '\n') { - if (virStrToLong_i(id_c, &char_ptr, 10, &ids[got]) == -1) { - VIR_ERROR(_("Cannot parse number from '%s'"), id_c); - goto err; - } - memset(id_c, 0, 10); - j = 0; - got++; - } else { - id_c[j] = ret[i]; - j++; - } - i++; - } - } - - VIR_FREE(cmd); - VIR_FREE(ret); - return got; - - err: - VIR_FREE(cmd); - VIR_FREE(ret); - return -1; -} - static int phypListDomains(virConnectPtr conn, int *ids, int nids) { @@ -1513,6 +2090,55 @@ phypDomainDestroy(virDomainPtr dom) } +static int +phypBuildLpar(virConnectPtr conn, virDomainDefPtr def) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + int system_type = phyp_driver->system_type; + char *managed_system = phyp_driver->managed_system; + char *cmd = NULL; + char *ret = NULL; + int exit_status = 0; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + virBufferAddLit(&buf, "mksyscfg"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferVSprintf(&buf, " -r lpar -p %s -i min_mem=%d,desired_mem=%d," + "max_mem=%d,desired_procs=%d,virtual_scsi_adapters=%s", + def->name, (int) def->memory, (int) def->memory, + (int) def->maxmem, (int) def->vcpus, def->disks[0]->src); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0) { + VIR_ERROR(_("Unable to create LPAR. Reason: '%s'"), ret); + goto err; + } + + if (phypUUIDTable_AddLpar(conn, def->uuid, def->id) == -1) { + VIR_ERROR0(_("Unable to add LPAR to the table")); + goto err; + } + + VIR_FREE(cmd); + VIR_FREE(ret); + return 0; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + static virDomainPtr phypDomainCreateAndStart(virConnectPtr conn, const char *xml, unsigned int flags) @@ -1578,50 +2204,6 @@ phypConnectGetCapabilities(virConnectPtr conn) return xml; } -virCapsPtr -phypCapsInit(void) -{ - struct utsname utsname; - virCapsPtr caps; - virCapsGuestPtr guest; - - uname(&utsname); - - if ((caps = virCapabilitiesNew(utsname.machine, 0, 0)) == NULL) - goto no_memory; - - /* Some machines have problematic NUMA toplogy causing - * unexpected failures. We don't want to break the QEMU - * driver in this scenario, so log errors & carry on - */ - if (nodeCapsInitNUMA(caps) < 0) { - virCapabilitiesFreeNUMAInfo(caps); - VIR_WARN0 - ("Failed to query host NUMA topology, disabling NUMA capabilities"); - } - - /* XXX shouldn't 'borrow' KVM's prefix */ - virCapabilitiesSetMacPrefix(caps, (unsigned char[]) { - 0x52, 0x54, 0x00}); - - if ((guest = virCapabilitiesAddGuest(caps, - "linux", - utsname.machine, - sizeof(int) == 4 ? 32 : 8, - NULL, NULL, 0, NULL)) == NULL) - goto no_memory; - - if (virCapabilitiesAddGuestDomain(guest, - "phyp", NULL, NULL, 0, NULL) == NULL) - goto no_memory; - - return caps; - - no_memory: - virCapabilitiesFree(caps); - return NULL; -} - static int phypDomainSetCPU(virDomainPtr dom, unsigned int nvcpus) { @@ -1683,7 +2265,7 @@ phypDomainSetCPU(virDomainPtr dom, unsigned int nvcpus) } -virDriver phypDriver = { +static virDriver phypDriver = { VIR_DRV_PHYP, "PHYP", phypOpen, /* open */ phypClose, /* close */ NULL, /* supports_feature */ @@ -1782,584 +2364,6 @@ virDriver phypDriver = { NULL, /* domainSnapshotDelete */ }; -int -phypBuildLpar(virConnectPtr conn, virDomainDefPtr def) -{ - ConnectionData *connection_data = conn->networkPrivateData; - phyp_driverPtr phyp_driver = conn->privateData; - LIBSSH2_SESSION *session = connection_data->session; - int system_type = phyp_driver->system_type; - char *managed_system = phyp_driver->managed_system; - char *cmd = NULL; - char *ret = NULL; - int exit_status = 0; - virBuffer buf = VIR_BUFFER_INITIALIZER; - - virBufferAddLit(&buf, "mksyscfg"); - if (system_type == HMC) - virBufferVSprintf(&buf, " -m %s", managed_system); - virBufferVSprintf(&buf, " -r lpar -p %s -i min_mem=%d,desired_mem=%d," - "max_mem=%d,desired_procs=%d,virtual_scsi_adapters=%s", - def->name, (int) def->memory, (int) def->memory, - (int) def->maxmem, (int) def->vcpus, def->disks[0]->src); - if (virBufferError(&buf)) { - virBufferFreeAndReset(&buf); - virReportOOMError(); - return -1; - } - cmd = virBufferContentAndReset(&buf); - - ret = phypExec(session, cmd, &exit_status, conn); - - if (exit_status < 0) { - VIR_ERROR(_("Unable to create LPAR. Reason: '%s'"), ret); - goto err; - } - - if (phypUUIDTable_AddLpar(conn, def->uuid, def->id) == -1) { - VIR_ERROR0(_("Unable to add LPAR to the table")); - goto err; - } - - VIR_FREE(cmd); - VIR_FREE(ret); - return 0; - - err: - VIR_FREE(cmd); - VIR_FREE(ret); - return -1; -} - -int -phypUUIDTable_RemLpar(virConnectPtr conn, int id) -{ - phyp_driverPtr phyp_driver = conn->privateData; - uuid_tablePtr uuid_table = phyp_driver->uuid_table; - unsigned int i = 0; - - for (i = 0; i <= uuid_table->nlpars; i++) { - if (uuid_table->lpars[i]->id == id) { - uuid_table->lpars[i]->id = -1; - memset(uuid_table->lpars[i]->uuid, 0, VIR_UUID_BUFLEN); - } - } - - if (phypUUIDTable_WriteFile(conn) == -1) - goto err; - - if (phypUUIDTable_Push(conn) == -1) - goto err; - - return 0; - - err: - return -1; -} - -int -phypUUIDTable_AddLpar(virConnectPtr conn, unsigned char *uuid, int id) -{ - phyp_driverPtr phyp_driver = conn->privateData; - uuid_tablePtr uuid_table = phyp_driver->uuid_table; - - uuid_table->nlpars++; - unsigned int i = uuid_table->nlpars; - i--; - - if (VIR_REALLOC_N(uuid_table->lpars, uuid_table->nlpars) < 0) { - virReportOOMError(); - goto err; - } - - if (VIR_ALLOC(uuid_table->lpars[i]) < 0) { - virReportOOMError(); - goto err; - } - - uuid_table->lpars[i]->id = id; - memmove(uuid_table->lpars[i]->uuid, uuid, VIR_UUID_BUFLEN); - - if (phypUUIDTable_WriteFile(conn) == -1) - goto err; - - if (phypUUIDTable_Push(conn) == -1) - goto err; - - return 0; - - err: - return -1; -} - -int -phypUUIDTable_ReadFile(virConnectPtr conn) -{ - phyp_driverPtr phyp_driver = conn->privateData; - uuid_tablePtr uuid_table = phyp_driver->uuid_table; - unsigned int i = 0; - int fd = -1; - char local_file[] = "./uuid_table"; - int rc = 0; - int id; - - if ((fd = open(local_file, O_RDONLY)) == -1) { - VIR_WARN0("Unable to write information to local file."); - goto err; - } - - /* Creating a new data base and writing to local file */ - if (VIR_ALLOC_N(uuid_table->lpars, uuid_table->nlpars) >= 0) { - for (i = 0; i < uuid_table->nlpars; i++) { - - rc = read(fd, &id, sizeof(int)); - if (rc == sizeof(int)) { - if (VIR_ALLOC(uuid_table->lpars[i]) < 0) { - virReportOOMError(); - goto err; - } - uuid_table->lpars[i]->id = id; - } else { - VIR_WARN0 - ("Unable to read from information to local file."); - goto err; - } - - rc = read(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN); - if (rc != VIR_UUID_BUFLEN) { - VIR_WARN0("Unable to read information to local file."); - goto err; - } - } - } else - virReportOOMError(); - - close(fd); - return 0; - - err: - close(fd); - return -1; -} - -int -phypUUIDTable_WriteFile(virConnectPtr conn) -{ - phyp_driverPtr phyp_driver = conn->privateData; - uuid_tablePtr uuid_table = phyp_driver->uuid_table; - unsigned int i = 0; - int fd = -1; - char local_file[] = "./uuid_table"; - - if ((fd = creat(local_file, 0755)) == -1) - goto err; - - for (i = 0; i < uuid_table->nlpars; i++) { - if (safewrite(fd, &uuid_table->lpars[i]->id, - sizeof(uuid_table->lpars[i]->id)) != - sizeof(uuid_table->lpars[i]->id)) { - VIR_ERROR0(_("Unable to write information to local file.")); - goto err; - } - - if (safewrite(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN) != - VIR_UUID_BUFLEN) { - VIR_ERROR0(_("Unable to write information to local file.")); - goto err; - } - } - - close(fd); - return 0; - - err: - close(fd); - return -1; -} - -int -phypUUIDTable_Init(virConnectPtr conn) -{ - uuid_tablePtr uuid_table; - phyp_driverPtr phyp_driver; - int nids_numdomains = 0; - int nids_listdomains = 0; - int *ids = NULL; - unsigned int i = 0; - - if ((nids_numdomains = phypNumDomainsGeneric(conn, 2)) < 0) - goto err; - - if (VIR_ALLOC_N(ids, nids_numdomains) < 0) { - virReportOOMError(); - goto err; - } - - if ((nids_listdomains = - phypListDomainsGeneric(conn, ids, nids_numdomains, 1)) < 0) - goto err; - - /* exit early if there are no domains */ - if (nids_numdomains == 0 && nids_listdomains == 0) - goto exit; - else if (nids_numdomains != nids_listdomains) { - VIR_ERROR0(_("Unable to determine number of domains.")); - goto err; - } - - phyp_driver = conn->privateData; - uuid_table = phyp_driver->uuid_table; - uuid_table->nlpars = nids_listdomains; - - /* try to get the table from server */ - if (phypUUIDTable_Pull(conn) == -1) { - /* file not found in the server, creating a new one */ - if (VIR_ALLOC_N(uuid_table->lpars, uuid_table->nlpars) >= 0) { - for (i = 0; i < uuid_table->nlpars; i++) { - if (VIR_ALLOC(uuid_table->lpars[i]) < 0) { - virReportOOMError(); - goto err; - } - uuid_table->lpars[i]->id = ids[i]; - - if (virUUIDGenerate(uuid_table->lpars[i]->uuid) < 0) - VIR_WARN("Unable to generate UUID for domain %d", - ids[i]); - } - } else { - virReportOOMError(); - goto err; - } - - if (phypUUIDTable_WriteFile(conn) == -1) - goto err; - - if (phypUUIDTable_Push(conn) == -1) - goto err; - } else { - if (phypUUIDTable_ReadFile(conn) == -1) - goto err; - goto exit; - } - - exit: - VIR_FREE(ids); - return 0; - - err: - VIR_FREE(ids); - return -1; -} - -void -phypUUIDTable_Free(uuid_tablePtr uuid_table) -{ - int i; - - if (uuid_table == NULL) - return; - - for (i = 0; i < uuid_table->nlpars; i++) - VIR_FREE(uuid_table->lpars[i]); - - VIR_FREE(uuid_table->lpars); - VIR_FREE(uuid_table); -} - -int -phypUUIDTable_Push(virConnectPtr conn) -{ - ConnectionData *connection_data = conn->networkPrivateData; - LIBSSH2_SESSION *session = connection_data->session; - LIBSSH2_CHANNEL *channel = NULL; - virBuffer username = VIR_BUFFER_INITIALIZER; - struct stat local_fileinfo; - char buffer[1024]; - int rc = 0; - FILE *fd; - size_t nread, sent; - char *ptr; - char local_file[] = "./uuid_table"; - char *remote_file = NULL; - - if (conn->uri->user != NULL) { - virBufferVSprintf(&username, "%s", conn->uri->user); - - if (virBufferError(&username)) { - virBufferFreeAndReset(&username); - virReportOOMError(); - goto err; - } - } - - if (virAsprintf - (&remote_file, "/home/%s/libvirt_uuid_table", - virBufferContentAndReset(&username)) - < 0) { - virReportOOMError(); - goto err; - } - - if (stat(local_file, &local_fileinfo) == -1) { - VIR_WARN0("Unable to stat local file."); - goto err; - } - - if (!(fd = fopen(local_file, "rb"))) { - VIR_WARN0("Unable to open local file."); - goto err; - } - - do { - channel = - libssh2_scp_send(session, remote_file, - 0x1FF & local_fileinfo.st_mode, - (unsigned long) local_fileinfo.st_size); - - if ((!channel) && (libssh2_session_last_errno(session) != - LIBSSH2_ERROR_EAGAIN)) - goto err; - } while (!channel); - - do { - nread = fread(buffer, 1, sizeof(buffer), fd); - if (nread <= 0) { - if (feof(fd)) { - /* end of file */ - break; - } else { - VIR_ERROR(_("Failed to read from %s"), local_file); - goto err; - } - } - ptr = buffer; - sent = 0; - - do { - /* write the same data over and over, until error or completion */ - rc = libssh2_channel_write(channel, ptr, nread); - if (LIBSSH2_ERROR_EAGAIN == rc) { /* must loop around */ - continue; - } else if (rc > 0) { - /* rc indicates how many bytes were written this time */ - sent += rc; - } - ptr += sent; - nread -= sent; - } while (rc > 0 && sent < nread); - } while (1); - - if (channel) { - libssh2_channel_send_eof(channel); - libssh2_channel_wait_eof(channel); - libssh2_channel_wait_closed(channel); - libssh2_channel_free(channel); - channel = NULL; - } - virBufferFreeAndReset(&username); - return 0; - - err: - if (channel) { - libssh2_channel_send_eof(channel); - libssh2_channel_wait_eof(channel); - libssh2_channel_wait_closed(channel); - libssh2_channel_free(channel); - channel = NULL; - } - return -1; -} - -int -phypUUIDTable_Pull(virConnectPtr conn) -{ - ConnectionData *connection_data = conn->networkPrivateData; - LIBSSH2_SESSION *session = connection_data->session; - LIBSSH2_CHANNEL *channel = NULL; - virBuffer username = VIR_BUFFER_INITIALIZER; - struct stat fileinfo; - char buffer[1024]; - int rc = 0; - int fd; - int got = 0; - int amount = 0; - int total = 0; - int sock = 0; - char local_file[] = "./uuid_table"; - char *remote_file = NULL; - - if (conn->uri->user != NULL) { - virBufferVSprintf(&username, "%s", conn->uri->user); - - if (virBufferError(&username)) { - virBufferFreeAndReset(&username); - virReportOOMError(); - goto err; - } - } - - if (virAsprintf - (&remote_file, "/home/%s/libvirt_uuid_table", - virBufferContentAndReset(&username)) - < 0) { - virReportOOMError(); - goto err; - } - - /* Trying to stat the remote file. */ - do { - channel = libssh2_scp_recv(session, remote_file, &fileinfo); - - if (!channel) { - if (libssh2_session_last_errno(session) != - LIBSSH2_ERROR_EAGAIN) { - goto err;; - } else { - waitsocket(sock, session); - } - } - } while (!channel); - - /* Creating a new data base based on remote file */ - if ((fd = creat(local_file, 0755)) == -1) - goto err; - - /* Request a file via SCP */ - while (got < fileinfo.st_size) { - do { - amount = sizeof(buffer); - - if ((fileinfo.st_size - got) < amount) { - amount = fileinfo.st_size - got; - } - - rc = libssh2_channel_read(channel, buffer, amount); - if (rc > 0) { - if (safewrite(fd, buffer, rc) != rc) - VIR_WARN0 - ("Unable to write information to local file."); - - got += rc; - total += rc; - } - } while (rc > 0); - - if ((rc == LIBSSH2_ERROR_EAGAIN) - && (got < fileinfo.st_size)) { - /* this is due to blocking that would occur otherwise - * so we loop on this condition */ - - waitsocket(sock, session); /* now we wait */ - continue; - } - break; - } - close(fd); - goto exit; - - exit: - if (channel) { - libssh2_channel_send_eof(channel); - libssh2_channel_wait_eof(channel); - libssh2_channel_wait_closed(channel); - libssh2_channel_free(channel); - channel = NULL; - } - virBufferFreeAndReset(&username); - return 0; - - err: - if (channel) { - libssh2_channel_send_eof(channel); - libssh2_channel_wait_eof(channel); - libssh2_channel_wait_closed(channel); - libssh2_channel_free(channel); - channel = NULL; - } - return -1; -} - -int -escape_specialcharacters(char *src, char *dst, size_t dstlen) -{ - size_t len = strlen(src); - char temp_buffer[len]; - unsigned int i = 0, j = 0; - if (len == 0) - return -1; - - for (i = 0; i < len; i++) { - switch (src[i]) { - case '&': - case ';': - case '`': - case '@': - case '"': - case '|': - case '*': - case '?': - case '~': - case '<': - case '>': - case '^': - case '(': - case ')': - case '[': - case ']': - case '{': - case '}': - case '$': - case '%': - case '#': - case '\\': - case '\n': - case '\r': - case '\t': - continue; - default: - temp_buffer[j] = src[i]; - j++; - } - } - temp_buffer[j] = '\0'; - - if (virStrcpy(dst, temp_buffer, dstlen) == NULL) - return -1; - - return 0; -} - -int -waitsocket(int socket_fd, LIBSSH2_SESSION * session) -{ - struct timeval timeout; - int rc; - fd_set fd; - fd_set *writefd = NULL; - fd_set *readfd = NULL; - int dir; - - timeout.tv_sec = 0; - timeout.tv_usec = 1000; - - FD_ZERO(&fd); - - FD_SET(socket_fd, &fd); - - /* now make sure we wait in the correct direction */ - dir = libssh2_session_block_directions(session); - - if (dir & LIBSSH2_SESSION_BLOCK_INBOUND) - readfd = &fd; - - if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) - writefd = &fd; - - rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout); - - return rc; -} - int phypRegister(void) { diff --git a/src/phyp/phyp_driver.h b/src/phyp/phyp_driver.h index 80ff0c321e..a22156c875 100644 --- a/src/phyp/phyp_driver.h +++ b/src/phyp/phyp_driver.h @@ -1,5 +1,5 @@ - /* + * Copyright (C) 2010 Red Hat, Inc. * Copyright IBM Corp. 2009 * * phyp_driver.c: ssh layer to access Power Hypervisors @@ -22,14 +22,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "conf/capabilities.h" -#include "conf/domain_conf.h" -#include -#include +#ifndef PHYP_DRIVER_H +# define PHYP_DRIVER_H -#define LPAR_EXEC_ERR -1 -#define SSH_CONN_ERR -2 /* error while trying to connect to remote host */ -#define SSH_CMD_ERR -3 /* error while trying to execute the remote cmd */ +# include "conf/capabilities.h" +# include "conf/domain_conf.h" +# include +# include + +# define LPAR_EXEC_ERR -1 +# define SSH_CONN_ERR -2 /* error while trying to connect to remote host */ +# define SSH_CMD_ERR -3 /* error while trying to execute the remote cmd */ typedef struct _ConnectionData ConnectionData; typedef ConnectionData *ConnectionDataPtr; @@ -75,60 +78,6 @@ struct _phyp_driver { char *managed_system; }; -int phypCheckSPFreeSapce(virConnectPtr conn, int required_size, char *sp); - -int phypGetSystemType(virConnectPtr conn); - -int phypGetVIOSPartitionID(virConnectPtr conn); - -virCapsPtr phypCapsInit(void); - -int phypBuildLpar(virConnectPtr conn, virDomainDefPtr def); - -int phypUUIDTable_WriteFile(virConnectPtr conn); - -int phypUUIDTable_ReadFile(virConnectPtr conn); - -int phypUUIDTable_AddLpar(virConnectPtr conn, unsigned char *uuid, int id); - -int phypUUIDTable_RemLpar(virConnectPtr conn, int id); - -int phypUUIDTable_Pull(virConnectPtr conn); - -int phypUUIDTable_Push(virConnectPtr conn); - -int phypUUIDTable_Init(virConnectPtr conn); - -void phypUUIDTable_Free(uuid_tablePtr uuid_table); - -int escape_specialcharacters(char *src, char *dst, size_t dstlen); - -int waitsocket(int socket_fd, LIBSSH2_SESSION * session); - -int phypGetLparUUID(unsigned char *uuid, int lpar_id, virConnectPtr conn); - int phypRegister(void); -int phypGetLparState(virConnectPtr conn, unsigned int lpar_id); - -unsigned long phypGetLparMem(virConnectPtr conn, - const char *managed_system, int lpar_id, - int type); - -unsigned long phypGetLparCPU(virConnectPtr conn, - const char *managed_system, int lpar_id); - -unsigned long phypGetLparCPUGeneric(virConnectPtr conn, - const char *managed_system, - int lpar_id, int type); - -int phypGetRemoteSlot(virConnectPtr conn, const char *managed_system, - const char *lpar_name); - -char *phypGetBackingDevice(virConnectPtr conn, const char *managed_system, - char *lpar_name); - -int phypDiskType(virConnectPtr conn, char *backing_device); - -LIBSSH2_SESSION *openSSHSession(virConnectPtr conn, virConnectAuthPtr auth, - int *internal_socket); +#endif /* PHYP_DRIVER_H */